Compare commits

..

No commits in common. "master" and "v3.1.2" have entirely different histories.

140 changed files with 5141 additions and 36152 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

8
.gitignore vendored
View File

@ -2,8 +2,6 @@
.AppleDouble
.LSOverride
*.xcodeproj
.build/*
Packages/*
# Icon must end with two \r
Icon
@ -46,9 +44,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>

10
.travis.yml Normal file
View File

@ -0,0 +1,10 @@
language: objective-c
xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder
xcode_scheme: SocketIO-iOS
osx_image: xcode7
script: xcodebuild -project Socket.IO-Client-Swift.xcodeproj -scheme SocketIO-iOS -sdk iphonesimulator build test CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
before_install:
install: cd Socket.IO-Test-Server/ && npm install && cd .. && node Socket.IO-Test-Server/main.js &
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 +0,0 @@
// 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"]),
]
)

165
README.md
View File

@ -1,95 +1,89 @@
[![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: "localhost:8080")
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
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:@"localhost:8080" opts:nil];
[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.
## Installation
Requires Swift 4/5 and Xcode 10.x
### 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"])
],
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")
]
)
```
Then import `import SocketIO`.
### Carthage
Carthage
-----------------
Add this line to your `Cartfile`:
```
github "socketio/socket.io-client-swift" ~> 16.1.1
github "socketio/socket.io-client-swift" ~> 3.1.2 # Or latest version
```
Run `carthage update --platform ios,macosx`.
Add the `Starscream` and `SocketIO` frameworks to your projects and follow the usual Carthage process.
Manually (iOS 7+)
-----------------
1. Copy the SocketIOClientSwift 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.
### 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', '~> 3.1.2' # Or latest version
```
Install pods:
@ -102,27 +96,62 @@ Import the module:
Swift:
```swift
import SocketIO
import Socket_IO_Client_Swift
```
Objective-C:
```Objective-C
@import SocketIO;
#import <Socket_IO_Client_Swift/Socket_IO_Client_Swift-Swift.h>
```
##API
Constructors
-----------
`init(socketURL: String, opts: NSDictionary? = nil)` - Constructs a new client for the given URL. opts can be omitted (will use default values) note: If your socket.io server is secure, you need to specify `https` in your socketURL.
# [Docs](https://nuclearace.github.io/Socket.IO-Client-Swift/index.html)
Options
-------
- `connectParams: [String: AnyObject]?` - Dictionary whose contents will be passed with the connection.
- `reconnects: Bool` Default is `true`
- `reconnectAttempts: Int` Default is `-1` (infinite tries)
- `reconnectWait: Int` Default is `10`
- `forcePolling: Bool` Default is `false`. `true` forces the client to use xhr-polling.
- `forceWebsockets: Bool` Default is `false`. `true` forces the client to use WebSockets.
- `nsp: String` Default is `"/"`. Connects to a namespace.
- `cookies: [NSHTTPCookie]?` An array of NSHTTPCookies. Passed during the handshake. Default is nil.
- `log: Bool` If `true` socket will log debug messages. Default is false.
- `logger: SocketLogger` If you wish to implement your own logger that conforms to SocketLogger you can pass it in here. Will use the default logging defined under the protocol otherwise.
- `sessionDelegate: NSURLSessionDelegate` Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs. Default is nil.
- `path: String` - If the server uses a custom path. ex: `"/swift"`. Default is `""`
- `extraHeaders: [String: String]?` - Adds custom headers to the initial request. Default is nil.
- `handleQueue: dispatch_queue_t` - The dispatch queue that handlers are run on. Default is the main queue.
- [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)
Methods
-------
1. `on(event: String, callback: NormalCallback)` - 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.
2. `once(event: String, callback: NormalCallback)` - Adds a handler that will only be executed once.
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. `close()` - Closes the socket. Once a socket is closed it should not be reopened.
11. `reconnect()` - Causes the client to reconnect to the server.
12. `joinNamespace()` - Causes the client to join nsp. Shouldn't need to be called unless you change nsp manually.
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
## Detailed Example
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,19 @@
Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift"
s.module_name = "SocketIO"
s.version = "16.1.1"
s.version = "3.1.2"
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 1.2.
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.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v3.1.2' }
s.source_files = "SocketIOClientSwift/**/*.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 = "0640"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
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>
@ -58,7 +58,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
BlueprintName = "SocketIO-Mac"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -80,7 +80,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
BlueprintName = "SocketIO-Mac"
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -98,7 +98,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
BuildableName = "SocketIO.framework"
BlueprintName = "SocketIO"
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 = "0640"
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 = "SocketIO.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 = "SocketIO.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 = "SocketIO.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 = "SocketIO.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,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

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<string>io.socket.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

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>io.socket.$(PRODUCT_NAME:rfc1034identifier)</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,36 @@
//
// SocketIO_MacTests.swift
// SocketIO-MacTests
//
// Created by Nacho Soto on 7/11/15.
//
//
import Cocoa
import XCTest
class SocketIO_MacTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock() {
// Put the code you want to measure the time of here.
}
}
}

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>io.socket.$(PRODUCT_NAME:rfc1034identifier)</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,114 @@
//
// AbstractSocketTest.swift
// AbstractSocketTest.socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 02.08.15.
//
//
import XCTest
class AbstractSocketTest: XCTestCase {
static let serverURL = "localhost:6979"
static let TEST_TIMEOUT = 8.0
static var socket:SocketIOClient!
var testKind:TestKind?
func openConnection() {
guard AbstractSocketTest.socket.status == SocketIOClientStatus.NotConnected else {return}
weak var expection = self.expectationWithDescription("connect")
XCTAssertTrue(AbstractSocketTest.socket.status == SocketIOClientStatus.NotConnected)
AbstractSocketTest.socket.on("connect") {data, ack in
XCTAssertEqual(AbstractSocketTest.socket.status, SocketIOClientStatus.Connected)
XCTAssertFalse(AbstractSocketTest.socket.secure)
if let expection = expection {
expection.fulfill()
}
}
AbstractSocketTest.socket.connect()
XCTAssertEqual(AbstractSocketTest.socket.status, SocketIOClientStatus.Connecting)
waitForExpectationsWithTimeout(AbstractSocketTest.TEST_TIMEOUT, handler: nil)
}
func generateTestName(rawTestName:String) ->String {
return rawTestName + testKind!.rawValue
}
func checkConnectionStatus() {
XCTAssertEqual(AbstractSocketTest.socket.status, SocketIOClientStatus.Connected)
XCTAssertFalse(AbstractSocketTest.socket.secure)
}
func socketMultipleEmit(testName:String, emitData:Array<AnyObject>, callback:NormalCallback){
let finalTestname = generateTestName(testName)
weak var expection = self.expectationWithDescription(finalTestname)
func didGetEmit(result:[AnyObject], ack:SocketAckEmitter?) {
callback(result, ack)
if let expection = expection {
expection.fulfill()
}
}
AbstractSocketTest.socket.emit(finalTestname, withItems: emitData)
AbstractSocketTest.socket.on(finalTestname + "Return", callback: didGetEmit)
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
}
func socketEmit(testName:String, emitData:AnyObject?, callback:NormalCallback){
let finalTestname = generateTestName(testName)
weak var expection = self.expectationWithDescription(finalTestname)
func didGetEmit(result:[AnyObject], ack:SocketAckEmitter?) {
callback(result, ack)
if let expection = expection {
expection.fulfill()
}
}
AbstractSocketTest.socket.on(finalTestname + "Return", callback: didGetEmit)
if let emitData = emitData {
AbstractSocketTest.socket.emit(finalTestname, emitData)
} else {
AbstractSocketTest.socket.emit(finalTestname)
}
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
}
func socketAcknwoledgeMultiple(testName:String, Data:Array<AnyObject>, callback:NormalCallback){
let finalTestname = generateTestName(testName)
weak var expection = self.expectationWithDescription(finalTestname)
func didGetResult(result: [AnyObject]) {
callback(result, SocketAckEmitter(socket: AbstractSocketTest.socket, ackNum: -1))
if let expection = expection {
expection.fulfill()
}
}
AbstractSocketTest.socket.emitWithAck(finalTestname, withItems: Data)(timeoutAfter: 5, callback: didGetResult)
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
}
func socketAcknwoledge(testName:String, Data:AnyObject?, callback:NormalCallback){
let finalTestname = generateTestName(testName)
weak var expection = self.expectationWithDescription(finalTestname)
func didGet(result:[AnyObject]) {
callback(result, SocketAckEmitter(socket: AbstractSocketTest.socket, ackNum: -1))
if let expection = expection {
expection.fulfill()
}
}
var ack:OnAckCallback!
if let Data = Data {
ack = AbstractSocketTest.socket.emitWithAck(finalTestname, Data)
} else {
ack = AbstractSocketTest.socket.emitWithAck(finalTestname)
}
ack(timeoutAfter: 20, callback: didGet)
waitForExpectationsWithTimeout(SocketEmitTest.TEST_TIMEOUT, handler: nil)
}
}

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>io.socket.$(PRODUCT_NAME:rfc1034identifier)</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,25 @@
//
// SocketAckManagerTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 04.09.15.
//
//
import XCTest
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,88 @@
//
// SocketAcknowledgementTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 27.07.15.
//
//
import XCTest
class SocketAcknowledgementTest: AbstractSocketTest {
override func setUp() {
super.setUp()
testKind = TestKind.Acknowledgement
if AbstractSocketTest.socket == nil {
AbstractSocketTest.socket = SocketIOClient(socketURL: "milkbartube.com:6979", opts: [
"reconnects": true, // default true
"reconnectAttempts": -1, // default -1
"reconnectWait": 5, // default 10
"forcePolling": false,
"forceWebsockets": false,// default false
"path": ""])
openConnection()
}else {
AbstractSocketTest.socket.leaveNamespace()
}
}
func testConnectionStatus() {
super.checkConnectionStatus()
}
func testBasic() {
SocketTestCases.testBasic(socketAcknwoledge)
}
func testNull() {
SocketTestCases.testNull(socketAcknwoledge)
}
func testBinary() {
SocketTestCases.testBinary(socketAcknwoledge)
}
func testArray() {
SocketTestCases.testArray(socketAcknwoledge)
}
func testString() {
SocketTestCases.testString(socketAcknwoledge)
}
func testBool() {
SocketTestCases.testBool(socketAcknwoledge)
}
func testInteger() {
SocketTestCases.testInteger(socketAcknwoledge)
}
func testDouble() {
SocketTestCases.testDouble(socketAcknwoledge)
}
func testJSON() {
SocketTestCases.testJSON(socketAcknwoledge)
}
func testJSONWithBuffer() {
SocketTestCases.testJSONWithBuffer(socketAcknwoledge)
}
func testUnicode() {
SocketTestCases.testUnicode(socketAcknwoledge)
}
func testMultipleItems() {
SocketTestCases.testMultipleItems(socketAcknwoledgeMultiple)
}
func testMultipleWithBuffer() {
SocketTestCases.testMultipleItemsWithBuffer(socketAcknwoledgeMultiple)
}
}

View File

@ -0,0 +1,93 @@
//
// ConvertedSocketTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 25.07.15.
//
//
import XCTest
import Foundation
class SocketEmitTest: AbstractSocketTest {
override func setUp() {
super.setUp()
testKind = TestKind.Emit
if AbstractSocketTest.socket == nil {
AbstractSocketTest.socket = SocketIOClient(socketURL: AbstractSocketTest.serverURL, opts: [
"reconnects": true, // default true
"reconnectAttempts": -1, // default -1
"reconnectWait": 5, // default 10
"forcePolling": false,
"forceWebsockets": false,// default false
"path": ""]
)
openConnection()
}else {
AbstractSocketTest.socket.leaveNamespace()
}
}
override func tearDown() {
super.tearDown()
}
func testConnectionStatus() {
super.checkConnectionStatus()
}
func testBasic() {
SocketTestCases.testBasic(socketEmit)
}
func testNull() {
SocketTestCases.testNull(socketEmit)
}
func testBinary() {
SocketTestCases.testBinary(socketEmit)
}
func testArray() {
SocketTestCases.testArray(socketEmit)
}
func testString() {
SocketTestCases.testString(socketEmit)
}
func testBool() {
SocketTestCases.testBool(socketEmit)
}
func testInteger() {
SocketTestCases.testInteger(socketEmit)
}
func testDouble() {
SocketTestCases.testDouble(socketEmit)
}
func testJSON() {
SocketTestCases.testJSON(socketEmit)
}
func testJSONWithBuffer() {
SocketTestCases.testJSONWithBuffer(socketEmit)
}
func testUnicode() {
SocketTestCases.testUnicode(socketEmit)
}
func testMultipleItems() {
SocketTestCases.testMultipleItems(socketMultipleEmit)
}
func testMultipleWithBuffer() {
SocketTestCases.testMultipleItemsWithBuffer(socketMultipleEmit)
}
}

View File

@ -0,0 +1,88 @@
//
// SocketNamespaceAcknowledgementTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 28.07.15.
//
//
import XCTest
class SocketNamespaceAcknowledgementTest: AbstractSocketTest {
override func setUp() {
super.setUp()
testKind = TestKind.Acknowledgement
if AbstractSocketTest.socket == nil {
AbstractSocketTest.socket = SocketIOClient(socketURL: AbstractSocketTest.serverURL, opts: [
"reconnects": true, // default true
"reconnectAttempts": -1, // default -1
"reconnectWait": 5, // default 10
"forcePolling": false,
"forceWebsockets": false,// default false
"path": "",
"nsp": "/swift"])
openConnection()
}else {
AbstractSocketTest.socket.joinNamespace("/swift")
}
}
func testConnectionStatus() {
super.checkConnectionStatus()
}
func testBasic() {
SocketTestCases.testBasic(socketAcknwoledge)
}
func testNull() {
SocketTestCases.testNull(socketAcknwoledge)
}
func testBinary() {
SocketTestCases.testBinary(socketAcknwoledge)
}
func testArray() {
SocketTestCases.testArray(socketAcknwoledge)
}
func testString() {
SocketTestCases.testString(socketAcknwoledge)
}
func testBool() {
SocketTestCases.testBool(socketAcknwoledge)
}
func testInteger() {
SocketTestCases.testInteger(socketAcknwoledge)
}
func testDouble() {
SocketTestCases.testDouble(socketAcknwoledge)
}
func testJSON() {
SocketTestCases.testJSON(socketAcknwoledge)
}
func testJSONWithBuffer() {
SocketTestCases.testJSONWithBuffer(socketAcknwoledge)
}
func testUnicode() {
SocketTestCases.testUnicode(socketAcknwoledge)
}
func testMultipleItems() {
SocketTestCases.testMultipleItems(socketAcknwoledgeMultiple)
}
func testMultipleWithBuffer() {
SocketTestCases.testMultipleItemsWithBuffer(socketAcknwoledgeMultiple)
}
}

View File

@ -0,0 +1,87 @@
//
// SocketNamespaceEmitTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 26.07.15.
//
//
import XCTest
class SocketNamespaceEmitTest: AbstractSocketTest {
override func setUp() {
super.setUp()
testKind = TestKind.Emit
if AbstractSocketTest.socket == nil {
AbstractSocketTest.socket = SocketIOClient(socketURL: AbstractSocketTest.serverURL, opts: [
"reconnects": true, // default true
"reconnectAttempts": -1, // default -1
"reconnectWait": 5, // default 10
"forcePolling": false,
"forceWebsockets": false,// default false
"path": "",
"nsp": "/swift"])
openConnection()
}else {
AbstractSocketTest.socket.joinNamespace("/swift")
}
}
func testConnectionStatus() {
super.checkConnectionStatus()
}
func testBasic() {
SocketTestCases.testBasic(socketEmit)
}
func testNull() {
SocketTestCases.testNull(socketEmit)
}
func testBinary() {
SocketTestCases.testBinary(socketEmit)
}
func testArray() {
SocketTestCases.testArray(socketEmit)
}
func testString() {
SocketTestCases.testString(socketEmit)
}
func testBool() {
SocketTestCases.testBool(socketEmit)
}
func testInteger() {
SocketTestCases.testInteger(socketEmit)
}
func testDouble() {
SocketTestCases.testDouble(socketEmit)
}
func testJSON() {
SocketTestCases.testJSON(socketEmit)
}
func testJSONWithBuffer() {
SocketTestCases.testJSONWithBuffer(socketEmit)
}
func testUnicode() {
SocketTestCases.testUnicode(socketEmit)
}
func testMultipleItems() {
SocketTestCases.testMultipleItems(socketMultipleEmit)
}
func testMultipleWithBuffer() {
SocketTestCases.testMultipleItemsWithBuffer(socketMultipleEmit)
}
}

View File

@ -0,0 +1,110 @@
//
// SocketParserTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 05.09.15.
//
//
import XCTest
class SocketParserTest: XCTestCase {
//Format key: message; namespace-data-binary-id
static let packetTypes: Dictionary<String, (String, [AnyObject], [NSData], Int)> = [
"0": ("/", [], [], -1), "1": ("/", [], [], -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)]
func testDisconnect() {
let message = "1"
validateParseResult(message)
}
func testConnect() {
let message = "0"
validateParseResult(message)
}
func testDisconnectNameSpace() {
let message = "1/swift"
validateParseResult(message)
}
func testConnecttNameSpace() {
let message = "0/swift"
validateParseResult(message)
}
func testNameSpaceArrayParse() {
let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]"
validateParseResult(message)
}
func testNameSpaceArrayAckParse() {
let message = "3/swift,0[[\"test3\",\"test4\"]]"
validateParseResult(message)
}
func testNameSpaceBinaryEventParse() {
let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
validateParseResult(message)
}
func testNameSpaceBinaryAckParse() {
let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
validateParseResult(message)
}
func testNamespaceErrorParse() {
let message = "4/swift,"
validateParseResult(message)
}
func testInvalidInput() {
let message = "8"
switch SocketParser.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(1), "6")
XCTAssertEqual(parser.currentCharacter, "1")
XCTAssertEqual(parser.readUntilStringOccurence("-"), "1")
XCTAssertEqual(parser.currentCharacter, "/")
}
func validateParseResult(message: String) {
let validValues = SocketParserTest.packetTypes[message]!
let packet = SocketParser.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(str:type)!)
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)
measureBlock({
for item in keys.enumerate() {
SocketParser.parseString(item.element)
}
})
}
}

View File

@ -0,0 +1,248 @@
//
// SocketTestCases.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 02.08.15.
//
//
import XCTest
import Foundation
class SocketTestCases: NSObject {
typealias SocketSendFunction = (testName:String, emitData:AnyObject?, callback:NormalCallback)->()
static func testBasic(abstractSocketSend:SocketSendFunction) {
let testName = "basicTest"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
}
abstractSocketSend(testName: testName, emitData: nil, callback: didGetResult)
}
static func testNull(abstractSocketSend:SocketSendFunction) {
let testName = "testNull"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let _ = result.first as? NSNull {
}else
{
XCTFail("Should have NSNull as result")
}
}
abstractSocketSend(testName: testName, emitData: NSNull(), callback: didGetResult)
}
static func testBinary(abstractSocketSend:SocketSendFunction) {
let testName = "testBinary"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let data = result.first as? NSData {
let string = NSString(data: data, encoding: NSUTF8StringEncoding)!
XCTAssertEqual(string, "gakgakgak2")
}else {
XCTFail("Should have NSData as result")
}
}
let data = NSString(string: "gakgakgak2").dataUsingEncoding(NSUTF8StringEncoding)!
abstractSocketSend(testName: testName, emitData: data, callback: didGetResult)
}
static func testArray(abstractSocketSend:SocketSendFunction) {
let testName = "testArray"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let array = result.first as? NSArray {
XCTAssertEqual(array.count, 2)
XCTAssertEqual((array.firstObject! as! String), "test3")
XCTAssertEqual((array.lastObject! as! String), "test4")
}else {
XCTFail("Should have NSArray as result")
}
}
abstractSocketSend(testName: testName, emitData: ["test1", "test2"], callback: didGetResult)
}
static func testString(abstractSocketSend:SocketSendFunction) {
let testName = "testString"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let string = result.first as? String {
XCTAssertEqual(string, "polo")
}else {
XCTFail("Should have String as result")
}
}
abstractSocketSend(testName: testName, emitData: "marco", callback: didGetResult)
}
static func testBool(abstractSocketSend:SocketSendFunction) {
let testName = "testBool"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let bool = result.first as? NSNumber {
XCTAssertTrue(bool.boolValue)
}else {
XCTFail("Should have Boolean as result")
}
}
abstractSocketSend(testName: testName, emitData: false, callback: didGetResult)
}
static func testInteger(abstractSocketSend:SocketSendFunction) {
let testName = "testInteger"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let integer = result.first as? Int {
XCTAssertEqual(integer, 20)
}else {
XCTFail("Should have Integer as result")
}
}
abstractSocketSend(testName: testName, emitData: 10, callback: didGetResult)
}
static func testDouble(abstractSocketSend:SocketSendFunction) {
let testName = "testDouble"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let double = result.first as? NSNumber {
XCTAssertEqual(double.floatValue, 1.2)
}else {
XCTFail("Should have Double as result")
}
}
abstractSocketSend(testName: testName, emitData: 1.1, callback: didGetResult)
}
static func testJSONWithBuffer(abstractSocketSend:SocketSendFunction) {
let testName = "testJSONWithBuffer"
let data = "0".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let json = result.first as? NSDictionary {
XCTAssertEqual((json.valueForKey("testString")! as! String), "test")
XCTAssertEqual((json.valueForKey("testNumber")! as! Int), 15)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2)
XCTAssertEqual(((json.valueForKey("testArray")! as! Array<AnyObject>).last! as! Int), 1)
let string = NSString(data: (json.valueForKey("testArray")! as! Array<AnyObject>).first! as! NSData, encoding: NSUTF8StringEncoding)!
XCTAssertEqual(string, "gakgakgak2")
}else {
XCTFail("Should have NSDictionary as result")
}
}
let json = ["name": "test", "testArray": ["hallo"], "nestedTest": ["test": "test"], "number": 15, "buf": data]
abstractSocketSend(testName: testName, emitData: json, callback: didGetResult)
}
static func testJSON(abstractSocketSend:SocketSendFunction) {
let testName = "testJSON"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let json = result.first as? NSDictionary {
XCTAssertEqual((json.valueForKey("testString")! as! String), "test")
XCTAssertEqual(json.valueForKey("testNumber")! as? Int, 15)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).count, 2)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).first! as? Int, 1)
XCTAssertEqual((json.valueForKey("testArray")! as! Array<AnyObject>).last! as? Int, 1)
}else {
XCTFail("Should have NSDictionary as result")
}
}
let json = ["name": "test", "testArray": ["hallo"], "nestedTest": ["test": "test"], "number": 15]
abstractSocketSend(testName: testName, emitData: json, callback: didGetResult)
}
static func testUnicode(abstractSocketSend:SocketSendFunction) {
let testName = "testUnicode"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
if let unicode = result.first as? String {
XCTAssertEqual(unicode, "🚄")
}else {
XCTFail("Should have String as result")
}
}
abstractSocketSend(testName: testName, emitData: "🚀", callback: didGetResult)
}
static func testMultipleItemsWithBuffer(abstractSocketMultipleSend:(testName:String, emitData:Array<AnyObject>, callback:NormalCallback)->()) {
let testName = "testMultipleItemsWithBuffer"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
XCTAssertEqual(result.count, 5)
if result.count != 5 {
XCTFail("Fatal Fail. Lost some Data")
return
}
if let array = result.first as? Array<AnyObject> {
XCTAssertEqual((array.last! as! Int), 2)
XCTAssertEqual((array.first! as! Int), 1)
}else {
XCTFail("Should have Array as result")
}
if let dict = result[1] as? NSDictionary {
XCTAssertEqual((dict.valueForKey("test") as! String), "bob")
}else {
XCTFail("Should have NSDictionary as result")
}
if let number = result[2] as? Int {
XCTAssertEqual(number, 25)
}else {
XCTFail("Should have Integer as result")
}
if let string = result[3] as? String {
XCTAssertEqual(string, "polo")
}else {
XCTFail("Should have Integer as result")
}
if let data = result[4] as? NSData {
let string = NSString(data: data, encoding: NSUTF8StringEncoding)!
XCTAssertEqual(string, "gakgakgak2")
}else {
XCTFail("Should have NSData as result")
}
}
let data = NSString(string: "gakgakgak2").dataUsingEncoding(NSUTF8StringEncoding)!
let emitArray = [["test1", "test2"], ["test": "test"], 15, "marco", data]
abstractSocketMultipleSend(testName: testName, emitData: emitArray, callback: didGetResult)
}
static func testMultipleItems(abstractSocketMultipleSend:(testName:String, emitData:Array<AnyObject>, callback:NormalCallback)->()) {
let testName = "testMultipleItems"
func didGetResult(result:[AnyObject], ack:SocketAckEmitter?) {
XCTAssertEqual(result.count, 5)
if result.count != 5 {
XCTFail("Fatal Fail. Lost some Data")
return
}
if let array = result.first as? Array<AnyObject> {
XCTAssertEqual((array.last! as! Int), 2)
XCTAssertEqual((array.first! as! Int), 1)
}else {
XCTFail("Should have Array as result")
}
if let dict = result[1] as? NSDictionary {
XCTAssertEqual((dict.valueForKey("test") as! String), "bob")
}else {
XCTFail("Should have NSDictionary as result")
}
if let number = result[2] as? Int {
XCTAssertEqual(number, 25)
}else {
XCTFail("Should have Integer as result")
}
if let string = result[3] as? String {
XCTAssertEqual(string, "polo")
}else {
XCTFail("Should have Integer as result")
}
if let bool = result[4] as? NSNumber {
XCTAssertFalse(bool.boolValue)
}else {
XCTFail("Should have NSNumber as result")
}
}
let emitArray = [["test1", "test2"], ["test": "test"], 15, "marco", false]
abstractSocketMultipleSend(testName: testName, emitData: emitArray, callback: didGetResult)
}
}

View File

@ -0,0 +1,13 @@
//
// TestKind.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 28.07.15.
//
//
import Foundation
enum TestKind: String {
case Emit, Acknowledgement
}

View File

@ -0,0 +1,43 @@
//
// 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...) {
socket.emitAck(ackNum, withItems: items)
}
public func with(items: [AnyObject]) {
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 let event: String
/// The data items for this event.
@objc
public let items: [Any]?
/// The description of this event.
@objc public final class SocketAnyEvent: NSObject {
public let event: String!
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,703 @@
//
// 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, WebSocketDelegate {
private typealias Probe = (msg: String, type: PacketType, data: [NSData]?)
private typealias ProbeWaitQueue = [Probe]
private let allowedCharacterSet = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
private let emitQueue = dispatch_queue_create("engineEmitQueue", DISPATCH_QUEUE_SERIAL)
private let handleQueue = dispatch_queue_create("engineHandleQueue", DISPATCH_QUEUE_SERIAL)
private let logType = "SocketEngine"
private let parseQueue = dispatch_queue_create("engineParseQueue", DISPATCH_QUEUE_SERIAL)
private let session: NSURLSession!
private let workQueue = NSOperationQueue()
private var closed = false
private var extraHeaders: [String: String]?
private var fastUpgrade = false
private var forcePolling = false
private var forceWebsockets = false
private var pingInterval: Double?
private var pingTimer: NSTimer?
private var pingTimeout = 0.0 {
didSet {
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
}
}
private var pongsMissed = 0
private var pongsMissedMax = 0
private var postWait = [String]()
private var probing = false
private var probeWait = ProbeWaitQueue()
private var waitingForPoll = false
private var waitingForPost = false
private var websocketConnected = false
private(set) var connected = false
private(set) var polling = true
private(set) var websocket = false
weak var client: SocketEngineClient?
var cookies: [NSHTTPCookie]?
var sid = ""
var socketPath = ""
var urlPolling = ""
var urlWebSocket = ""
var ws: WebSocket?
@objc public enum PacketType: Int {
case Open, Close, Ping, Pong, Message, Upgrade, Noop
init?(str: String) {
if let value = Int(str), raw = PacketType(rawValue: value) {
self = raw
} else {
return nil
}
}
}
public init(client: SocketEngineClient, sessionDelegate: NSURLSessionDelegate?) {
self.client = client
self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: sessionDelegate, delegateQueue: workQueue)
}
public convenience init(client: SocketEngineClient, opts: NSDictionary?) {
self.init(client: client, sessionDelegate: opts?["sessionDelegate"] as? NSURLSessionDelegate)
forceWebsockets = opts?["forceWebsockets"] as? Bool ?? false
forcePolling = opts?["forcePolling"] as? Bool ?? false
cookies = opts?["cookies"] as? [NSHTTPCookie]
socketPath = opts?["path"] as? String ?? ""
extraHeaders = opts?["extraHeaders"] as? [String: String]
}
deinit {
Logger.log("Engine is being deinit", type: logType)
}
private func checkIfMessageIsBase64Binary(var message: String) {
if message.hasPrefix("b4") {
// binary in base64 string
message.removeRange(Range<String.Index>(start: message.startIndex,
end: message.startIndex.advancedBy(2)))
if let data = NSData(base64EncodedString: message,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters) {
client?.parseBinaryData(data)
}
}
}
public func close(fast fast: Bool) {
Logger.log("Engine is being closed. Fast: %@", type: logType, args: fast)
pingTimer?.invalidate()
closed = true
ws?.disconnect()
if fast || polling {
write("", withType: PacketType.Close, withData: nil)
client?.engineDidClose("Disconnect")
}
stopPolling()
}
private func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
if websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
byteArray[0] = 4
let mutData = NSMutableData(bytes: &byteArray, length: 1)
mutData.appendData(data)
return .Left(mutData)
} else {
var str = "b4"
str += data.base64EncodedStringWithOptions(
NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
return .Right(str)
}
}
private func createURLs(params: [String: AnyObject]?) -> (String, String) {
if client == nil {
return ("", "")
}
let path = socketPath == "" ? "/socket.io" : socketPath
let url = "\(client!.socketURL)\(path)/?transport="
var urlPolling: String
var urlWebSocket: String
if client!.secure {
urlPolling = "https://" + url + "polling"
urlWebSocket = "wss://" + url + "websocket"
} else {
urlPolling = "http://" + url + "polling"
urlWebSocket = "ws://" + url + "websocket"
}
if params != nil {
for (key, value) in params! {
let keyEsc = key.stringByAddingPercentEncodingWithAllowedCharacters(
allowedCharacterSet)!
urlPolling += "&\(keyEsc)="
urlWebSocket += "&\(keyEsc)="
if value is String {
let valueEsc = (value as! String).stringByAddingPercentEncodingWithAllowedCharacters(
allowedCharacterSet)!
urlPolling += "\(valueEsc)"
urlWebSocket += "\(valueEsc)"
} else {
urlPolling += "\(value)"
urlWebSocket += "\(value)"
}
}
}
return (urlPolling, urlWebSocket)
}
private func createWebsocketAndConnect(connect: Bool) {
let wsUrl = urlWebSocket + (sid == "" ? "" : "&sid=\(sid)")
ws = WebSocket(url: NSURL(string: wsUrl)!,
cookies: cookies)
if extraHeaders != nil {
for (headerName, value) in extraHeaders! {
ws?.headers[headerName] = value
}
}
ws?.queue = handleQueue
ws?.delegate = self
if connect {
ws?.connect()
}
}
private func doFastUpgrade() {
if waitingForPoll {
Logger.error("Outstanding poll when switched to WebSockets," +
"we'll probably disconnect soon. You should report this.", type: logType)
}
sendWebSocketMessage("", withType: PacketType.Upgrade, datas: nil)
websocket = true
polling = false
fastUpgrade = false
probing = false
flushProbeWait()
}
private func doPoll() {
if websocket || waitingForPoll || !connected {
return
}
waitingForPoll = true
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)&b64=1")!)
if cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
req.allHTTPHeaderFields = headers
}
if extraHeaders != nil {
for (headerName, value) in extraHeaders! {
req.setValue(value, forHTTPHeaderField: headerName)
}
}
doRequest(req)
}
private func doRequest(req: NSMutableURLRequest) {
if !polling {
return
}
req.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
Logger.log("Doing polling request", type: logType)
session.dataTaskWithRequest(req) {[weak self] data, res, err in
if let this = self {
if err != nil || data == nil {
if this.polling {
this.handlePollingFailed(err?.localizedDescription ?? "Error")
} else {
Logger.error(err?.localizedDescription ?? "Error", type: this.logType)
}
return
}
Logger.log("Got polling response", type: this.logType)
if let str = NSString(data: data!, encoding: NSUTF8StringEncoding) as? String {
dispatch_async(this.parseQueue) {[weak this] in
this?.parsePollingMessage(str)
}
}
this.waitingForPoll = false
if this.fastUpgrade {
this.doFastUpgrade()
} else if !this.closed && this.polling {
this.doPoll()
}
}}.resume()
}
private func flushProbeWait() {
Logger.log("Flushing probe wait", type: logType)
dispatch_async(emitQueue) {[weak self] in
if let this = self {
for waiter in this.probeWait {
this.write(waiter.msg, withType: waiter.type, withData: waiter.data)
}
this.probeWait.removeAll(keepCapacity: false)
if this.postWait.count != 0 {
this.flushWaitingForPostToWebSocket()
}
}
}
}
private func flushWaitingForPost() {
if postWait.count == 0 || !connected {
return
} else if websocket {
flushWaitingForPostToWebSocket()
return
}
var postStr = ""
for packet in postWait {
let len = packet.characters.count
postStr += "\(len):\(packet)"
}
postWait.removeAll(keepCapacity: false)
let req = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&sid=\(sid)")!)
if let cookies = cookies {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
req.allHTTPHeaderFields = headers
}
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")
waitingForPost = true
Logger.log("POSTing: %@", type: logType, args: postStr)
session.dataTaskWithRequest(req) {[weak self] data, res, err in
if let this = self {
if err != nil && this.polling {
this.handlePollingFailed(err?.localizedDescription ?? "Error")
return
} else if err != nil {
NSLog(err?.localizedDescription ?? "Error")
return
}
this.waitingForPost = false
dispatch_async(this.emitQueue) {[weak this] in
if !(this?.fastUpgrade ?? true) {
this?.flushWaitingForPost()
this?.doPoll()
}
}
}}.resume()
}
// We had packets waiting for send when we upgraded
// Send them raw
private func flushWaitingForPostToWebSocket() {
guard let ws = self.ws else {return}
for msg in postWait {
ws.writeString(msg)
}
postWait.removeAll(keepCapacity: true)
}
private func handleClose() {
if let client = client where polling == true {
client.engineDidClose("Disconnect")
}
}
private func handleMessage(message: String) {
client?.parseSocketMessage(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.filter {$0 == "websocket"}.count != 0
} 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(true)
}
}
} catch {
Logger.error("Error parsing open packet", type: logType)
return
}
startPingTimer()
if !forceWebsockets {
doPoll()
}
}
private func handlePong(pongMessage: String) {
pongsMissed = 0
// We should upgrade
if pongMessage == "3probe" {
upgradeTransport()
}
}
// A poll failed, tell the client about it
private func handlePollingFailed(reason: String) {
connected = false
ws?.disconnect()
pingTimer?.invalidate()
waitingForPoll = false
waitingForPost = false
if !closed {
client?.didError(reason)
client?.engineDidClose(reason)
}
}
public func open(opts: [String: AnyObject]? = nil) {
if connected {
Logger.error("Tried to open while connected", type: logType)
client?.didError("Tried to open while connected")
return
}
Logger.log("Starting engine", type: logType)
Logger.log("Handshaking", type: logType)
closed = false
(urlPolling, urlWebSocket) = createURLs(opts)
if forceWebsockets {
polling = false
websocket = true
createWebsocketAndConnect(true)
return
}
let reqPolling = NSMutableURLRequest(URL: NSURL(string: urlPolling + "&b64=1")!)
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)
}
}
doRequest(reqPolling)
}
private 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
}
}
}
private func parseEngineData(data: NSData) {
Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
client?.parseBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
}
private func parseEngineMessage(var message: String, fromPolling: Bool) {
Logger.log("Got message: %@", type: logType, args: message)
if fromPolling {
fixDoubleUTF8(&message)
}
let type = PacketType(str: (message["^(\\d)"].groups()?[1]) ?? "") ?? {
self.checkIfMessageIsBase64Binary(message)
return .Noop
}()
switch type {
case PacketType.Message:
message.removeAtIndex(message.startIndex)
handleMessage(message)
case PacketType.Noop:
handleNOOP()
case PacketType.Pong:
handlePong(message)
case PacketType.Open:
message.removeAtIndex(message.startIndex)
handleOpen(message)
case PacketType.Close:
handleClose()
default:
Logger.log("Got unknown packet type", type: logType)
}
}
private func probeWebSocket() {
if websocketConnected {
sendWebSocketMessage("probe", withType: PacketType.Ping)
}
}
/// Send an engine message (4)
public func send(msg: String, withData datas: [NSData]?) {
if probing {
probeWait.append((msg, PacketType.Message, datas))
} else {
write(msg, withType: PacketType.Message, withData: datas)
}
}
@objc private func sendPing() {
//Server is not responding
if pongsMissed > pongsMissedMax {
pingTimer?.invalidate()
client?.engineDidClose("Ping timeout")
return
}
++pongsMissed
write("", withType: PacketType.Ping, withData: nil)
}
/// Send polling message.
/// Only call on emitQueue
private func sendPollMessage(var msg: String, withType type: PacketType,
datas:[NSData]? = nil) {
Logger.log("Sending poll: %@ as type: %@", type: logType, args: msg, type.rawValue)
doubleEncodeUTF8(&msg)
let strMsg = "\(type.rawValue)\(msg)"
postWait.append(strMsg)
for data in datas ?? [] {
if case let .Right(bin) = createBinaryDataForSend(data) {
postWait.append(bin)
}
}
if !waitingForPost {
flushWaitingForPost()
}
}
/// Send message on WebSockets
/// Only call on emitQueue
private func sendWebSocketMessage(str: String, withType type: PacketType,
datas:[NSData]? = nil) {
Logger.log("Sending ws: %@ as type: %@", type: logType, args: str, type.rawValue)
ws?.writeString("\(type.rawValue)\(str)")
for data in datas ?? [] {
if case let Either.Left(bin) = createBinaryDataForSend(data) {
ws?.writeData(bin)
}
}
}
// 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)
}
}
}
func stopPolling() {
session.finishTasksAndInvalidate()
}
private func upgradeTransport() {
if websocketConnected {
Logger.log("Upgrading transport to WebSockets", type: logType)
fastUpgrade = true
sendPollMessage("", withType: PacketType.Noop)
// After this point, we should not send anymore polling messages
}
}
/**
Write a message, independent of transport.
*/
public func write(msg: String, withType type: PacketType, withData data: [NSData]?) {
dispatch_async(emitQueue) {
if self.connected {
if self.websocket {
Logger.log("Writing ws: %@ has data: %@", type: self.logType, args: msg,
data == nil ? false : true)
self.sendWebSocketMessage(msg, withType: type, datas: data)
} else {
Logger.log("Writing poll: %@ has data: %@", type: self.logType, args: msg,
data == nil ? false : true)
self.sendPollMessage(msg, withType: type, datas: data)
}
}
}
}
// Delagate methods
public func websocketDidConnect(socket:WebSocket) {
websocketConnected = true
if !forceWebsockets {
probing = true
probeWebSocket()
} else {
connected = true
probing = false
polling = false
}
}
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
websocketConnected = false
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 {
client?.didError(reason)
}
client?.engineDidClose(reason)
} else {
flushProbeWait()
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
parseEngineMessage(text, fromPolling: false)
}
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
parseEngineData(data)
}
}

View File

@ -1,8 +1,8 @@
//
// SocketEnginePacketType.swift
// SocketEngineClient.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 10/7/15.
// 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
@ -25,26 +25,12 @@
import Foundation
/// Represents the type of engine.io packet types.
@objc public enum SocketEnginePacketType: Int {
/// Open message.
case open
@objc public protocol SocketEngineClient {
var socketURL: String {get}
var secure: Bool {get}
/// Close message.
case close
/// Ping message.
case ping
/// Pong message.
case pong
/// Regular message.
case message
/// Upgrade message.
case upgrade
/// NOOP.
case noop
func didError(reason: AnyObject)
func engineDidClose(reason: String)
func parseSocketMessage(msg: String)
func parseBinaryData(data: NSData)
}

View File

@ -24,27 +24,23 @@
import Foundation
/// A wrapper around a handler.
public struct SocketEventHandler {
// MARK: Properties
private func emitAckCallback(socket: SocketIOClient, num: Int?) -> SocketAckEmitter? {
return num != nil ? SocketAckEmitter(socket: socket, ackNum: num!) : nil
}
/// The event for this handler.
public let event: String
struct SocketEventHandler {
let event: String
let callback: NormalCallback
let id: NSUUID
/// A unique identifier for this handler.
public let id: UUID
init(event: String, id: NSUUID = NSUUID(), callback: NormalCallback) {
self.event = event
self.id = id
self.callback = callback
}
/// 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) {
callback(items, SocketAckEmitter(socket: socket, ackNum: ack))
func executeCallback(items: [AnyObject], withAck ack: Int? = nil, withAckType type: Int? = nil,
withSocket socket: SocketIOClient) {
self.callback(items, emitAckCallback(socket, num: ack))
}
}

View File

@ -0,0 +1,38 @@
//
// 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(inout name: String) {
let utf8 = name.dataUsingEncoding(NSISOLatin1StringEncoding)!
let latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding)!
name = latin1 as String
}
func doubleEncodeUTF8(inout str: String) {
let latin1 = str.dataUsingEncoding(NSUTF8StringEncoding)!
let utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding)!
str = utf8 as String
}

View File

@ -0,0 +1,509 @@
//
// 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 {
private let emitQueue = dispatch_queue_create("emitQueue", DISPATCH_QUEUE_SERIAL)
private let handleQueue: dispatch_queue_t!
public let socketURL: String
public private(set) var engine: SocketEngine?
public private(set) var secure = false
public private(set) var status = SocketIOClientStatus.NotConnected
public var nsp = "/"
public var opts: [String: AnyObject]?
public var reconnects = true
public var reconnectWait = 10
public var sid: String? {
return engine?.sid
}
private let logType = "SocketIOClient"
private var anyHandler: ((SocketAnyEvent) -> Void)?
private var currentReconnectAttempt = 0
private var handlers = ContiguousArray<SocketEventHandler>()
private var connectParams: [String: AnyObject]?
private var reconnectTimer: NSTimer?
private let reconnectAttempts: Int!
private var ackHandlers = SocketAckManager()
private var currentAck = -1
var waitingData = [SocketPacket]()
/**
Create a new SocketIOClient. opts can be omitted
*/
public init(var socketURL: String, opts: [String: AnyObject]? = nil) {
if socketURL["https://"].matches().count != 0 {
self.secure = true
}
socketURL = socketURL["http://"] ~= ""
socketURL = socketURL["https://"] ~= ""
self.socketURL = socketURL
self.opts = opts
if let connectParams = opts?["connectParams"] as? [String: AnyObject] {
self.connectParams = connectParams
}
if let logger = opts?["logger"] as? SocketLogger {
Logger = logger
}
if let log = opts?["log"] as? Bool {
Logger.log = log
}
if let nsp = opts?["nsp"] as? String {
self.nsp = nsp
}
if let reconnects = opts?["reconnects"] as? Bool {
self.reconnects = reconnects
}
if let reconnectAttempts = opts?["reconnectAttempts"] as? Int {
self.reconnectAttempts = reconnectAttempts
} else {
self.reconnectAttempts = -1
}
if let reconnectWait = opts?["reconnectWait"] as? Int {
self.reconnectWait = abs(reconnectWait)
}
if let handleQueue = opts?["handleQueue"] as? dispatch_queue_t {
self.handleQueue = handleQueue
} else {
self.handleQueue = dispatch_get_main_queue()
}
super.init()
}
deinit {
Logger.log("Client is being deinit", type: logType)
engine?.close(fast: true)
}
private func addEngine() -> SocketEngine {
Logger.log("Adding engine", type: logType)
let newEngine = SocketEngine(client: self, opts: opts)
engine = newEngine
return newEngine
}
private func clearReconnectTimer() {
reconnectTimer?.invalidate()
reconnectTimer = nil
}
/**
Closes the socket. Only reopen the same socket if you know what you're doing.
Will turn off automatic reconnects.
Pass true to fast if you're closing from a background task
*/
public func close() {
Logger.log("Closing socket", type: logType)
reconnects = false
didDisconnect("Closed")
}
/**
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 {
return
}
if status == .Closed {
Logger.log("Warning! This socket was previously closed. This might be dangerous!",
type: logType)
}
status = SocketIOClientStatus.Connecting
addEngine().open(connectParams)
guard timeoutAfter != 0 else {
return
}
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
if self.status != .Connected {
self.status = .Closed
self.engine?.close(fast: true)
handler?()
}
}
}
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
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, dispatch_get_main_queue()) {
this.ackHandlers.timeoutAck(ack)
}
}
}
}
}
func didConnect() {
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
}
Logger.log("Disconnected: %@", type: logType, args: reason)
status = .Closed
reconnects = false
// Make sure the engine is actually dead.
engine?.close(fast: true)
handleEvent("disconnect", data: [reason], isInternalMessage: true)
}
/// error
public func didError(reason: AnyObject) {
Logger.error("%@", type: logType, args: reason)
handleEvent("error", data: reason as? [AnyObject] ?? [reason],
isInternalMessage: true)
}
/**
Same as close
*/
public func disconnect() {
close()
}
/**
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 {
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 {
return
}
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false)
let str = packet.packetString
Logger.log("Emitting: %@", type: logType, args: str)
if packet.type == .BinaryEvent {
engine?.send(str, withData: packet.binary)
} else {
engine?.send(str, withData: nil)
}
}
// 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
Logger.log("Emitting Ack: %@", type: self.logType, args: str)
if packet.type == SocketPacket.PacketType.BinaryAck {
self.engine?.send(str, withData: packet.binary)
} else {
self.engine?.send(str, withData: nil)
}
}
}
}
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()
}
}
// Called when the socket gets an ack for something it sent
func handleAck(ack: Int, data: AnyObject?) {
Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "")
ackHandlers.executeAck(ack,
items: (data as? [AnyObject]) ?? (data != nil ? [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,
wantsAck ack: Int? = nil) {
guard status == .Connected || isInternalMessage else {
return
}
Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
if anyHandler != nil {
dispatch_async(handleQueue) {
self.anyHandler?(SocketAnyEvent(event: event, items: data))
}
}
for handler in handlers where handler.event == event {
if let ack = ack {
dispatch_async(handleQueue) {
handler.executeCallback(data, withAck: ack, withSocket: self)
}
} else {
dispatch_async(handleQueue) {
handler.executeCallback(data, withAck: ack, withSocket: self)
}
}
}
}
/**
Leaves nsp and goes back to /
*/
public func leaveNamespace() {
if nsp != "/" {
engine?.send("1\(nsp)", withData: nil)
nsp = "/"
}
}
/**
Joins nsp if it is not /
*/
public func joinNamespace() {
Logger.log("Joining namespace", type: logType)
if nsp != "/" {
engine?.send("0\(nsp)", withData: nil)
}
}
/**
Joins namespace /
*/
public func joinNamespace(namespace: String) {
self.nsp = namespace
joinNamespace()
}
/**
Removes handler(s)
*/
public func off(event: String) {
Logger.log("Removing handler for event: %@", type: logType, args: event)
handlers = ContiguousArray(handlers.filter { $0.event != event })
}
/**
Adds a handler for an event.
*/
public func on(event: String, callback: NormalCallback) {
Logger.log("Adding handler for event: %@", type: logType, args: event)
let handler = SocketEventHandler(event: event, callback: callback)
handlers.append(handler)
}
/**
Adds a single-use handler for an event.
*/
public func once(event: String, callback: NormalCallback) {
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.handlers = ContiguousArray(this.handlers.filter {$0.id != id})
callback(data, ack)
}
handlers.append(handler)
}
/**
Removes all handlers.
Can be used after disconnecting to break any potential remaining retain cycles.
*/
public func removeAllHandlers() {
handlers.removeAll(keepCapacity: false)
}
/**
Adds a handler that will be called on every event.
*/
public func onAny(handler: (SocketAnyEvent) -> Void) {
anyHandler = handler
}
/**
Same as connect
*/
public func open() {
connect()
}
public func parseSocketMessage(msg: String) {
dispatch_async(handleQueue) {
SocketParser.parseSocketMessage(msg, socket: self)
}
}
public func parseBinaryData(data: NSData) {
dispatch_async(handleQueue) {
SocketParser.parseBinaryData(data, socket: self)
}
}
/**
Tries to reconnect to the server.
*/
public func reconnect() {
engine?.stopPolling()
tryReconnect()
}
private func tryReconnect() {
if reconnectTimer == nil {
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
}
Logger.log("Trying to reconnect", type: logType)
handleEvent("reconnectAttempt", data: [reconnectAttempts - currentReconnectAttempt],
isInternalMessage: true)
currentReconnectAttempt++
connect()
}
}

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 {
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"
}
}
case NotConnected, Closed, Connecting, Connected, Reconnecting
}

View File

@ -0,0 +1,61 @@
//
// SocketLogger.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 4/11/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
var Logger: SocketLogger = DefaultSocketLogger()
public protocol SocketLogger {
/// Whether to log or not
var log: Bool {get set}
/// Normal log messages
func log(message: String, type: String, args: AnyObject...)
/// Error Messages
func error(message: String, type: String, args: AnyObject...)
}
public extension SocketLogger {
func log(message: String, type: String, args: AnyObject...) {
abstractLog("Log", message: message, type: type, args: args)
}
func error(message: String, type: String, args: AnyObject...) {
abstractLog("ERROR", message: message, type: type, args: args)
}
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)
}
}
struct DefaultSocketLogger: SocketLogger {
var log = false
}

View File

@ -0,0 +1,314 @@
//
// 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 var currentPlace = 0
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
init?(str: String) {
if let int = Int(str), raw = PacketType(rawValue: int) {
self = raw
} else {
return nil
}
}
}
var args: [AnyObject]? {
var arr = data
if data.count == 0 {
return nil
} else {
if type == PacketType.Event || type == PacketType.BinaryEvent {
arr.removeAtIndex(0)
return arr
} else {
return arr
}
}
}
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 data[0] as? String ?? 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 == currentPlace {
return true
}
binary.append(data)
currentPlace++
if placeholders == currentPlace {
currentPlace = 0
return true
} else {
return false
}
}
private func completeMessage(var message: String, ack: Bool) -> String {
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 = NSString(data: jsonSend, encoding: NSUTF8StringEncoding)
message += jsonString! as String + ","
} catch {
Logger.error("Error creating JSON object in SocketPacket.completeMessage", type: SocketPacket.logType)
}
} else if var str = arg as? String {
str = str["\n"] ~= "\\\\n"
str = str["\r"] ~= "\\\\r"
message += "\"\(str)\","
} else if arg is NSNull {
message += "null,"
} else {
message += "\(arg),"
}
}
if message != "" {
message.removeAtIndex(message.endIndex.predecessor())
}
return message + "]"
}
private func createAck() -> String {
let msg: String
if type == PacketType.Ack {
if nsp == "/" {
msg = "3\(id)["
} else {
msg = "3\(nsp),\(id)["
}
} else {
if nsp == "/" {
msg = "6\(binary.count)-\(id)["
} else {
msg = "6\(binary.count)-/\(nsp),\(id)["
}
}
return completeMessage(msg, ack: true)
}
private func createMessageForEvent() -> String {
let message: String
if type == PacketType.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 == PacketType.Event || type == PacketType.BinaryEvent {
str = createMessageForEvent()
} else {
str = createAck()
}
return str
}
mutating func fillInPlaceholders() {
for i in 0..<data.count {
if let str = data[i] as? String, num = str["~~(\\d)"].groups() {
data[i] = binary[Int(num[1])!]
} else if data[i] is NSDictionary || data[i] is NSArray {
data[i] = _fillInPlaceholders(data[i])
}
}
}
private mutating func _fillInPlaceholders(data: AnyObject) -> AnyObject {
if let str = data as? String {
if let num = str["~~(\\d)"].groups() {
return binary[Int(num[1])!]
} else {
return str
}
} else if let dict = data as? NSDictionary {
let newDict = NSMutableDictionary(dictionary: dict)
for (key, value) in dict {
newDict[key as! NSCopying] = _fillInPlaceholders(value)
}
return newDict
} else if let arr = data as? NSArray {
let newArr = NSMutableArray(array: arr)
for i in 0..<arr.count {
newArr[i] = _fillInPlaceholders(arr[i])
}
return newArr
} else {
return data
}
}
}
extension SocketPacket {
private static func findType(binCount: Int, ack: Bool) -> PacketType {
switch binCount {
case 0 where !ack:
return PacketType.Event
case 0 where ack:
return PacketType.Ack
case _ where !ack:
return PacketType.BinaryEvent
case _ where ack:
return PacketType.BinaryAck
default:
return PacketType.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 {
static func shred(data: AnyObject, inout binary: [NSData]) -> AnyObject {
if let bin = data as? NSData {
let placeholder = ["_placeholder" :true, "num": binary.count]
binary.append(bin)
return placeholder
} else if var arr = data as? [AnyObject] {
for i in 0..<arr.count {
arr[i] = shred(arr[i], binary: &binary)
}
return arr
} else if let dict = data as? NSDictionary {
let mutDict = NSMutableDictionary(dictionary: dict)
for (key, value) in dict {
mutDict[key as! NSCopying] = shred(value, binary: &binary)
}
return mutDict
} else {
return data
}
}
static func deconstructData(var data: [AnyObject]) -> ([AnyObject], [NSData]) {
var binary = [NSData]()
for i in 0..<data.count {
if data[i] is NSArray || data[i] is NSDictionary {
data[i] = shred(data[i], binary: &binary)
} else if let bin = data[i] as? NSData {
data[i] = ["_placeholder" :true, "num": binary.count]
binary.append(bin)
}
}
return (data, binary)
}
}

View File

@ -0,0 +1,168 @@
//
// SocketParser.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
class SocketParser {
private static func isCorrectNamespace(nsp: String, _ socket: SocketIOClient) -> Bool {
return nsp == socket.nsp
}
private static func handleConnect(p: SocketPacket, socket: SocketIOClient) {
if p.nsp == "/" && socket.nsp != "/" {
socket.joinNamespace()
} else if p.nsp != "/" && socket.nsp == "/" {
socket.didConnect()
} else {
socket.didConnect()
}
}
private static func handlePacket(pack: SocketPacket, withSocket socket: SocketIOClient) {
switch pack.type {
case .Event where isCorrectNamespace(pack.nsp, socket):
socket.handleEvent(pack.event, data: pack.args ?? [],
isInternalMessage: false, wantsAck: pack.id)
case .Ack where isCorrectNamespace(pack.nsp, socket):
socket.handleAck(pack.id, data: pack.data)
case .BinaryEvent where isCorrectNamespace(pack.nsp, socket):
socket.waitingData.append(pack)
case .BinaryAck where isCorrectNamespace(pack.nsp, socket):
socket.waitingData.append(pack)
case .Connect:
handleConnect(pack, socket: socket)
case .Disconnect:
socket.didDisconnect("Got Disconnect")
case .Error:
socket.didError("Error: \(pack.data)")
default:
Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
}
}
static func parseString(message: String) -> Either<String, SocketPacket> {
var parser = SocketStringReader(message: message)
guard let type = SocketPacket.PacketType(str: parser.read(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 = ""
while parser.hasNext {
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 .Left(let err):
return .Left(err)
case .Right(let data):
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
nsp: namespace ?? "/", placeholders: placeholders))
}
}
// Parses data for events
private static 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
static func parseSocketMessage(message: String, socket: SocketIOClient) {
guard !message.isEmpty else { return }
Logger.log("Parsing %@", type: "SocketParser", args: message)
switch parseString(message) {
case .Left(let err):
Logger.error("\(err): %@", type: "SocketParser", args: message)
case .Right(let pack):
Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
handlePacket(pack, withSocket: socket)
}
}
static func parseBinaryData(data: NSData, socket: SocketIOClient) {
guard !socket.waitingData.isEmpty else {
Logger.error("Got data when not remaking packet", type: "SocketParser")
return
}
// Should execute event?
guard socket.waitingData[socket.waitingData.count - 1].addData(data) else {
return
}
var packet = socket.waitingData.removeLast()
packet.fillInPlaceholders()
if packet.type != .BinaryAck {
socket.handleEvent(packet.event, data: packet.args ?? [],
isInternalMessage: false, wantsAck: packet.id)
} else {
socket.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))
}
}

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)
}

View File

@ -0,0 +1,203 @@
//
// 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
private var swiftRegexCache = [String: NSRegularExpression]()
internal class SwiftRegex: NSObject, BooleanType {
var target:String
var regex: NSRegularExpression
init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
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()
}
}
super.init()
}
private static func failure(message: String) {
fatalError("SwiftRegex: \(message)")
}
private final var targetRange: NSRange {
return NSRange(location: 0,length: target.utf16.count)
}
private final 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: [])
}
func ~= (left: SwiftRegex, right: [String]) -> String {
var matchNumber = 0
return left.substituteMatches({match, stop -> String in
if ++matchNumber == right.count {
stop.memory = true
}
return left.regex.replacementStringForResult( match,
inString: left.target as String, offset: 0, template: right[matchNumber-1] )
}, options: [])
}
func ~= (left: SwiftRegex, right: (String) -> String) -> String {
// return right(left.substring(match.range))
return left.substituteMatches(
{match, stop -> String in
right(left.substring(match.range)!)
}, options: [])
}
func ~= (left: SwiftRegex, right: ([String]?) -> String) -> String {
return left.substituteMatches({match, stop -> String in
return right(left.groupsForMatch(match))
}, options: [])
}

View File

@ -0,0 +1,981 @@
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Websocket.swift
//
// Created by Dalton Cherry on 7/16/14.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
import Foundation
import CoreFoundation
public protocol WebSocketDelegate: class {
func websocketDidConnect(socket: WebSocket)
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
func websocketDidReceiveMessage(socket: WebSocket, text: String)
func websocketDidReceiveData(socket: WebSocket, data: NSData)
}
public protocol WebSocketPongDelegate: class {
func websocketDidReceivePong(socket: WebSocket)
}
public class WebSocket : NSObject, NSStreamDelegate {
enum OpCode : UInt8 {
case ContinueFrame = 0x0
case TextFrame = 0x1
case BinaryFrame = 0x2
//3-7 are reserved.
case ConnectionClose = 0x8
case Ping = 0x9
case Pong = 0xA
//B-F reserved.
}
enum CloseCode : UInt16 {
case Normal = 1000
case GoingAway = 1001
case ProtocolError = 1002
case ProtocolUnhandledType = 1003
// 1004 reserved.
case NoStatusReceived = 1005
//1006 reserved.
case Encoding = 1007
case PolicyViolated = 1008
case MessageTooBig = 1009
}
enum InternalErrorCode : UInt16 {
// 0-999 WebSocket status codes not used
case OutputStreamWriteError = 1
}
//Where the callback is executed. It defaults to the main UI thread queue.
public var queue = dispatch_get_main_queue()
var optionalProtocols : Array<String>?
//Constant Values.
let headerWSUpgradeName = "Upgrade"
let headerWSUpgradeValue = "websocket"
let headerWSHostName = "Host"
let headerWSConnectionName = "Connection"
let headerWSConnectionValue = "Upgrade"
let headerWSProtocolName = "Sec-WebSocket-Protocol"
let headerWSVersionName = "Sec-WebSocket-Version"
let headerWSVersionValue = "13"
let headerWSKeyName = "Sec-WebSocket-Key"
let headerOriginName = "Origin"
let headerWSAcceptName = "Sec-WebSocket-Accept"
let BUFFER_MAX = 4096
let FinMask: UInt8 = 0x80
let OpCodeMask: UInt8 = 0x0F
let RSVMask: UInt8 = 0x70
let MaskMask: UInt8 = 0x80
let PayloadLenMask: UInt8 = 0x7F
let MaxFrameSize: Int = 32
class WSResponse {
var isFin = false
var code: OpCode = .ContinueFrame
var bytesLeft = 0
var frameCount = 0
var buffer: NSMutableData?
}
public weak var delegate: WebSocketDelegate?
public weak var pongDelegate: WebSocketPongDelegate?
public var onConnect: ((Void) -> Void)?
public var onDisconnect: ((NSError?) -> Void)?
public var onText: ((String) -> Void)?
public var onData: ((NSData) -> Void)?
public var onPong: ((Void) -> Void)?
public var headers = Dictionary<String,String>()
public var voipEnabled = false
public var selfSignedSSL = false
private var security: Security?
public var isConnected :Bool {
return connected
}
private var cookies:[NSHTTPCookie]?
private var url: NSURL
private var inputStream: NSInputStream?
private var outputStream: NSOutputStream?
private var isRunLoop = false
private var connected = false
private var isCreated = false
private var writeQueue: NSOperationQueue?
private var readStack = Array<WSResponse>()
private var inputQueue = Array<NSData>()
private var fragBuffer: NSData?
private var certValidated = false
private var didDisconnect = false
//init the websocket with a url
public init(url: NSURL) {
self.url = url
}
public convenience init(url: NSURL, cookies:[NSHTTPCookie]?) {
self.init(url: url)
self.cookies = cookies
}
//used for setting protocols.
public convenience init(url: NSURL, protocols: Array<String>) {
self.init(url: url)
optionalProtocols = protocols
}
///Connect to the websocket server on a background thread
public func connect() {
if isCreated {
return
}
dispatch_async(queue, { [weak self] in
guard let weakSelf = self else {
return
}
weakSelf.didDisconnect = false
})
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), { [weak self] in
guard let weakSelf = self else {
return
}
weakSelf.isCreated = true
weakSelf.createHTTPRequest()
weakSelf.isCreated = false
})
}
///disconnect from the websocket server
public func disconnect() {
writeError(CloseCode.Normal.rawValue)
}
///write a string to the websocket. This sends it as a text frame.
public func writeString(str: String) {
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame)
}
///write binary data to the websocket. This sends it as a binary frame.
public func writeData(data: NSData) {
dequeueWrite(data, code: .BinaryFrame)
}
//write a ping to the websocket. This sends it as a control frame.
//yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
public func writePing(data: NSData) {
dequeueWrite(data, code: .Ping)
}
//private methods below!
//private method that starts the connection
private func createHTTPRequest() {
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
url, kCFHTTPVersion1_1).takeRetainedValue()
var port = url.port
if port == nil {
if url.scheme == "wss" || url.scheme == "https" {
port = 443
} else {
port = 80
}
}
if self.cookies != nil {
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(self.cookies!)
for (key, value) in headers {
self.addHeader(urlRequest, key: key as String, val: value as String)
}
}
self.addHeader(urlRequest, key: headerWSUpgradeName, val: headerWSUpgradeValue)
self.addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue)
if let protocols = optionalProtocols {
self.addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joinWithSeparator(","))
}
self.addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
self.addHeader(urlRequest, key: headerWSKeyName, val: self.generateWebSocketKey())
self.addHeader(urlRequest, key: headerOriginName, val: url.absoluteString)
self.addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
for (key,value) in headers {
self.addHeader(urlRequest, key: key, val: value)
}
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest)!.takeRetainedValue()
self.initStreamsWithData(serializedRequest, Int(port!))
}
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
private func addHeader(urlRequest: CFHTTPMessage,key: String, val: String) {
let nsKey: NSString = key
let nsVal: NSString = val
CFHTTPMessageSetHeaderFieldValue(urlRequest,
nsKey,
nsVal)
}
//generate a websocket key as needed in rfc
private func generateWebSocketKey() -> String {
var key = ""
let seed = 16
for (var i = 0; i < seed; i++) {
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
key += "\(Character(uni))"
}
let data = key.dataUsingEncoding(NSUTF8StringEncoding)
let baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return baseKey!
}
//Start the stream connection and write the data to the output stream
private func initStreamsWithData(data: NSData, _ port: Int) {
//higher level API we will cut over to at some point
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
let h: NSString = url.host!
CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
inputStream!.delegate = self
outputStream!.delegate = self
if url.scheme == "wss" || url.scheme == "https" {
inputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
outputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
} else {
certValidated = true //not a https session, so no need to check SSL pinning
}
if self.voipEnabled {
inputStream!.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
outputStream!.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
}
if self.selfSignedSSL {
let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String)
}
isRunLoop = true
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream!.open()
outputStream!.open()
let bytes = UnsafePointer<UInt8>(data.bytes)
outputStream!.write(bytes, maxLength: data.length)
while(isRunLoop) {
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as NSDate)
}
}
//delegate for the stream methods. Processes incoming bytes
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
if let sec = security where !certValidated && (eventCode == .HasBytesAvailable || eventCode == .HasSpaceAvailable) {
let possibleTrust: AnyObject? = aStream.propertyForKey(kCFStreamPropertySSLPeerTrust as String)
if let trust: AnyObject = possibleTrust {
let domain: AnyObject? = aStream.propertyForKey(kCFStreamSSLPeerName as String)
if sec.isValid(trust as! SecTrustRef, domain: domain as! String?) {
certValidated = true
} else {
let error = self.errorWithDetail("Invalid SSL certificate", code: 1)
doDisconnect(error)
disconnectStream(error)
return
}
}
}
if eventCode == .HasBytesAvailable {
if(aStream == inputStream) {
processInputStream()
}
} else if eventCode == .ErrorOccurred {
disconnectStream(aStream.streamError)
} else if eventCode == .EndEncountered {
disconnectStream(nil)
}
}
//disconnect the stream object
private func disconnectStream(error: NSError?) {
if writeQueue != nil {
writeQueue!.waitUntilAllOperationsAreFinished()
}
if let stream = inputStream {
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
stream.close()
}
if let stream = outputStream {
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
stream.close()
}
outputStream = nil
isRunLoop = false
certValidated = false
self.doDisconnect(error)
connected = false
}
///handles the incoming bytes and sending them to the proper processing method
private func processInputStream() {
let buf = NSMutableData(capacity: BUFFER_MAX)
let buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
if length > 0 {
if !connected {
let status = processHTTP(buffer, bufferLen: length)
if !status {
self.doDisconnect(self.errorWithDetail("Invalid HTTP upgrade", code: 1))
}
} else {
var process = false
if inputQueue.count == 0 {
process = true
}
inputQueue.append(NSData(bytes: buffer, length: length))
if process {
dequeueInput()
}
}
}
}
///dequeue the incoming input so it is processed in order
private func dequeueInput() {
if inputQueue.count > 0 {
let data = inputQueue[0]
var work = data
if (fragBuffer != nil) {
let combine = NSMutableData(data: fragBuffer!)
combine.appendData(data)
work = combine
fragBuffer = nil
}
let buffer = UnsafePointer<UInt8>(work.bytes)
processRawMessage(buffer, bufferLen: work.length)
inputQueue = inputQueue.filter{$0 != data}
dequeueInput()
}
}
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
var k = 0
var totalSize = 0
for var i = 0; i < bufferLen; i++ {
if buffer[i] == CRLFBytes[k] {
k++
if k == 3 {
totalSize = i + 1
break
}
} else {
k = 0
}
}
if totalSize > 0 {
if validateResponse(buffer, bufferLen: totalSize) {
dispatch_async(queue, {
self.connected = true
if let connectBlock = self.onConnect {
connectBlock()
}
self.delegate?.websocketDidConnect(self)
})
totalSize += 1 //skip the last \n
let restSize = bufferLen - totalSize
if restSize > 0 {
processRawMessage((buffer+totalSize), bufferLen: restSize)
}
return true
}
}
return false
}
///validates the HTTP is a 101 as per the RFC spec
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
if CFHTTPMessageGetResponseStatusCode(response) != 101 {
return false
}
let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response)
let headers:NSDictionary? = cfHeaders?.takeRetainedValue()
let acceptKey = headers?[headerWSAcceptName] as! NSString
if acceptKey.length > 0 {
return true
}
return false
}
///process the websocket data
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
let response = readStack.last
if response != nil && bufferLen < 2 {
fragBuffer = NSData(bytes: buffer, length: bufferLen)
return
}
if response != nil && response!.bytesLeft > 0 {
let resp = response!
var len = resp.bytesLeft
var extra = bufferLen - resp.bytesLeft
if resp.bytesLeft > bufferLen {
len = bufferLen
extra = 0
}
resp.bytesLeft -= len
resp.buffer?.appendData(NSData(bytes: buffer, length: len))
processResponse(resp)
let offset = bufferLen - extra
if extra > 0 {
processExtra((buffer+offset), bufferLen: extra)
}
return
} else {
let isFin = (FinMask & buffer[0])
let receivedOpcode = (OpCodeMask & buffer[0])
let isMasked = (MaskMask & buffer[1])
let payloadLen = (PayloadLenMask & buffer[1])
var offset = 2
if((isMasked > 0 || (RSVMask & buffer[0]) > 0) && receivedOpcode != OpCode.Pong.rawValue) {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("masked and rsv data is not currently supported", code: errCode)
self.doDisconnect(error)
writeError(errCode)
return
}
let isControlFrame = (receivedOpcode == OpCode.ConnectionClose.rawValue || receivedOpcode == OpCode.Ping.rawValue)
if !isControlFrame && (receivedOpcode != OpCode.BinaryFrame.rawValue && receivedOpcode != OpCode.ContinueFrame.rawValue &&
receivedOpcode != OpCode.TextFrame.rawValue && receivedOpcode != OpCode.Pong.rawValue) {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)
self.doDisconnect(error)
writeError(errCode)
return
}
if isControlFrame && isFin == 0 {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("control frames can't be fragmented", code: errCode)
self.doDisconnect(error)
writeError(errCode)
return
}
if receivedOpcode == OpCode.ConnectionClose.rawValue {
var code = CloseCode.Normal.rawValue
if payloadLen == 1 {
code = CloseCode.ProtocolError.rawValue
} else if payloadLen > 1 {
let codeBuffer = UnsafePointer<UInt16>((buffer+offset))
code = codeBuffer[0].bigEndian
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
code = CloseCode.ProtocolError.rawValue
}
offset += 2
}
if payloadLen > 2 {
let len = Int(payloadLen-2)
if len > 0 {
let bytes = UnsafePointer<UInt8>((buffer+offset))
let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
if str == nil {
code = CloseCode.ProtocolError.rawValue
}
}
}
let error = self.errorWithDetail("connection closed by server", code: code)
self.doDisconnect(error)
writeError(code)
return
}
if isControlFrame && payloadLen > 125 {
writeError(CloseCode.ProtocolError.rawValue)
return
}
var dataLength = UInt64(payloadLen)
if dataLength == 127 {
let bytes = UnsafePointer<UInt64>((buffer+offset))
dataLength = bytes[0].bigEndian
offset += sizeof(UInt64)
} else if dataLength == 126 {
let bytes = UnsafePointer<UInt16>((buffer+offset))
dataLength = UInt64(bytes[0].bigEndian)
offset += sizeof(UInt16)
}
if bufferLen < offset || UInt64(bufferLen - offset) < dataLength {
fragBuffer = NSData(bytes: buffer, length: bufferLen)
return
}
var len = dataLength
if dataLength > UInt64(bufferLen) {
len = UInt64(bufferLen-offset)
}
var data: NSData!
if len < 0 {
len = 0
data = NSData()
} else {
data = NSData(bytes: UnsafePointer<UInt8>((buffer+offset)), length: Int(len))
}
if receivedOpcode == OpCode.Pong.rawValue {
dispatch_async(queue, {
self.onPong?()
self.pongDelegate?.websocketDidReceivePong(self)
})
let step = Int(offset+numericCast(len))
let extra = bufferLen-step
if extra > 0 {
processRawMessage((buffer+step), bufferLen: extra)
}
return
}
var response = readStack.last
if isControlFrame {
response = nil //don't append pings
}
if isFin == 0 && receivedOpcode == OpCode.ContinueFrame.rawValue && response == nil {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("continue frame before a binary or text frame", code: errCode)
self.doDisconnect(error)
writeError(errCode)
return
}
var isNew = false
if(response == nil) {
if receivedOpcode == OpCode.ContinueFrame.rawValue {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("first frame can't be a continue frame",
code: errCode)
self.doDisconnect(error)
writeError(errCode)
return
}
isNew = true
response = WSResponse()
response!.code = OpCode(rawValue: receivedOpcode)!
response!.bytesLeft = Int(dataLength)
response!.buffer = NSMutableData(data: data)
} else {
if receivedOpcode == OpCode.ContinueFrame.rawValue {
response!.bytesLeft = Int(dataLength)
} else {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("second and beyond of fragment message must be a continue frame",
code: errCode)
self.doDisconnect(error)
writeError(errCode)
return
}
response!.buffer!.appendData(data)
}
if response != nil {
response!.bytesLeft -= Int(len)
response!.frameCount++
response!.isFin = isFin > 0 ? true : false
if(isNew) {
readStack.append(response!)
}
processResponse(response!)
}
let step = Int(offset+numericCast(len))
let extra = bufferLen-step
if(extra > 0) {
processExtra((buffer+step), bufferLen: extra)
}
}
}
///process the extra of a buffer
private func processExtra(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
if bufferLen < 2 {
fragBuffer = NSData(bytes: buffer, length: bufferLen)
} else {
processRawMessage(buffer, bufferLen: bufferLen)
}
}
///process the finished response of a buffer
private func processResponse(response: WSResponse) -> Bool {
if response.isFin && response.bytesLeft <= 0 {
if response.code == .Ping {
let data = response.buffer! //local copy so it is perverse for writing
dequeueWrite(data, code: OpCode.Pong)
} else if response.code == .TextFrame {
let str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding)
if let str = str as String? {
dispatch_async(queue, {
self.onText?(str)
self.delegate?.websocketDidReceiveMessage(self, text: str)
})
} else {
writeError(CloseCode.Encoding.rawValue)
return false
}
} else if response.code == .BinaryFrame {
let data = response.buffer! //local copy so it is perverse for writing
dispatch_async(queue) {
self.onData?(data)
self.delegate?.websocketDidReceiveData(self, data: data)
}
}
readStack.removeLast()
return true
}
return false
}
///Create an error
private func errorWithDetail(detail: String, code: UInt16) -> NSError {
var details = Dictionary<String,String>()
details[NSLocalizedDescriptionKey] = detail
return NSError(domain: "Websocket", code: Int(code), userInfo: details)
}
///write a an error to the socket
private func writeError(code: UInt16) {
let buf = NSMutableData(capacity: sizeof(UInt16))
let buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
buffer[0] = code.bigEndian
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
}
///used to write things to the stream
private func dequeueWrite(data: NSData, code: OpCode) {
if writeQueue == nil {
writeQueue = NSOperationQueue()
writeQueue!.maxConcurrentOperationCount = 1
}
writeQueue!.addOperationWithBlock {
//stream isn't ready, let's wait
var tries = 0;
while self.outputStream == nil || !self.connected {
if(tries < 5) {
sleep(1);
} else {
break;
}
tries++;
}
if !self.connected {
return
}
var offset = 2
UINT16_MAX
let bytes = UnsafeMutablePointer<UInt8>(data.bytes)
let dataLength = data.length
let frame = NSMutableData(capacity: dataLength + self.MaxFrameSize)
let buffer = UnsafeMutablePointer<UInt8>(frame!.mutableBytes)
buffer[0] = self.FinMask | code.rawValue
if dataLength < 126 {
buffer[1] = CUnsignedChar(dataLength)
} else if dataLength <= Int(UInt16.max) {
buffer[1] = 126
let sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
sizeBuffer[0] = UInt16(dataLength).bigEndian
offset += sizeof(UInt16)
} else {
buffer[1] = 127
let sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
sizeBuffer[0] = UInt64(dataLength).bigEndian
offset += sizeof(UInt64)
}
buffer[1] |= self.MaskMask
let maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey)
offset += sizeof(UInt32)
for (var i = 0; i < dataLength; i++) {
buffer[offset] = bytes[i] ^ maskKey[i % sizeof(UInt32)]
offset += 1
}
var total = 0
while true {
if self.outputStream == nil {
break
}
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total)
let len = self.outputStream?.write(writeBuffer, maxLength: offset-total)
if len == nil || len! < 0 {
var error: NSError?
if let streamError = self.outputStream?.streamError {
error = streamError
} else {
let errCode = InternalErrorCode.OutputStreamWriteError.rawValue
error = self.errorWithDetail("output stream error during write", code: errCode)
}
self.doDisconnect(error)
break
} else {
total += len!
}
if total >= offset {
break
}
}
}
}
///used to preform the disconnect delegate
private func doDisconnect(error: NSError?) {
if !self.didDisconnect {
dispatch_async(queue) {
self.didDisconnect = true
self.onDisconnect?(error)
self.delegate?.websocketDidDisconnect(self, error: error)
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Security.swift
// Starscream
//
// Created by Dalton Cherry on 5/16/15.
// Copyright (c) 2015 Vluxe. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
import Foundation
import Security
private class SSLCert {
var certData: NSData?
var key: SecKeyRef?
/**
Designated init for certificates
:param: data is the binary data of the certificate
:returns: a representation security object to be used with
*/
init(data: NSData) {
self.certData = data
}
/**
Designated init for public keys
:param: key is the public key to be used
:returns: a representation security object to be used with
*/
init(key: SecKeyRef) {
self.key = key
}
}
private class Security {
private var validatedDN = true //should the domain name be validated?
var isReady = false //is the key processing done?
var certificates: [NSData]? //the certificates
var pubKeys: [SecKeyRef]? //the public keys
var usePublicKeys = false //use public keys or certificate validation?
/**
Use certs from main app bundle
:param: usePublicKeys is to specific if the publicKeys or certificates should be used for SSL pinning validation
:returns: a representation security object to be used with
*/
private convenience init(usePublicKeys: Bool = false) {
let paths = NSBundle.mainBundle().pathsForResourcesOfType("cer", inDirectory: ".")
var collect = Array<SSLCert>()
for path in paths {
if let d = NSData(contentsOfFile: path as String) {
collect.append(SSLCert(data: d))
}
}
self.init(certs:collect, usePublicKeys: usePublicKeys)
}
/**
Designated init
:param: keys is the certificates or public keys to use
:param: usePublicKeys is to specific if the publicKeys or certificates should be used for SSL pinning validation
:returns: a representation security object to be used with
*/
private init(certs: [SSLCert], usePublicKeys: Bool) {
self.usePublicKeys = usePublicKeys
if self.usePublicKeys {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
var collect = Array<SecKeyRef>()
for cert in certs {
if let data = cert.certData where cert.key == nil {
cert.key = self.extractPublicKey(data)
}
if let k = cert.key {
collect.append(k)
}
}
self.pubKeys = collect
self.isReady = true
})
} else {
var collect = Array<NSData>()
for cert in certs {
if let d = cert.certData {
collect.append(d)
}
}
self.certificates = collect
self.isReady = true
}
}
/**
Valid the trust and domain name.
:param: trust is the serverTrust to validate
:param: domain is the CN domain to validate
:returns: if the key was successfully validated
*/
private func isValid(trust: SecTrustRef, domain: String?) -> Bool {
var tries = 0
while(!self.isReady) {
usleep(1000)
tries += 1
if tries > 5 {
return false //doesn't appear it is going to ever be ready...
}
}
var policy: SecPolicyRef
if self.validatedDN {
policy = SecPolicyCreateSSL(true, domain)
} else {
policy = SecPolicyCreateBasicX509()
}
SecTrustSetPolicies(trust,policy)
if self.usePublicKeys {
if let keys = self.pubKeys {
var trustedCount = 0
let serverPubKeys = publicKeyChainForTrust(trust)
for serverKey in serverPubKeys as [AnyObject] {
for key in keys as [AnyObject] {
if serverKey.isEqual(key) {
trustedCount++
break
}
}
}
if trustedCount == serverPubKeys.count {
return true
}
}
} else if let certs = self.certificates {
let serverCerts = certificateChainForTrust(trust)
var collect = Array<SecCertificate>()
for cert in certs {
collect.append(SecCertificateCreateWithData(nil,cert)!)
}
SecTrustSetAnchorCertificates(trust,collect)
var result: SecTrustResultType = 0
SecTrustEvaluate(trust,&result)
let r = Int(result)
if r == kSecTrustResultUnspecified || r == kSecTrustResultProceed {
var trustedCount = 0
for serverCert in serverCerts {
for cert in certs {
if cert == serverCert {
trustedCount++
break
}
}
}
if trustedCount == serverCerts.count {
return true
}
}
}
return false
}
/**
Get the public key from a certificate data
:param: data is the certificate to pull the public key from
:returns: a public key
*/
func extractPublicKey(data: NSData) -> SecKeyRef? {
let possibleCert = SecCertificateCreateWithData(nil,data)
if let cert = possibleCert {
return extractPublicKeyFromCert(cert,policy: SecPolicyCreateBasicX509())
}
return nil
}
/**
Get the public key from a certificate
:param: data is the certificate to pull the public key from
:returns: a public key
*/
func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKeyRef? {
let possibleTrust = UnsafeMutablePointer<SecTrust?>.alloc(1)
SecTrustCreateWithCertificates( cert, policy, possibleTrust)
if let trust = possibleTrust.memory {
var result: SecTrustResultType = 0
SecTrustEvaluate(trust,&result)
return SecTrustCopyPublicKey(trust)
}
return nil
}
/**
Get the certificate chain for the trust
:param: trust is the trust to lookup the certificate chain for
:returns: the certificate chain for the trust
*/
func certificateChainForTrust(trust: SecTrustRef) -> Array<NSData> {
var collect = Array<NSData>()
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
let cert = SecTrustGetCertificateAtIndex(trust,i)
collect.append(SecCertificateCopyData(cert!))
}
return collect
}
/**
Get the public key chain for the trust
:param: trust is the trust to lookup the certificate chain and extract the public keys
:returns: the public keys from the certifcate chain for the trust
*/
func publicKeyChainForTrust(trust: SecTrustRef) -> Array<SecKeyRef> {
var collect = Array<SecKeyRef>()
let policy = SecPolicyCreateBasicX509()
for var i = 0; i < SecTrustGetCertificateCount(trust); i++ {
let cert = SecTrustGetCertificateAtIndex(trust,i)
if let key = extractPublicKeyFromCert(cert!, policy: policy) {
collect.append(key)
}
}
return collect
}
}

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,75 +0,0 @@
//
// SocketLogger.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 4/11/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
/// Represents a class will log client events.
public protocol SocketLogger : AnyObject {
// MARK: Properties
/// Whether to log or not
var log: Bool { get set }
// MARK: Methods
/// 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)
/// 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)
}
public extension SocketLogger {
/// Default implementation.
func log(_ message: @autoclosure () -> String, type: String) {
guard log else { return }
abstractLog("LOG", message: message(), type: type)
}
/// Default implementation.
func error(_ message: @autoclosure () -> String, type: String) {
guard log else { return }
abstractLog("ERROR", message: message(), type: type)
}
private func abstractLog(_ logType: String, message: @autoclosure () -> String, type: String) {
NSLog("\(logType) \(type): %@", message())
}
}
class DefaultSocketLogger : SocketLogger {
static var Logger: SocketLogger = DefaultSocketLogger()
var log = false
}

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)
}

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,147 +0,0 @@
//
// SocketParserTest.swift
// Socket.IO-Client-Swift
//
// Created by Lukas Schmidt on 05.09.15.
//
//
import XCTest
@testable import SocketIO
class SocketParserTest: XCTestCase {
func testDisconnect() {
let message = "1"
validateParseResult(message)
}
func testConnect() {
let message = "0"
validateParseResult(message)
}
func testDisconnectNameSpace() {
let message = "1/swift"
validateParseResult(message)
}
func testConnecttNameSpace() {
let message = "0/swift"
validateParseResult(message)
}
func testIdEvent() {
let message = "25[\"test\"]"
validateParseResult(message)
}
func testBinaryPlaceholderAsString() {
let message = "2[\"test\",\"~~0\"]"
validateParseResult(message)
}
func testNameSpaceArrayParse() {
let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]"
validateParseResult(message)
}
func testNameSpaceArrayAckParse() {
let message = "3/swift,0[[\"test3\",\"test4\"]]"
validateParseResult(message)
}
func testNameSpaceBinaryEventParse() {
let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
validateParseResult(message)
}
func testNameSpaceBinaryAckParse() {
let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
validateParseResult(message)
}
func testNamespaceErrorParse() {
let message = "4/swift,"
validateParseResult(message)
}
func testErrorTypeString() {
let message = "4\"ERROR\""
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 {
}
}
func testGenericParser() {
var parser = SocketStringReader(message: "61-/swift,")
XCTAssertEqual(parser.read(count: 1), "6")
XCTAssertEqual(parser.currentCharacter, "1")
XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1")
XCTAssertEqual(parser.currentCharacter, "/")
}
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)
}
func testParsePerformance() {
let keys = Array(SocketParserTest.packetTypes.keys)
measure {
for item in keys.enumerated() {
_ = try! self.testManager.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

@ -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>

View File

@ -1,452 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SocketEnginePacketType 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/SocketEnginePacketType" class="dashAnchor"></a>
<a title="SocketEnginePacketType 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" />
SocketEnginePacketType 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>SocketEnginePacketType</h1>
<div class="declaration">
<div class="language">
<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>
<p>Represents the type of engine.io packet types.</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@E@SocketEnginePacketType@SocketEnginePacketTypeOpen"></a>
<a name="//apple_ref/swift/Element/open" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeOpen">open</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Open message.</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="kd">open</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeClose"></a>
<a name="//apple_ref/swift/Element/close" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeClose">close</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Close message.</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">close</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypePing"></a>
<a name="//apple_ref/swift/Element/ping" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypePing">ping</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Ping message.</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">ping</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypePong"></a>
<a name="//apple_ref/swift/Element/pong" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypePong">pong</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Pong message.</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">pong</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeMessage"></a>
<a name="//apple_ref/swift/Element/message" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeMessage">message</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Regular message.</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">message</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeUpgrade"></a>
<a name="//apple_ref/swift/Element/upgrade" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeUpgrade">upgrade</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>Upgrade message.</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">upgrade</span></code></pre>
</div>
</div>
</section>
</div>
</li>
<li class="item">
<div>
<code>
<a name="/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeNoop"></a>
<a name="//apple_ref/swift/Element/noop" class="dashAnchor"></a>
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType@SocketEnginePacketTypeNoop">noop</a>
</code>
</div>
<div class="height-container">
<div class="pointer-container"></div>
<section class="section">
<div class="pointer"></div>
<div class="abstract">
<p>NOOP.</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">noop</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