Compare commits

...

718 Commits

Author SHA1 Message Date
Erik Little
42da871d93
update readme 2024-10-01 12:32:32 -04:00
Erik Little
03032d0c72
Update some more deps; bump version 2024-10-01 12:30:52 -04:00
Erik Little
d690d9c1bf
Merge pull request #1464 from socketio/development
v16.1.1
2024-10-01 12:28:07 -04:00
Erik Little
99cc2448f7
Merge pull request #1467 from olejnjak/xcode15
Xcode 15 support
2024-10-01 12:16:49 -04:00
Erik Little
99b673dfa5
Merge pull request #1491 from hsjcom/master
Fix the issue where it takes over 60 seconds to close the socket after a network disconnection
2024-10-01 12:15:25 -04:00
Erik Little
b4bff5db90
Merge pull request #1492 from xxZap/master
Support Privacy Manifest: bump Starscream package version to upToNextMajor 4.0.8
2024-10-01 12:14:08 -04:00
Shaojie Hong
354ed7e5e4
Update SocketEngine.swift
Fix the issue where it takes over 60 seconds to close the socket after a network disconnection, and the problem where the server-side socket takes over 30 seconds to close when the server ends a connection
2024-05-09 16:58:16 +08:00
Alessio Zap Boerio
5ecc5bbae9 Bump Starscream version to upToNextMajor 4.0.8 2024-04-15 13:39:56 +02:00
Erik Little
d069bbeefe
Merge pull request #1482 from elefantel/patch-1
Bump minimum deployment target to iOS 12 to match Starscream dependency
2024-03-18 09:11:26 -04:00
Mpendulo Ndlovu
eb806b62bf
Bump minimum deployment target to iOS 12 to match Starscream dependency
Currently there is an error when compiling for release:
```
Compiling for iOS 11.0, but module 'Starscream' has a minimum deployment target of iOS 12.0
```

This pull request addresses this error by bumping the minimum deployment target to match Starscream.
2024-03-18 11:18:13 +02:00
Jakub Olejnik
6dd51170bb Bump Carthage deployment targets 2023-11-21 16:24:22 +01:00
Erik Little
76b941933e
Merge pull request #1463 from davidkessler-ch/master
fix never running timingOut due to weak self capture
2023-11-13 15:40:51 -05:00
Erik Little
71a627c099
Merge pull request #1375 from emersonsoftware/fix_reconnect_issue
Handling reconnect scenarios properly when socket is hung
2023-11-13 15:40:16 -05:00
David K
a21af1016e
fix never running timingOut due to weak self capture 2023-11-10 23:49:06 +01:00
Erik Little
85585c42c0
Merge pull request #1437 from humanfriend22/type-patch-1
Typo in README example code
2023-08-28 14:52:04 -04:00
Erik Little
175da8b515
bump tvos version 2023-08-28 14:34:00 -04:00
Erik Little
ccc73e3790
bump podspec 2023-08-28 14:29:54 -04:00
Erik Little
786b11ad46
update changelog 2023-08-28 14:19:25 -04:00
Erik Little
332a25f241
update to newer starscream 2023-08-25 10:40:32 -04:00
Erik Little
12b08a975f
change ios version; dep 2023-08-25 10:12:51 -04:00
Erik Little
2058eba1fb
Merge remote-tracking branch 'origin/master' into development
* origin/master:
  Fix Starscream to version 4.0.4
  Remove unused var in SocketAckManagerTest.testManagerTimeoutAck
2023-08-25 10:05:46 -04:00
Erik Little
d7846b31a2
Merge pull request #1451 from IvanGamov/fix/StarScreamPackage
Fix Starscream to version 4.0.4
2023-08-21 08:12:56 -04:00
Ivan Gamov
3c81d0ee55 Fix Starscream to version 4.0.4 2023-08-21 15:08:52 +03:00
Erik Little
0898078cc8
Merge pull request #1448 from NachoSoto/xros
Add support for `xrOS`
2023-06-26 11:59:06 -04:00
NachoSoto
69124a74e8 Updated Starscream 2023-06-24 16:12:30 -07:00
NachoSoto
4325b6d139 Add support for xrOS 2023-06-24 16:00:11 -07:00
NachoSoto
66eca437b8 Disabled Bitcode for Xcode 14 2023-06-24 15:58:52 -07:00
humanfriend22
8837d4a0d8 correct SocketActStatus in example code 2023-03-10 04:03:36 +00:00
Erik Little
61a7f2e936
Merge pull request #1420 from ranker-dev/feature/custom-engine-option
Add option to allow the use of URLSessionWebSocketTask in WebSocket client.
2022-07-29 10:49:57 -04:00
George Navarro
45cc6b9728 Added a useCustomEngine option to control if WebSocket is initialized to use the custom engine or native URLSession web tasks. 2022-07-25 18:13:20 -07:00
Erik Little
173def3cea
Remove travis 2022-07-12 14:55:55 -04:00
Erik Little
2b1cd74f6a
Take weak reference to self in OnAckCallback 2022-07-12 14:34:38 -04:00
Erik Little
e1c18a3ea8
Merge pull request #1410 from NachoSoto/headers-phase
Fixed build phases order in target
2022-04-18 15:03:48 -04:00
NachoSoto
eb9de532f1 Fixed build phases order in target
See [Xcode 10's known issues](https://developer.apple.com/documentation/xcode-release-notes/build-system-release-notes-for-xcode-10) in the release notes:

> Targets with Copy Headers build phases ordered after Compile Sources build phases may fail to build and emit a diagnostic regarding build cycles. (39880168)
>*Workaround*: Arrange any Copy Headers build phases before Compile Sources build phases.

This has been an issue for nearly 4 years, and now with Xcode 13.3 it leads to `XCBBuildService` to crash consistently.
2022-04-18 20:16:09 +02:00
Erik Little
a1ed825835
Merge pull request #1388 from filblue/rm-unused-var-in-SocketAckManagerTest.testManagerTimeoutAck
Remove unused var in SocketAckManagerTest.testManagerTimeoutAck
2021-12-01 16:57:27 -05:00
filblue
cc3ce5679e Remove unused var in SocketAckManagerTest.testManagerTimeoutAck 2021-11-12 18:18:26 +03:00
Erik Little
b686b17e0a
Merge pull request #1385 from NachoSoto/master
Added support for Mac Catalyst
2021-11-02 12:19:46 -07:00
NachoSoto
c6d28246ea Updated project to use XCFramework
This enables support for macCatalyst
2021-11-02 11:05:38 -07:00
NachoSoto
f4f071551f Added support for Mac Catalyst 2021-10-29 19:50:45 -07:00
Mark Schisler
ec4378ca49
Handling reconnect scenarios properly when socket is hung 2021-08-19 09:45:54 -05:00
Erik Little
d031afdbc4
Merge pull request #1362 from darrachequesne/docs/compatibility
docs: add compatibility table
2021-07-10 06:51:24 -04:00
Damien Arrachequesne
61d0a41103
docs: add compatibility table 2021-07-10 11:32:24 +02:00
Erik Little
07f2d08981
Merge pull request #1359 from WyattMufson/swift-fixes
Fix swift warnings
2021-06-19 12:36:38 -04:00
Wyatt Mufson
9609774b3a Fix swift warnings 2021-06-17 11:38:43 -04:00
Erik Little
8d9a613835
Merge pull request #1335 from TysonAndre/patch-1
Fix typo in 15to16 upgrading notes
2021-03-02 14:44:39 -05:00
Tyson Andre
678fb81ed5
Fix typo in 15to16 upgrading notes 2021-03-02 14:42:02 -05:00
Erik Little
af5ce97b75
Merge branch 'development'
* development:
  handle version in keyValueToSocketIOClientOption
  Updated methods signature
  Added client emit methods with array parameters
2021-02-16 09:38:49 -05:00
Erik Little
2c78e36ebd
handle version in keyValueToSocketIOClientOption 2021-02-16 09:37:05 -05:00
Erik Little
162eb3d649
Merge pull request #1324 from OneSman7/development
Added client emit methods with array parameters
2021-02-10 08:57:19 -05:00
Erasov Ivan
ef6b63c82f Updated methods signature 2021-02-09 00:13:42 +03:00
Erasov Ivan
c015012783 Added client emit methods with array parameters 2021-02-05 19:14:54 +03:00
Erik Little
6b80f75ec8
Merge branch 'development'
* development:
  Update and gen docs
  prepare podspec for release
  Regenerate docs
  update docs, remove other prints
  remove print
  Support both v2 and v3
  Start working on migration guide
  update docs
  Add ability to send payload with connect
  more CocoaPods testing
  CocoaPods testing
  Fix tests
  Better timeouts
  Support socket.io 3 + starscream 4
  update examples for new operator
  Add some helpful operators
  fix swift syntax highlighting
  show how to test for ack timeouts
2021-02-01 09:30:30 -05:00
Erik Little
bdcdddf465
Merge pull request #1309 from socketio/socket.io-3
Support socket.io 3 + starscream 4
2021-02-01 09:28:32 -05:00
Erik Little
2a0e0f5e28
Update and gen docs 2021-02-01 09:27:44 -05:00
Erik Little
888b84aee2
prepare podspec for release 2021-01-27 13:58:57 -05:00
Erik Little
8b1149255d
Regenerate docs 2021-01-27 13:57:46 -05:00
Erik Little
2913751beb
update docs, remove other prints 2021-01-27 13:40:07 -05:00
Erik Little
1c2af5a60f
remove print 2021-01-27 13:24:42 -05:00
Erik Little
fde88c10c5
Support both v2 and v3 2021-01-27 13:22:14 -05:00
Erik Little
21290f5752
Start working on migration guide 2020-11-07 19:19:06 -05:00
Erik Little
194642314e
update docs 2020-11-07 18:57:29 -05:00
Erik Little
d7d8903fee
Add ability to send payload with connect 2020-11-07 18:53:06 -05:00
Erik Little
ce4de49d50
more CocoaPods testing 2020-11-07 17:34:16 -05:00
Erik Little
b130231f4e
CocoaPods testing 2020-11-07 17:16:48 -05:00
Erik Little
7ce0d99526
Fix tests 2020-11-07 17:06:05 -05:00
Erik Little
c6a6d952e6
Better timeouts 2020-11-07 16:03:29 -05:00
Erik Little
6cd8f79e8b
Support socket.io 3 + starscream 4 2020-11-07 15:13:52 -05:00
Erik Little
9433f60557
Merge pull request #1165 from petergp/feature/allow-app-extension-api-only
Enabled allow app extension api only
2020-11-07 12:49:25 -05:00
Erik Little
6992ea5250
update examples for new operator 2019-11-25 14:37:13 -05:00
Erik Little
a06af14dd9
Add some helpful operators 2019-11-25 14:34:11 -05:00
Erik Little
68376581a0
fix swift syntax highlighting 2019-11-25 14:18:37 -05:00
Erik Little
eb47dcadd4
show how to test for ack timeouts 2019-11-25 14:16:43 -05:00
Erik Little
36db2ff0eb
Merge branch 'development'
* development:
  bump version
  bump travis xcode version
  Fixed endless reconnection loop
2019-10-17 06:32:23 -04:00
Erik Little
046bb0e9ff
bump version 2019-10-17 06:32:02 -04:00
Erik Little
0dc4dd4a93
bump travis xcode version 2019-10-17 06:18:42 -04:00
Erik Little
cb74f6ca55
Merge branch 'master' into development
* master:
  Updates test
  Adds missing character for url percent encoding
2019-10-17 06:06:26 -04:00
Erik Little
1a0f6bb6ce
Merge pull request #1241 from scorealarm/bugfix/adds-missing-character-for-url-encoding
Adds missing character for url encoding
2019-10-17 06:05:38 -04:00
Erik Little
091797f9b7
Merge pull request #1231 from salpeev/fix/reconnection
Fixed endless reconnection loop
2019-10-17 06:03:32 -04:00
Marin Huljev
5611c8ad24 Updates test 2019-10-14 23:02:17 +02:00
Marin Huljev
ae54ea01d0 Adds missing character for url percent encoding 2019-10-14 22:06:31 +02:00
Serhii Alpieiev
1db9232d71 Fixed endless reconnection loop 2019-09-07 18:07:19 +03:00
Erik Little
5dcfe18748
bump version and docs 2019-05-28 09:09:24 -04:00
Erik Little
558ea65aa1
Merge branch 'development'
* development:
  update changelog/readme for 15.1
  update changelog
  fix #1178
  expose Starscream WebSocket enableSOCKSProxy option to socket.io-client-swift options
2019-05-28 09:04:09 -04:00
Erik Little
0d44b10734
update changelog/readme for 15.1 2019-05-28 08:55:11 -04:00
Erik Little
c1744e9e6f
Merge pull request #1049 from pdupris/enableSOCKSProxy
Add enableSOCKSProxy option to pass to Starscream WebSockets
2019-05-28 08:50:11 -04:00
Erik Little
2fd9e4b993
update changelog 2019-03-28 07:17:45 -04:00
Erik Little
44682659b6
fix #1178 2019-03-28 07:11:35 -04:00
Erik Little
148c302474
bump version and docs 2019-03-28 06:29:32 -04:00
Erik Little
6037b85f4b
Merge branch 'development'
* development:
  correct beta version in podspec
  beta version
  swift 5
  call closeOutEngine to clean up after a ping timeout
2019-03-28 06:26:13 -04:00
Erik Little
bd7428485c
correct beta version in podspec 2019-03-26 12:41:23 -04:00
Erik Little
3df38fcff5
beta version 2019-03-26 12:35:31 -04:00
Erik Little
7219906306
swift 5 2019-03-26 12:20:34 -04:00
Erik Little
7e0917c2cd
Merge branch 'master' into development
* master:
  bump version and docs
  update readme and changelog for new version
2019-03-26 12:16:58 -04:00
Peter Gammelgaard Poulsen
0df634a586 Enabled allow app extension api only 2019-03-05 20:52:03 +01:00
Erik Little
1a8285fcf0
Merge pull request #1159 from cobrowseio/development
Call closeOutEngine to clean up after a ping timeout
2019-02-28 07:16:27 -05:00
Andy
fc4e1802f6 call closeOutEngine to clean up after a ping timeout 2019-02-11 19:01:43 +00:00
Erik Little
19a177485d
bump version and docs 2019-01-16 08:54:32 -05:00
Erik Little
00aaea935c
Merge branch 'development'
* development:
  update readme and changelog for new version
  add changelog entry for exponential backoff
  config setting and test updates for reconnectWaitMax and randomizationFactor
  add configurable exponential backoff
  Fix #1147
  Bump Starscream to 3.0.6
  Update to Swift 4.2
2019-01-16 08:51:31 -05:00
Erik Little
6a3d82c60a
update readme and changelog for new version 2019-01-16 08:51:21 -05:00
Erik Little
4c98c24047
Merge pull request #1149 from cobrowseio/development
Add configurable exponential backoff
2019-01-14 14:28:27 -05:00
Andy
a17a66af00 add changelog entry for exponential backoff 2019-01-14 19:16:58 +00:00
Andy
9433050588 config setting and test updates for reconnectWaitMax and randomizationFactor 2019-01-12 22:05:01 +00:00
Andy
49b9a07a95 add configurable exponential backoff 2019-01-12 19:44:51 +00:00
Erik Little
f407beab99
Fix #1147 2019-01-11 12:39:54 -05:00
Erik Little
fa81fc222f
Merge pull request #1126 from DmitryPR/swift-update
Swift update
2018-11-28 17:26:46 -05:00
Erik Little
649989fd83
Merge branch 'master' into development
* master:
  bump version
2018-11-28 17:23:34 -05:00
Erik Little
f7ef126d97
bump version 2018-11-28 17:14:29 -05:00
Erik Little
e4f63e8f15
Merge branch 'development'
* development:
  Remove unnecessary function calls.
  Fix build
  Don’t create empty closures when we don’t need them. Fixes https://github.com/socketio/socket.io-client-swift/issues/1118.
  Propagate http header callback from websocket back to client.
  clean up emit completion code
  update cartfile too
  update deps: Fix #1105
  update xcode settings
  convert SocketData to serialisable socket representation
  Add a variadic method for emit completion handlers in swift
  no need to capture completion hander in wrapper
  wrap completion handler to run on handleQueue
  add optional write completion handler for emit's
2018-11-28 17:08:17 -05:00
Dmitry Preobrazhenskiy
3cfd12b0bc Bump Starscream to 3.0.6
This solves the issue:
https://github.com/socketio/socket.io-client-swift/issues/1105
2018-11-28 23:38:13 +02:00
Dmitry Preobrazhenskiy
94b01420af Update to Swift 4.2
This solves the issue:
https://github.com/socketio/socket.io-client-swift/issues/1101
2018-11-28 23:37:27 +02:00
Erik Little
ec86a19fc6
Merge pull request #1119 from vonox7/completion-handler-nil
Don’t create empty closures when we don’t need them
2018-11-07 09:38:22 -05:00
Valentin Slawicek
e0cbe59a10 Remove unnecessary function calls. 2018-11-07 13:53:25 +01:00
Valentin Slawicek
8f94c038d8 Fix build 2018-11-07 12:47:55 +01:00
Valentin Slawicek
a4b334b6f2 Don’t create empty closures when we don’t need them.
Fixes https://github.com/socketio/socket.io-client-swift/issues/1118.
2018-11-07 12:37:48 +01:00
Erik Little
9708019adc
Merge pull request #1112 from vonox7/http-header-callback-rebased
Propagate http header callback from websocket back to client (rebased)
2018-10-18 10:57:00 -04:00
Valentin Slawicek
5a6a4f02d9 Propagate http header callback from websocket back to client. 2018-10-17 21:38:19 +02:00
Erik Little
75057023cb
clean up emit completion code 2018-10-17 09:55:11 -04:00
Erik Little
d839a35340
update cartfile too 2018-10-17 06:57:59 -04:00
Erik Little
d5a478f64a
update deps: Fix #1105 2018-10-17 06:56:30 -04:00
Erik Little
e5f3fb13ae
Merge pull request #1097 from cobrowseio/writecompletion
Add optional write completion handler for emit's
2018-10-04 06:56:18 -04:00
Erik Little
0d8890defd
update xcode settings 2018-10-04 06:55:05 -04:00
Erik Little
016e12720d
Merge branch 'development'
* development:
  update changelog and bump pod version
  check for 200 status code when polling #857
  update xcode versino
  set the right URL in websocket creation
  fix cookies import when create the websocket
  Be sure to keep secure config even if config is changed. Fix #1078
  Don't need to write DispatchTime
  use while let instead of while and if let
2018-10-04 05:56:16 -04:00
Erik Little
d25a926226
update changelog and bump pod version 2018-10-04 05:55:44 -04:00
Andy
09fc43349f convert SocketData to serialisable socket representation 2018-10-02 21:08:55 +07:00
Andy
b3e305fd14 Add a variadic method for emit completion handlers in swift 2018-10-02 20:55:38 +07:00
Andy
d763fad449 no need to capture completion hander in wrapper 2018-10-02 19:05:22 +07:00
Erik Little
e877bb26c3
check for 200 status code when polling #857 2018-10-02 07:53:36 -04:00
Andy
28fad62ccd wrap completion handler to run on handleQueue 2018-10-02 13:47:03 +07:00
Andy
f9d8595a25 add optional write completion handler for emit's 2018-09-29 16:29:58 +07:00
Erik Little
3bf28cd427
Merge pull request #1080 from flashbreak/master
fix cookies import when create the websocket
2018-09-27 08:33:13 -04:00
Erik Little
c3032579c0
update xcode versino 2018-09-18 11:00:18 -04:00
Hugo Schouman
867db19bc5 set the right URL in websocket creation 2018-09-05 19:26:35 +02:00
Hugo Schouman
cfa6a217be fix cookies import when create the websocket 2018-09-03 15:51:20 +02:00
Erik Little
520ff72395
Be sure to keep secure config even if config is changed. Fix #1078 2018-08-30 09:14:34 -04:00
Erik Little
25df8b66fc
Don't need to write DispatchTime 2018-08-29 10:25:09 -04:00
Erik Little
d632135289
use while let instead of while and if let 2018-08-28 10:46:52 -04:00
Erik Little
a3d443268a
bump version 2018-07-29 10:34:17 -04:00
Erik Little
d03e319e35
Merge pull request #1059 from socketio/development
v13.3.0
2018-07-29 10:30:14 -04:00
Erik Little
165ec25713
Add isBinary property to SocketPacket.PacketType 2018-07-29 10:23:41 -04:00
Erik Little
35c93ee6f5
Merge branch 'master' into development
* master:
  Update 12to13.md
2018-07-27 08:43:32 -04:00
Erik Little
cc90426d94
Merge pull request #1061 from hawflakes/patch-1
Update 12to13.md
2018-07-27 08:43:13 -04:00
Erik Little
6db5348daa
use AnyObject over class in protocols 2018-07-27 08:42:30 -04:00
Erik Little
9bf073156f
fix tab issue 2018-07-21 10:39:27 -04:00
山楂片
8f50375cf2
Update 12to13.md
remove extra 'the'
2018-07-20 01:19:34 -07:00
Erik Little
451f4c1b69
Merge branch 'master' into development
* master:
  bump version
2018-07-18 12:16:08 -04:00
Erik Little
95aa544275
Merge pull request #1058 from OneSman7/support-cookies-for-web-socket
Added passing cookies from long polling session to web scoket
2018-07-18 10:47:50 -04:00
Erasov Ivan
eab73c81a7 Fixed a typo 2018-07-18 17:01:50 +03:00
Erasov Ivan
cfc01ac9fc Code style fixes 2018-07-18 16:59:34 +03:00
Erasov Ivan
64d2527190 Added passing cookies from long polling session to web scoket 2018-07-18 15:23:10 +03:00
Peter Dupris
b48f1e9af5 expose Starscream WebSocket enableSOCKSProxy option to socket.io-client-swift options 2018-06-27 19:35:52 -07:00
Erik Little
6cfea5aca3
bump version 2018-06-07 09:54:29 -04:00
Erik Little
d06c1e5f5b
Merge branch 'development'
* development:
  update changelog
  update starscream for spm
  Fix tests so they don't rely on comparing strings or the order of hashed collections
  don't bind error when we're not pattern matching
  Clarify comments to explain why we did the move
  Added comments to document changes reasons
  Fixed loosing POST packets on web socket connection failure and engine memory leak on server errors.
  add test for extraHeaders on objc
2018-06-07 09:50:01 -04:00
Erik Little
2cc47b0117
update changelog 2018-06-07 09:49:04 -04:00
Erik Little
884cc6f8f1
update starscream for spm 2018-06-07 09:31:52 -04:00
Erik Little
2629449436
Fix tests so they don't rely on comparing strings or the order of hashed collections 2018-06-07 09:25:34 -04:00
Erik Little
0a7e1f4185
don't bind error when we're not pattern matching 2018-06-07 07:58:11 -04:00
Erik Little
5fdff65281
Clarify comments to explain why we did the move 2018-06-07 07:15:43 -04:00
Erik Little
f7ccf338ad
Merge pull request #1034 from OneSman7/Fix-loosing-packets-on-websocket-connect-failure
Fixed loosing POST packets on web socket connection failure
2018-06-07 06:47:04 -04:00
Erasov Ivan
feb476c76b Added comments to document changes reasons 2018-06-07 13:42:13 +03:00
Erasov Ivan
b258a93750 Fixed loosing POST packets on web socket connection failure and engine memory leak on server errors. 2018-06-07 13:13:44 +03:00
Erik Little
d07441e7fa
add test for extraHeaders on objc 2018-06-05 10:41:39 -04:00
Erik Little
6564d1a0c5
bump version and docs 2018-05-16 18:51:51 -04:00
Erik Little
41af615428
Merge branch 'development'
* development:
  Add note about manager not being thread safe
  Make it clear that `handleQueue` should be serial
  remove some redundant connected checking
  get rid of internal emitAck method
  open engine
  Add raw view to ack emitter
  change access level to public for raw view
  rename SocketBinaryView
  Add rawEmitView. Implements #992
  Add way to skip binary inspection.
  bump version
  Set reconnectAttempts in manager. Fixes #989
2018-05-16 18:48:28 -04:00
Erik Little
4ea1bb9c43
Add note about manager not being thread safe 2018-05-10 07:46:38 -04:00
Erik Little
c3cabe43bf
Make it clear that handleQueue should be serial 2018-05-10 07:29:39 -04:00
Erik Little
6ff403fad1
remove some redundant connected checking 2018-04-02 11:36:20 -04:00
Erik Little
b73afe0da9
get rid of internal emitAck method 2018-04-01 18:48:15 -04:00
Erik Little
be43b0ab3c
open engine 2018-03-31 11:16:58 -04:00
Erik Little
24f3106fe7
Add raw view to ack emitter 2018-03-30 14:56:19 -04:00
Erik Little
1b6144a78c
change access level to public for raw view 2018-03-30 14:39:31 -04:00
Erik Little
948ea5fa00
rename SocketBinaryView 2018-03-30 14:37:15 -04:00
Erik Little
d21a65e117
Add rawEmitView. Implements #992 2018-03-30 14:33:18 -04:00
Erik Little
4564aebec1
Add way to skip binary inspection.
Still a WIP. ACKs still don't have a way to bypass
2018-03-30 14:16:54 -04:00
Erik Little
840892288b
Merge branch 'development'
* development:
  bump version
  Set reconnectAttempts in manager. Fixes #989
2018-03-30 09:51:50 -04:00
Erik Little
47bcfb1299
bump version 2018-03-30 09:51:41 -04:00
Erik Little
d24e8f83c6
Set reconnectAttempts in manager. Fixes #989 2018-03-30 09:40:19 -04:00
Erik Little
731aaf4203
Fix cocoapods choking with .swift-version set to system 2018-03-11 11:26:28 -04:00
Erik Little
746be11f3b
update starscream 2018-03-11 11:21:40 -04:00
Erik Little
5634b33d19
bump version 2018-03-11 11:02:02 -04:00
Erik Little
3a09e7d548
update docs 2018-03-11 11:01:49 -04:00
Erik Little
31aed9e793
Merge branch 'development'
* development:
  update changelog
  Remove MARK: for websockets methods
  Use callbacks instead of delegate methods for Starscream
  Fix exclusive access issue
  Execute acks sync. Implement #950
  Fixes build warnings caused by documentation issues.
  update starscream carthage
2018-03-11 10:57:14 -04:00
Erik Little
4e558833a3
update changelog 2018-03-02 11:38:16 -05:00
Erik Little
07c3678ea9
Remove MARK: for websockets methods 2018-03-02 11:33:46 -05:00
Erik Little
ef02247a0c
Use callbacks instead of delegate methods for Starscream 2018-03-02 11:28:35 -05:00
Erik Little
d811b194eb
Fix exclusive access issue 2018-03-01 10:15:28 -05:00
Erik Little
9b10cab925
Execute acks sync. Implement #950 2018-02-11 17:16:15 -05:00
Erik Little
1e29b2047d
Merge pull request #941 from Sproketti/documentation_fix
Fixes build warnings caused by documentation issues.
2018-02-01 07:20:13 -05:00
Henri Salminen
8df1a12412 Fixes build warnings caused by documentation issues. 2018-01-30 14:28:58 +02:00
Erik Little
d853d8594a
Merge branch 'master' into development
* master:
  update docs
2018-01-10 09:17:52 -05:00
Erik Little
c3a8c411a5
update starscream carthage 2018-01-10 09:17:42 -05:00
Erik Little
d388e1cf03
update docs 2018-01-10 09:10:36 -05:00
Erik Little
ea93e69d5c
Merge branch 'development'
* development:
  fix insert invoked twice
  add , to disconnect
  update changelog
  Fix #923
  update reconnect documentation
  update starscream
  Fix #894
2018-01-10 09:09:11 -05:00
Erik Little
4ec634ccfd
Merge branch 'master' of https://github.com/slidoooor/socket.io-client-swift into development
* 'master' of https://github.com/slidoooor/socket.io-client-swift:
  fix insert invoked twice
2018-01-10 08:11:17 -05:00
slidoooor
fa7fcc8c3b fix insert invoked twice 2018-01-10 13:21:30 +08:00
Erik Little
8eca6249c0
add , to disconnect 2018-01-07 18:23:36 -05:00
Erik Little
3d9b2b2c1c
update changelog 2018-01-07 12:34:53 -05:00
Erik Little
658d5f5b71
Fix #923 2018-01-07 12:24:20 -05:00
Erik Little
9224e2b3e6
update reconnect documentation 2018-01-05 09:25:54 -05:00
Erik Little
c395fa3f0f
update starscream 2017-12-20 07:12:14 -05:00
Erik Little
f74eb8c88a
Fix #894 2017-12-20 07:11:31 -05:00
Erik Little
1025c80ef5
update docs 2017-11-30 06:40:39 -05:00
Erik Little
313032aa41
Merge branch 'development'
* development:
  Fix #882. Don't automatically remove sockets from nsps since they might be used again
  bump version
  Enable bitcode in debug
  Enable bitcode for select sdks
  simplify ranges
  update changelog
  Just use one boolean to determine polling/ws
  use addHeaders
  update changelog
  Implement #684
  Fix some documentation marks
2017-11-30 06:38:56 -05:00
Erik Little
a611aee899
Fix #882. Don't automatically remove sockets from nsps since they might be used again 2017-11-28 08:10:45 -05:00
Erik Little
0dff23d42b
bump version 2017-11-25 11:03:02 -05:00
Erik Little
0a27b2ea10
Enable bitcode in debug 2017-11-23 12:12:52 -05:00
Erik Little
fa60b9a80a
Enable bitcode for select sdks 2017-11-23 11:56:14 -05:00
Erik Little
f0ac68e369
simplify ranges 2017-11-23 11:37:31 -05:00
Erik Little
11bc8e5df2
update changelog 2017-11-18 10:34:31 -05:00
Erik Little
3df5d6d0b4
Just use one boolean to determine polling/ws 2017-11-18 10:19:51 -05:00
Erik Little
ef2228cf29
use addHeaders 2017-11-17 14:11:03 -05:00
Erik Little
a9b5259a08
update changelog 2017-11-14 10:20:26 -05:00
Erik Little
3525caedd1
Implement #684 2017-11-14 10:18:49 -05:00
Erik Little
943e94ed0e
Fix some documentation marks 2017-11-14 08:18:07 -05:00
Erik Little
96ce620f69
update docs 2017-11-14 07:22:17 -05:00
Erik Little
1458a482d0
bump version 2017-11-14 07:21:30 -05:00
Erik Little
fd548121c2
Merge branch 'development'
* development:
  Fix #865
  Change .swift-version
  Fix documentation
2017-11-14 07:19:58 -05:00
Erik Little
05943767e5
Fix #865 2017-11-14 07:16:44 -05:00
Erik Little
2fa0a43e4c
Change .swift-version 2017-11-12 14:38:26 -05:00
Erik Little
fa34cd9be5
Fix documentation 2017-11-12 12:36:11 -05:00
Erik Little
b6a8984ce0
update docs 2017-11-12 11:36:35 -05:00
Erik Little
176986d22a
Merge branch 'development'
* development: (31 commits)
  Add note about namespace methods
  Add note in changelog to checkout the migration guide
  Add more to the migration guide
  don't return optional from defaultSocket
  Add link to 12to13 and style
  Start working on a migration guide
  Fix #855
  refactor SocketIOClient.handlePacket
  bump version
  Do we really need to update carthage?
  Make sure to turn off logging in setup
  Don't use NSDictionary in definitions
  Fix tests
  Fix changelog
  update starscream versions
  nsp should be readonly now
  Add SocketManager for multiplexing namespaces
  Change sentPing/gotPong to ping/pong since those are already reserved
  Fix comment
  Add ability to track ping/pongs
  ...
2017-11-12 11:34:49 -05:00
Erik Little
f2ae32b01d
Add note about namespace methods 2017-11-12 11:32:12 -05:00
Erik Little
c141f7c105
Add note in changelog to checkout the migration guide 2017-11-12 11:25:56 -05:00
Erik Little
5c9dc2cee8
Add more to the migration guide 2017-11-12 11:22:26 -05:00
Erik Little
3595662729
don't return optional from defaultSocket 2017-11-12 10:32:59 -05:00
Erik Little
c98df21747
Add link to 12to13 and style 2017-11-10 09:26:17 -05:00
Erik Little
f0a792bd51
Start working on a migration guide 2017-11-10 09:00:36 -05:00
Erik Little
fa5e815912
Merge branch 'master' into development
* master:
  bump version
  Fix #855
2017-11-08 08:40:06 -05:00
Erik Little
6905113b49
Merge branch 'v12.1.3'
* v12.1.3:
  bump version
  Fix #855
2017-11-08 08:33:33 -05:00
Erik Little
45af5d96d9
bump version 2017-11-08 08:25:57 -05:00
Erik Little
ff0f1c8c77
Fix #855 2017-11-08 08:24:13 -05:00
Erik Little
d251b4de87
Fix #855 2017-11-08 08:17:36 -05:00
Erik Little
5cfc97386a
refactor SocketIOClient.handlePacket 2017-10-25 08:16:44 -04:00
Erik Little
c9e6d3ec33
bump version 2017-10-22 11:07:20 -04:00
Erik Little
5db5260ae8
Do we really need to update carthage? 2017-10-22 10:48:37 -04:00
Erik Little
6e3d97617f
Make sure to turn off logging in setup 2017-10-22 10:44:09 -04:00
Erik Little
cf597ae09d
Don't use NSDictionary in definitions 2017-10-22 10:26:16 -04:00
Erik Little
846e7cb0aa
Fix tests 2017-10-21 18:35:36 -04:00
Erik Little
a255d1131d
Fix changelog 2017-10-21 18:06:47 -04:00
Erik Little
16e85a297c
update starscream versions 2017-10-21 18:04:38 -04:00
Erik Little
535f1700bf
nsp should be readonly now 2017-10-21 18:02:56 -04:00
Erik Little
5a85c97f3d
Merge branch 'manager' into development
* manager:
  Add SocketManager for multiplexing namespaces
2017-10-21 17:28:52 -04:00
Erik Little
5b52edd880
Add SocketManager for multiplexing namespaces 2017-10-21 17:17:29 -04:00
Erik Little
1ed87e571d
Change sentPing/gotPong to ping/pong since those are already reserved 2017-10-14 10:28:14 -04:00
Erik Little
bb1618faaf
Fix comment 2017-10-14 10:17:04 -04:00
Erik Little
c03fc96f04
Add ability to track ping/pongs 2017-10-14 10:15:36 -04:00
Erik Little
7b04309990
remove some code duplication 2017-10-14 09:43:27 -04:00
Erik Little
22fa1d4894
Merge remote-tracking branch 'origin/one-target' into development
* origin/one-target:
  remove some debug prints
  lower watch version
  add watchos to podspec
  target watchos
  Rename header file; add armv7k arch
  fix travis
  make single target
2017-10-11 08:28:39 -04:00
Erik Little
f9360fc94f
Add note about queue type 2017-10-11 08:28:12 -04:00
Erik Little
953bc09bf3
remove some debug prints 2017-10-07 14:13:47 -04:00
Erik Little
c3c2c24254
lower watch version 2017-10-07 13:52:34 -04:00
Erik Little
51a1be19c8
add watchos to podspec 2017-10-07 13:44:49 -04:00
Erik Little
7b9997b111
target watchos 2017-10-07 13:34:27 -04:00
Erik Little
98a8e4f7f8
Rename header file; add armv7k arch 2017-10-07 13:27:24 -04:00
Erik Little
f85877fb72
fix travis 2017-10-07 13:05:54 -04:00
Erik Little
18b1c65c7c
make single target 2017-10-07 12:59:12 -04:00
Erik Little
0d6c7ece04
remove old group 2017-10-07 11:19:54 -04:00
Erik Little
07dc3e4040
bump starscream version 2017-10-07 11:12:47 -04:00
Erik Little
099c379272
update docs 2017-10-05 19:16:53 -04:00
Erik Little
f6d62301e7
bump version 2017-10-05 19:16:25 -04:00
Erik Little
c6bdf43d8d
Merge branch 'development'
* development:
  more test restructuring
  Restructure tests
  Add test for #829
2017-10-05 19:12:30 -04:00
Erik Little
45955aec4a
more test restructuring 2017-10-05 13:11:15 -04:00
Erik Little
2865c72748
Restructure tests 2017-10-05 13:03:45 -04:00
Erik Little
d4624e08bf
Add test for #829 2017-10-05 07:40:45 -04:00
Erik Little
102251b0bb
update docs 2017-10-04 17:34:57 -04:00
Erik Little
40c98d5027
bump version; better spm example 2017-10-04 17:34:09 -04:00
Erik Little
c8a127a8ed
Merge branch 'development'
* development:
  add test for transport open calling connect
  Treat transport open as joining the default namespace
2017-10-04 17:31:43 -04:00
Erik Little
5c0bbde77b
add test for transport open calling connect 2017-10-03 20:06:55 -04:00
Erik Little
cd2454373a
Treat transport open as joining the default namespace 2017-10-03 11:02:22 -04:00
Erik Little
84218d55c3
update docs 2017-10-01 10:53:21 -04:00
Erik Little
665cfef8d3
document SocketPacket.PacketType 2017-10-01 10:52:30 -04:00
Erik Little
43907a4001
Merge branch 'development'
* development: (23 commits)
  only build mac since the other targets aren't used in testing
  add package resolved file
  rename method
  update readme for carthage
  move carthage update to before_install
  Document SSLSecurity class
  update versions; use upstream starscream in podfile dep
  Go back to Starscream 2.1.1
  Fixes Mac build
  Proof of concept
  Remove StarScream
  Fix documentation
  Don't set configs after connect
  Allow changing config after init but before connect. Fixes #680
  Make a bunch of things public. Fixes #803
  More documentation
  bump starscream dev
  update version; again
  work on fixing for latest version
  update starscream
  ...
2017-10-01 10:46:34 -04:00
Erik Little
66d052cee2
only build mac since the other targets aren't used in testing 2017-10-01 10:19:51 -04:00
Erik Little
a2b1a999e5
add package resolved file 2017-10-01 10:10:05 -04:00
Erik Little
5e69272ebc
rename method 2017-10-01 10:08:00 -04:00
Erik Little
185d9708cd
update readme for carthage 2017-10-01 09:58:54 -04:00
Erik Little
6138c535c9
move carthage update to before_install 2017-10-01 09:03:50 -04:00
Erik Little
392e479c59
Document SSLSecurity class 2017-10-01 08:53:42 -04:00
Erik Little
15198fd9c2
update versions; use upstream starscream in podfile dep 2017-10-01 08:46:50 -04:00
Erik Little
3ee3f4f297
Merge branch 'lightsprint09-feature/explicit-dependency-starscream' into development
* lightsprint09-feature/explicit-dependency-starscream:
  Go back to Starscream 2.1.1
  Fixes Mac build
  Proof of concept
  Remove StarScream
2017-10-01 08:36:48 -04:00
Erik Little
fb02d154e1
Go back to Starscream 2.1.1
Add objc

Fix some warnings
2017-10-01 08:36:13 -04:00
Lukas Schmidt
883b0f3ba4
Fixes Mac build 2017-09-30 18:09:03 -04:00
Lukas Schmidt
6bff01a3b5
Proof of concept 2017-09-30 18:09:02 -04:00
Lukas Schmidt
42d96d96fd
Remove StarScream 2017-09-30 18:08:09 -04:00
Erik Little
819735efbf
Fix documentation 2017-09-30 13:48:35 -04:00
Erik Little
28cc8eef19
Don't set configs after connect 2017-09-30 13:32:44 -04:00
Erik Little
321bb186df
Allow changing config after init but before connect. Fixes #680 2017-09-30 13:19:49 -04:00
Erik Little
91eea96308
Make a bunch of things public. Fixes #803 2017-09-30 11:33:39 -04:00
Erik Little
486a89d407
More documentation 2017-09-30 10:24:40 -04:00
Erik Little
5607280836
bump starscream dev 2017-09-29 23:41:55 -04:00
Erik Little
d878f56839
update version; again 2017-09-29 23:21:05 -04:00
Erik Little
ca4261d8ca
work on fixing for latest version 2017-09-29 23:09:36 -04:00
Erik Little
6eafce0082
update starscream 2017-09-29 22:45:55 -04:00
Erik Little
752407fb67
More documentation 2017-09-29 22:09:38 -04:00
Erik Little
4d30b3c951
characters is going to be deprecated 2017-09-25 09:09:23 -04:00
Erik Little
1421da2aab
Merge branch 'master' into development
* master:
  update docs
  bump version
2017-09-24 18:33:45 -04:00
Erik Little
4dcfcc2a84
Fix warnings 2017-09-20 11:19:15 -04:00
Erik Little
8f50c5a3de
update docs 2017-09-20 07:13:51 -04:00
Erik Little
8364815deb
bump version 2017-09-20 07:13:24 -04:00
Erik Little
fc2852d1c1
Merge branch 'development'
* development:
  Fix manifest
  use .upToNextMajor
  see if this fixes spm
  update starscream dev
  start work on fixing spm
  bump tools versions
  Update proj for swift 4
  make build quiet
  Just use xcodebuild for swift4.0 branch
  Build swift4.0 branch
  Update xcodeproj after rebase
  Add missing @objc
  Update for latest xcode beta
  guard creating prefixless data
  Initial Swift4 work
  Rework logging protocol to use autoclosure
  Remove another NS* use
  Don't use NSDictionary
2017-09-20 07:07:58 -04:00
Erik Little
9be3184f2a
Fix manifest 2017-09-20 07:04:45 -04:00
Erik Little
62d59d7762
use .upToNextMajor 2017-09-19 21:56:42 -04:00
Erik Little
bf2beb7431
see if this fixes spm 2017-09-19 21:10:57 -04:00
Erik Little
ce8f1523cf
update starscream dev 2017-09-19 20:50:36 -04:00
Erik Little
32e0fe312b
start work on fixing spm 2017-09-19 20:36:52 -04:00
Erik Little
ad2fb175b3
bump tools versions 2017-09-19 20:15:47 -04:00
Erik Little
04ba1aa1c5
Update proj for swift 4 2017-09-19 20:07:12 -04:00
Erik Little
dc4c25bff5
make build quiet 2017-09-19 20:07:12 -04:00
Erik Little
dc3b1ea8c7
Just use xcodebuild for swift4.0 branch 2017-09-19 20:07:12 -04:00
Erik Little
2ac2f928c4
Build swift4.0 branch 2017-09-19 20:07:12 -04:00
Erik Little
358e44a436
Update xcodeproj after rebase 2017-09-19 20:07:12 -04:00
Erik Little
2f92a69bb0
Add missing @objc 2017-09-19 20:07:12 -04:00
Erik Little
6ca72c5751
Update for latest xcode beta 2017-09-19 20:07:12 -04:00
Erik Little
4b48bdd3e5
guard creating prefixless data 2017-09-19 20:07:12 -04:00
Erik
cd3eb37ac8
Initial Swift4 work 2017-09-19 20:07:12 -04:00
Erik Little
e9296fd65a
Rework logging protocol to use autoclosure 2017-09-19 08:54:17 -04:00
Erik Little
dda4a31149
Remove another NS* use 2017-09-18 08:59:58 -04:00
Erik Little
02d82adf07
Don't use NSDictionary 2017-09-17 11:50:27 -04:00
Erik Little
654d71abed
bump version 2017-09-17 10:24:13 -04:00
Erik Little
5bcb075aa5
update docs 2017-09-17 10:23:55 -04:00
Erik Little
21ea0aff42
Merge branch 'development'
* development:
  don't lose ping precision
  weak in protocols do nothing
  Fix url in faq
  Extract addHeaders to enginespec
  Add faq for namespace usage
  Remove redundant as, change method name
  Make log types static
  Removed Test Coverage from iOS scheme
  Fix queue violation. #792
2017-09-17 10:21:32 -04:00
Erik Little
f6fa5b79ea
don't lose ping precision 2017-09-16 10:41:15 -04:00
Erik Little
d8104f4bf8
weak in protocols do nothing 2017-09-16 10:04:59 -04:00
Erik Little
0516d3555a
Fix url in faq 2017-09-16 09:53:01 -04:00
Erik Little
df8f87cc21
Extract addHeaders to enginespec 2017-09-16 09:21:11 -04:00
Erik Little
3019fd7ea3
Add faq for namespace usage 2017-09-11 12:08:58 -04:00
Erik Little
5470fb6926
Remove redundant as, change method name 2017-09-06 21:08:00 -04:00
Erik Little
3eb7edc37c
Make log types static 2017-09-06 20:38:51 -04:00
Erik Little
eef5fd987d Merge pull request #796 from stevethomp/master
Fix Test Coverage iTunes Connect Submission Error
2017-09-06 19:20:21 -04:00
Steven Thompson
757bfdc867 Removed Test Coverage from iOS scheme 2017-09-05 16:33:09 -07:00
Erik Little
4237ed0d92
Fix queue violation. #792 2017-09-04 11:53:18 -04:00
Erik Little
4929c8488c
update docs 2017-08-31 18:34:49 -04:00
Erik Little
04e90fc905
Merge branch 'development'
* development:
  Bump starscream and remove cocoaseeds from readme
  update module file
  Change starscream branch
  Remove old version language
  correct version is 11.1.1
  Fix SPM and bump version
  Update starscream version in readme
  grammar
  Update comment
  Use errors in parsing method
  Rename directory to SocketIO
  work on podspec
  faq doesn't need to be in the project
  Reorganize files
  Add faqs page
2017-08-31 18:33:44 -04:00
Erik Little
64b56c593e
Bump starscream and remove cocoaseeds from readme 2017-08-29 10:23:15 -04:00
Erik Little
ef84747de2
update module file 2017-08-29 09:17:04 -04:00
Erik Little
56fe22cc58
Change starscream branch 2017-08-29 09:15:38 -04:00
Erik Little
038e1b0881
Remove old version language 2017-08-22 14:30:52 -04:00
Erik Little
ef278b0645
Merge branch 'master' into development
* master:
  Fix source files location
  correct version is 11.1.1
  Fix SPM and bump version
  Update starscream version in readme
2017-08-22 13:47:59 -04:00
Erik Little
3c507d135f
Fix source files location 2017-08-22 11:15:41 -04:00
Erik Little
86155d5714
correct version is 11.1.1 2017-08-22 11:06:20 -04:00
Erik Little
a1399d8c5c
Fix SPM and bump version 2017-08-22 11:06:03 -04:00
Erik Little
323327b0f2
correct version is 11.1.1 2017-08-22 11:03:57 -04:00
Erik Little
710dd3cd7f
Fix SPM and bump version 2017-08-22 11:03:00 -04:00
Erik Little
4f83c466f0
Update starscream version in readme 2017-08-18 18:58:10 -04:00
Erik Little
955382eb8f
Update starscream version in readme 2017-08-18 18:57:56 -04:00
Erik Little
4968e752e6
grammar 2017-08-18 11:59:16 -04:00
Erik Little
c8ff5bac96
Update comment 2017-08-18 11:58:50 -04:00
Erik Little
afbf2cfc40
Use errors in parsing method 2017-08-18 11:04:06 -04:00
Erik Little
079c8e4e4c
Rename directory to SocketIO 2017-08-17 23:10:30 -04:00
Erik Little
8c5f53d868
work on podspec 2017-08-17 23:00:57 -04:00
Erik Little
e6a2605c53
faq doesn't need to be in the project 2017-08-17 22:54:53 -04:00
Erik Little
c1d8158ba5
Reorganize files 2017-08-17 22:53:38 -04:00
Erik Little
6c510ebdb5
Merge branch 'master' into development
* master:
  update faq to reflect init's signature
2017-08-17 13:05:34 -04:00
Erik Little
db81499eb8
update faq to reflect init's signature 2017-08-17 13:05:19 -04:00
Erik Little
b5d459be0d
Merge branch 'master' into development
* master:
  update docs
  Add faqs page
2017-08-17 12:50:48 -04:00
Erik Little
60b7beefa5
update docs 2017-08-17 12:45:49 -04:00
Erik Little
0d14294d79
Add faqs page 2017-08-17 12:43:06 -04:00
Erik Little
818f82aaa5
Add faqs page 2017-08-17 12:38:10 -04:00
Erik Little
54c2b3bd35
update docs 2017-08-17 11:55:14 -04:00
Erik Little
8be2df0f4b
bump version 2017-08-17 11:54:50 -04:00
Erik Little
f34750a5ff
Merge branch 'development'
* development:
  Add once for client events
  Update starscream repo
  Bump starscream dep
  Add off for client events. Fixes #773
2017-08-17 11:48:07 -04:00
Erik Little
5621f0dbe1
Add once for client events 2017-08-17 10:08:51 -04:00
Erik Little
18efea4bad
Update starscream repo 2017-08-17 09:52:16 -04:00
Erik Little
7a16d157f7
Bump starscream dep 2017-08-17 09:34:23 -04:00
Erik Little
6d7ca472a3
Add off for client events. Fixes #773 2017-08-17 09:20:03 -04:00
Erik Little
0e5ffce862
bump version 2017-08-08 06:06:46 -04:00
Erik Little
ec5a8536be
Merge branch 'development'
* development:
  Re-add swift language to podspec
2017-08-08 06:02:51 -04:00
Erik Little
1ed131d925
Re-add swift language to podspec 2017-08-08 06:02:37 -04:00
Erik Little
74c45d5881
update docs 2017-08-06 09:57:47 -04:00
Erik Little
619db00c54
Merge branch 'development'
* development:
  Add test for SSLSecurity; bump starscream
  Bump socket.io dep
  grammar
  Update carthage instructions
2017-08-06 09:57:10 -04:00
Erik Little
6d21dfdade
Merge branch 'v11.0.1' into development
* v11.0.1:
  Add test for SSLSecurity; bump starscream
  Bump socket.io dep
2017-08-06 09:51:51 -04:00
Erik Little
38a1187cb7
Add test for SSLSecurity; bump starscream 2017-08-06 09:49:15 -04:00
Erik Little
2b6b001c0c
Bump socket.io dep 2017-08-06 09:40:52 -04:00
Erik Little
f799cb3a34
grammar 2017-07-25 19:49:28 -04:00
Erik Little
00ea70e3bc
grammar 2017-07-25 19:49:16 -04:00
Erik Little
684b9473d7
Update carthage instructions 2017-07-25 19:48:27 -04:00
Erik Little
319fca0227
Update carthage instructions 2017-07-25 19:48:20 -04:00
Erik Little
245c5a1392 Merge pull request #752 from bingfengzhu/patch-1
update doc
2017-07-25 06:44:48 -04:00
Bing
92792ba71e update doc 2017-07-24 23:55:26 +02:00
Erik Little
817f36e80b
update docs 2017-07-24 07:18:00 -04:00
Erik Little
3ba3354e9a
Merge branch 'development'
* development:
  work on fixing builds
  Update starscream
  Make Starscream a dependency
  Update starscream for new dep; add spm build
  Use ibm commoncrypto
  Tweak some tests
  Remove manual install instructions
2017-07-24 07:14:06 -04:00
Erik
98ac2a8035
work on fixing builds 2017-07-16 10:54:46 -04:00
Erik
72cd9d663e
Update starscream 2017-07-16 10:37:24 -04:00
Erik
9c4a3ba8c4
Merge branch 'v11.0.0' into development
* v11.0.0:
  Make Starscream a dependency
2017-07-16 10:36:13 -04:00
Erik
b3ea49f7fd
Make Starscream a dependency 2017-07-16 10:34:45 -04:00
Erik
967c5e49c2
Remove manual install instructions 2017-07-14 10:52:14 -04:00
Erik
781a9e32ca
Update starscream for new dep; add spm build 2017-07-08 09:40:50 -04:00
Erik
f00af67283
Use ibm commoncrypto 2017-07-08 09:33:43 -04:00
Erik
b62f69a0ca
Tweak some tests 2017-07-06 12:56:02 -04:00
Erik
407b5c644f
Remove manual install instructions 2017-07-06 12:22:28 -04:00
Erik
89b866a611
update docs and bump version 2017-07-04 11:29:13 -04:00
Erik
0013e7fdb6
Merge branch 'development'
* development:
  Make timeOut(after:) Take a double for finer control of timeouts
  increase timeouts for travis
  document connect data item
  Add test for namespace in connect
  Tell users what namespace was connected to
  Clean up SocketPacket methods a bit
  Use guard
2017-07-04 11:26:53 -04:00
Erik
49961eb6cf
Make timeOut(after:) Take a double for finer control of timeouts 2017-07-04 11:08:04 -04:00
Erik
54c54a23b7
increase timeouts for travis 2017-07-04 08:49:18 -04:00
Erik
beaa4b695c
document connect data item 2017-07-04 08:46:07 -04:00
Erik
141b0ce6bc
Add test for namespace in connect 2017-07-04 08:37:18 -04:00
Erik
206e1eed4f
Tell users what namespace was connected to 2017-07-04 08:29:02 -04:00
Erik
1a42580826
Clean up SocketPacket methods a bit 2017-07-04 08:09:20 -04:00
Erik
6b4dfd578f
Use guard 2017-07-02 14:14:15 -04:00
Erik
630ef27436
update docs 2017-07-02 13:56:55 -04:00
Erik
6a8a5dc24a
Merge branch 'development'
* development:
  update readme
  Add compress to NSDictionary to option method
  add note about voip
  Add compress option
  Fix cocoapods
  add missing updates
  Update websocket
2017-07-02 13:55:42 -04:00
Erik
8f22bdef46
update readme 2017-07-02 13:44:58 -04:00
Erik
a2ea2df83a Add compress to NSDictionary to option method 2017-07-02 13:43:01 -04:00
Erik
d37c7123d9 add note about voip 2017-07-02 13:35:52 -04:00
Erik
7ff10d141f Add compress option 2017-07-02 13:28:16 -04:00
Erik
839987727e
Fix cocoapods 2017-07-02 12:33:39 -04:00
Erik
c6dd1fb19b
add missing updates 2017-07-02 11:32:56 -04:00
Erik
d1cbbc0213
Update websocket 2017-07-02 11:31:30 -04:00
Erik Little
d09c2f046b Merge pull request #719 from mathieurobidoux/master
Changed 'timeoutAfter' from Int to Double to allow more precise value
2017-06-25 14:10:57 -04:00
mathieurobidoux
38dea9bb3e Changed 'timeoutAfter' from Int to Double to allow more precise value 2017-06-25 13:13:32 -04:00
Erik
b86e78797e
bump version 2017-06-18 12:51:42 -04:00
Erik
777f6e2406
update docs 2017-06-18 12:51:12 -04:00
Erik
33d7230a5f
Merge branch 'development'
* development:
  remove old test server
  update websocket
  Change Void to ()
  Allow changing the socketURL post init Fixes #470
  code style
  Add note about queue safety
2017-06-18 12:49:06 -04:00
Erik
b71348a074
remove old test server 2017-05-29 09:53:46 -04:00
Erik
db9671e2df
update websocket 2017-05-28 15:41:20 -04:00
Erik
2e7183b8de
Change Void to () 2017-05-28 15:30:39 -04:00
Erik
30e4f59a16
Allow changing the socketURL post init Fixes #470 2017-05-28 15:24:43 -04:00
Erik
17bec21ad1
code style 2017-05-28 12:06:24 -04:00
Erik
d9559e7c59
Add note about queue safety 2017-05-27 12:18:10 -04:00
Erik
77dfd78904
bump version and docs 2017-05-27 12:05:56 -04:00
Erik
033a509541
Merge branch 'development'
* development:
  Update readme to reflect that 10.0+ only support socket.io 2.0+
  Remove more doubleEncode stuff
  Remove doubleEncodeUTF8 from NSDictionary translation
  Fix unicode for socket.io 2.0
  Use guard statements in polling
  More Objective-c tests
  Use Data instead of NSData
  code style
  Make addHeaders inout
2017-05-27 12:01:34 -04:00
Erik
df3d7ae536
Update readme to reflect that 10.0+ only support socket.io 2.0+ 2017-05-27 11:53:35 -04:00
Erik
36cce4f969
Remove more doubleEncode stuff 2017-05-27 11:46:10 -04:00
Erik
4666c24d59
Remove doubleEncodeUTF8 from NSDictionary translation 2017-05-27 11:44:11 -04:00
Erik
468d7b2453
Fix unicode for socket.io 2.0 2017-05-27 11:35:22 -04:00
Erik
6ca554f4ad
Use guard statements in polling 2017-05-20 16:52:24 -04:00
Erik
7cf4d527df
Merge branch 'master' into development
* master:
  Revert "add note about socket.io 2.0 and unicode"
2017-05-20 16:44:52 -04:00
Erik
da5b019b33
Revert "add note about socket.io 2.0 and unicode"
This reverts commit 43d5455e823b5af15a3781c9a2a73ded7c74aac6.
2017-05-20 16:44:33 -04:00
Erik
bb61b70417
Merge branch 'master' into development
* master:
  add note about socket.io 2.0 and unicode
2017-05-20 14:37:09 -04:00
Erik
43d5455e82
add note about socket.io 2.0 and unicode 2017-05-20 14:36:56 -04:00
Erik
e6964b56d0
More Objective-c tests 2017-05-20 09:27:47 -04:00
Erik
88218e097d
Use Data instead of NSData 2017-05-20 08:40:13 -04:00
Erik
46a129072f
code style 2017-05-20 08:37:54 -04:00
Erik Little
4abd2ab671
Make addHeaders inout 2017-05-16 11:18:58 -04:00
Erik Little
87ecee13e6
bump version 2017-05-15 08:30:32 -04:00
Erik Little
f2ab06f732
update docs 2017-05-15 08:21:14 -04:00
Erik Little
62eeba69e8
Merge branch 'development'
* development:
  ack emits should allow custom types
  Report errors in SocketData to users. Resolves #677
  Fixes #676
  fix method name in docs
2017-05-15 08:11:07 -04:00
Erik Little
7d8eb6ffc7
ack emits should allow custom types 2017-05-08 07:50:13 -04:00
Erik
dd2167a09f
Report errors in SocketData to users. Resolves #677 2017-05-07 14:40:39 -04:00
Erik
8e25c6c417
Fixes #676 2017-05-07 14:01:31 -04:00
Erik
8d16a8312d
fix method name in docs 2017-05-07 12:39:54 -04:00
Erik
b6d0a1541a
bump version 2017-05-07 12:18:17 -04:00
Erik
a7c90cdac9
update docs 2017-05-07 11:56:03 -04:00
Erik
74fa4142d6
update docs 2017-05-07 11:44:09 -04:00
Erik
46b63b52b2
Merge branch 'development'
* development: (24 commits)
  Add enum for client events. Resolves #675
  Add client event for status changes. Closes #668
  Remove from manager can be discarded
  Use xctool
  Go back to straight xcodebuild
  Try and fix travis
  Disable logging in tests, use xctool again
  Implement #672
  Document SocketIOClientSwift
  Document SocketAnyEvent
  Move operators inside type
  Document ack types
  Fix #667 Make no ack an enum case
  remove refactor build
  Open client
  Make client single queued
  Make engine single queued
  add ignore for appcode
  Fix #657
  Parsable doesn't have to be a client
  ...
2017-05-07 11:42:54 -04:00
Erik
158bdfb418
Add enum for client events. Resolves #675 2017-05-07 11:32:05 -04:00
Erik
1eb39d650a
Add client event for status changes. Closes #668 2017-05-07 10:52:17 -04:00
Erik
2e492ee9bc
Remove from manager can be discarded 2017-05-07 10:33:19 -04:00
Erik
f10839b832
Use xctool 2017-05-07 10:28:50 -04:00
Erik
77034a46fe
Go back to straight xcodebuild 2017-05-07 10:01:45 -04:00
Erik
1c1eb3d08d
Try and fix travis 2017-05-07 09:58:44 -04:00
Erik
bcce3cdfe7
Disable logging in tests, use xctool again 2017-05-07 09:54:51 -04:00
Erik
af5e934d69
Implement #672 2017-05-06 16:02:04 -04:00
Erik
cc3d7f8b07
Merge branch 'documentation' into development
* documentation:
  Document SocketIOClientSwift
2017-05-06 14:46:22 -04:00
Erik
1ff8e11a1f
Document SocketIOClientSwift
add docs

Start documenting engine

More engine documentation

Document engine

document SocketEngineClient

Document SocketEnginePollable and SocketEnginePacketType

Document SocketEngineWebsocket

Document SocketIOClient

Document SocketIOClientStatus

Document SocketLogger

Document some typealiases

Document SocketIOClientOption

Document SocketIOClientConfiguration
2017-05-06 14:41:50 -04:00
Erik
a8ee018a16
Document SocketAnyEvent 2017-05-05 23:14:48 -04:00
Erik
08c6186fe4
Move operators inside type 2017-05-05 23:10:32 -04:00
Erik
e78200ee34
Document ack types 2017-05-05 23:05:55 -04:00
Erik
23c76417d2
Fix #667 Make no ack an enum case 2017-05-05 22:35:39 -04:00
Erik
58f51d07a2
Merge branch 'refactor-engine' into development
* refactor-engine:
  remove refactor build
  Open client
  Make client single queued
  Make engine single queued
  add ignore for appcode
2017-05-05 22:10:21 -04:00
Erik
9edd322a70
remove refactor build 2017-05-05 22:09:59 -04:00
Erik
abdffb9a4f
Open client 2017-05-05 22:07:14 -04:00
Erik
84dd3078d8
Make client single queued
Shouldn't need to protoct ack generation now that client is single queued
2017-05-05 22:07:12 -04:00
Erik
ed049e888d
Make engine single queued
Fix polling

allow building of refactor branch

remove self reference

Some refactoring
2017-05-05 22:07:12 -04:00
Erik
7e494f4bcb
add ignore for appcode 2017-05-05 22:07:12 -04:00
Erik Little
e1160114f6
Merge branch 'master' into development
* master:
  Fixed headings
2017-05-04 07:56:57 -04:00
Erik
e5eec3e97f
Fix #657 2017-05-03 22:21:33 -04:00
Erik
c87bb409b5
Parsable doesn't have to be a client 2017-05-01 18:45:53 -04:00
Erik
7777c76dae
refactor protocol 2017-05-01 18:44:27 -04:00
Erik Little
34d1e2f251 Merge pull request #658 from philipengberg/patch-1
Fixed headings
2017-04-25 05:03:32 -04:00
Philip Engberg
d668da69fb Fixed headings 2017-04-25 08:14:24 +02:00
Erik Little
1669f2c28f Merge pull request #651 from musicabbage/development
remove engine’s listener before assign new instance
2017-04-14 07:40:34 -04:00
musicabbage
907b1b3ae2 Removed if-statement for review notes
https://github.com/socketio/socket.io-client-swift/pull/651#pullrequestreview-32616528
2017-04-14 14:57:46 +08:00
musicabbage
e29c9043b2 remove engine’s listener before assign new instance 2017-04-13 12:08:38 +08:00
Erik Little
6f3610e578 Merge pull request #643 from hfossli/patch-1
Fix markdown formatting issues in README.md
2017-04-04 05:12:18 -04:00
Håvard Fossli
9a2b59ad78 Update README.md 2017-04-04 11:03:42 +02:00
Erik
1949b1fd48
actually bump version 2017-03-30 18:58:26 -04:00
Erik
6bf970e491
bump version 2017-03-30 18:54:04 -04:00
Erik
23050890e9
Merge branch 'development'
* development:
  Revert "double encoding should be getting fixed, make the default false"
2017-03-30 18:53:11 -04:00
Erik
d3c1d0cd04
Revert "double encoding should be getting fixed, make the default false"
This reverts commit 0fcb7903bb1ad6d1bb19fbf8567a2f63e5c78390.
2017-03-30 18:52:42 -04:00
Erik
3faf183cb2
bump version 2017-03-29 12:22:15 -04:00
Erik
fafd8b5f22
Merge branch 'development'
* development:
  bump websocket
  note that swift2.3 is a tag now
  Bump websocket version, fix some warnings
2017-03-29 12:20:37 -04:00
Erik
373c1a3447
bump websocket 2017-03-29 12:20:28 -04:00
Erik
3d5cf24de4
note that swift2.3 is a tag now 2017-03-28 05:14:39 -04:00
Erik
1f8c8b8f61
note that swift2.3 is a tag now 2017-03-28 05:14:25 -04:00
Erik
9e94ed1cea
Bump websocket version, fix some warnings 2017-03-28 05:10:46 -04:00
Erik
01790af3c5
bump version for xcode 8.3 2017-03-28 05:03:14 -04:00
Erik
551ad7f6af
bump version 2017-03-08 19:56:48 -05:00
Erik
b3fd4203d2
Merge branch 'development'
* development:
  SocketAckManager thread-safe acks removal
  thread-safe ack generation
  bump websocket
  Fix building on xcode8.3
  double encoding should be getting fixed, make the default false
  bump websocket
2017-03-08 19:55:46 -05:00
Erik Little
c462381587 Merge pull request #629 from Sistemium/development
SocketAckManager thread-safe acks removal
2017-03-07 10:17:52 -05:00
Alexander Levin
99faafe723 SocketAckManager thread-safe acks removal 2017-03-06 19:57:19 +02:00
Erik Little
efefecdbe3 Merge pull request #622 from Sistemium/development
thread-safe ack generation
2017-02-23 18:50:36 -05:00
Alexander Levin
fcb2b6bbf6 thread-safe ack generation 2017-02-23 09:32:50 +02:00
Erik
cce88ae3eb
bump websocket 2017-02-12 12:13:21 -05:00
Erik Little
1616a58bd7
Fix building on xcode8.3 2017-01-30 12:13:02 -05:00
Erik
0fcb7903bb
double encoding should be getting fixed, make the default false 2017-01-23 16:48:37 -05:00
Erik
3db37023c7
Merge branch 'master' into development
* master:
  Update SocketEngine.swift
  Update SocketEngine.swift
2017-01-23 16:44:02 -05:00
Erik Little
e38bda7239 Merge pull request #602 from mephi1984/patch-1
Update SocketEngine.swift
2017-01-23 08:47:49 -05:00
Erik
9a05f794f7
bump websocket 2016-12-30 19:49:23 -05:00
Vladislav Khorev
f943f41895 Update SocketEngine.swift
Fix issue #101
Place code in handleOpen, according to suggestion:
https://github.com/socketio/socket.io-client-swift/pull/602#issuecomment-269233001
2016-12-30 19:49:48 +03:00
Vladislav Khorev
494f3fa199 Update SocketEngine.swift
Fix issue #101
https://github.com/socketio/socket.io-client-swift/issues/101
2016-12-26 12:40:14 +03:00
Erik
0bb7fdd2eb
bump version 2016-12-18 20:19:09 -05:00
Erik
650538ad2e
Merge branch 'development'
* development:
  bump ws, fix #598
  remove namespace from socket id
2016-12-18 20:17:51 -05:00
Erik
b1debdf912
bump ws, fix #598 2016-12-18 20:06:12 -05:00
Erik
077de02345
remove namespace from socket id 2016-11-24 08:15:17 -05:00
Erik
163a770abc
bump version 2016-11-11 15:55:48 -05:00
Erik
fc2a8e348c
Merge branch 'development'
* development:
  Fix #562
2016-11-11 15:53:58 -05:00
Erik
56278795ea
Merge branch 'development' of https://github.com/socketio/socket.io-client-swift into development
* 'development' of https://github.com/socketio/socket.io-client-swift:
  SocketAckEmitter.isExpected => .expected
  change isRequired() to isExpected()
  remove semicolon
  Update README.md
  add SocketAckEmitter.isRequired()
  Update README.md
  bump version
  bump websocket version
  fix Use Legacy Swift issue
  bump websocket version
  Update README.md
2016-11-11 15:52:48 -05:00
Erik
a82f27ab8c
Fix #562 2016-11-11 15:52:36 -05:00
Erik Little
2b8476ceca
bump version 2016-10-28 11:53:02 -04:00
Erik Little
5ed4723535
Merge branch 'development'
* development:
  SocketAckEmitter.isExpected => .expected
  change isRequired() to isExpected()
  remove semicolon
  add SocketAckEmitter.isRequired()
  fix Use Legacy Swift issue
2016-10-28 11:51:58 -04:00
Erik Little
b6aaa42337
Merge branch 'master' into development
* master:
  Update README.md
2016-10-28 11:51:46 -04:00
Erik Little
e723604816 Merge pull request #544 from alexsun/patch-1
fix Use Legacy Swift issue
2016-10-28 11:46:46 -04:00
Erik Little
51ee9654da Merge pull request #557 from naderio/master
add SocketAckEmitter.expected to indicate if an ack is expected by server
2016-10-28 11:17:30 -04:00
Nader Toukabri
ea3fca3767 SocketAckEmitter.isExpected => .expected 2016-10-28 15:59:50 +01:00
Nader Toukabri
efad448fab change isRequired() to isExpected() 2016-10-28 15:14:07 +01:00
Nader Toukabri
018c993a9d remove semicolon 2016-10-28 15:09:21 +01:00
Erik Little
863480acf2 Update README.md 2016-10-28 09:43:46 -04:00
Nader Toukabri
ff12285e94 add SocketAckEmitter.isRequired() 2016-10-28 14:23:22 +01:00
Nader Toukabri
51b95f9cee Merge pull request #1 from socketio/master
sync
2016-10-28 12:56:33 +01:00
Erik Little
86181525df Update README.md 2016-10-27 07:14:53 -04:00
Erik Little
85b6dc1766
bump version 2016-10-27 07:02:01 -04:00
Erik Little
bc7ad37e62
Merge branch 'development'
* development:
  bump websocket version
  bump websocket version
  Fix #521
  add options to objective-c test
  add link to spm example
  remove redundant cast
  remove redundant cast
  Redo emitWithAck API since in Swift 3 parameter names aren't apart of the type
2016-10-27 06:38:56 -04:00
Erik Little
8042053331
bump websocket version 2016-10-27 06:37:39 -04:00
Jin Sun
0143dc25bf fix Use Legacy Swift issue 2016-10-18 17:29:01 +08:00
Erik Little
3e3ba60165
bump websocket version 2016-10-12 11:55:44 -04:00
Erik Little
bd5c852fb6 Update README.md 2016-10-05 08:56:22 -04:00
Erik
a32f2d34f0
Fix #521 2016-10-01 10:20:13 -04:00
Erik
fee53e0ccf
add options to objective-c test 2016-09-26 20:39:38 -04:00
Erik
2eb58fb262
add link to spm example 2016-09-25 14:51:54 -04:00
Erik
9ac6af95e3
Merge branch 'master' into development
* master:
  bump version
2016-09-25 13:39:14 -04:00
Erik
b3da89d61c
remove redundant cast 2016-09-25 12:10:29 -04:00
Erik
c91a79fe5b
remove redundant cast 2016-09-25 12:07:55 -04:00
Erik
6771f59ab7
Redo emitWithAck API since in Swift 3 parameter names aren't apart of the type 2016-09-25 11:59:10 -04:00
Erik
2faa2aeb95
bump version 2016-09-20 17:03:41 -04:00
Erik
04011a0a19
Merge branch 'development'
* development:
  fix objective-c
2016-09-20 17:01:41 -04:00
Erik
8ba3518fbc
fix objective-c 2016-09-20 16:57:09 -04:00
Erik
0849a75686
bump version 2016-09-19 19:02:20 -04:00
Erik
b33e73f119
bump websocket 2016-09-19 19:00:52 -04:00
Erik
549df19d4a
Fix adding / to path 2016-09-19 18:52:13 -04:00
Erik
100a9730d2
rename file 2016-09-14 08:09:14 -04:00
Erik
db35decac9
still try and fix cocoapods 2016-09-14 07:59:19 -04:00
Erik
2810e56162
Try and fix cocoapods 2016-09-14 07:54:55 -04:00
Erik
79e22b7d07
bump version 2016-09-14 07:22:27 -04:00
Erik
83ac8c9ac2
Merge branch 'development'
* development:
  We need to raise target version
2016-09-14 07:21:21 -04:00
Erik
d3de97b584
Merge branch 'development' of https://github.com/socketio/socket.io-client-swift into development
* 'development' of https://github.com/socketio/socket.io-client-swift:
  We need to raise target version
2016-09-14 07:21:07 -04:00
Erik
f051962e81
Merge branch 'development'
* development: (54 commits)
  refactor
  refactors
  clean up some things before xcode8 release
  remove testing of test branch
  Use xcodebuild until xctool is updated
  travis supports the gm
  update readme
  Turn off travis until it's updated
  Fix tests
  Fix truncation of binary data, use range operator for clarity
  Update for Xcode 8 GM
  Don't parse twice for errors
  use guarded try
  change spm name
  Modify mac version base mac os 10.9
  open socket manager
  refactor
  Fix swift3 errors that happened during merge
  Switch to using Any instead of AnyObject
  varios tweaks
  ...
2016-09-14 07:16:37 -04:00
Erik
723129b639
refactor 2016-09-14 07:16:22 -04:00
Erik Little
0183006c00
We need to raise target version 2016-09-12 08:10:12 -04:00
Erik
72b6565510
refactors 2016-09-10 10:12:37 -04:00
Erik
31adcd4728
clean up some things before xcode8 release 2016-09-10 09:17:50 -04:00
Erik
fa4346cbc8
remove testing of test branch 2016-09-10 08:27:44 -04:00
Erik
9d0c03be10
Use xcodebuild until xctool is updated 2016-09-10 08:26:10 -04:00
Erik Little
db999a58f2
travis supports the gm 2016-09-08 13:13:24 -04:00
Erik Little
a137686163
update readme 2016-09-08 07:33:17 -04:00
Erik Little
6016129562
Turn off travis until it's updated 2016-09-08 07:31:17 -04:00
Erik Little
a55e9ab3ba
Merge branch 'development' into swift3
* development:
  Don't parse twice for errors
  use guarded try
  change spm name
  Modify mac version base mac os 10.9
2016-09-08 07:30:28 -04:00
Erik Little
c5fd1c71be
Merge branch 'parse-data-subrange' of https://github.com/CFKevinRef/socket.io-client-swift into swift3
* 'parse-data-subrange' of https://github.com/CFKevinRef/socket.io-client-swift:
  Fix truncation of binary data, use range operator for clarity
2016-09-08 07:23:20 -04:00
Erik Little
34ef8a5278
Fix tests 2016-09-08 07:23:00 -04:00
Kevin Cassidy Jr
d808d8f157 Fix truncation of binary data, use range operator for clarity 2016-09-07 20:19:55 -07:00
Erik Little
259b453acb Merge pull request #484 from davbeck/swift3
Xcode 8 GM
2016-09-07 17:47:18 -04:00
David Beck
bc929b7c26 Merge branch 'swift3' of github.com:socketio/socket.io-client-swift into swift3
# Conflicts:
#	Source/SocketTypes.swift
2016-09-07 14:21:10 -07:00
David Beck
ffcf5fbf92 Update for Xcode 8 GM 2016-09-07 14:19:53 -07:00
Erik
16eefa4abf
Don't parse twice for errors 2016-09-02 18:03:15 -04:00
Erik
49dfd7432c
use guarded try 2016-09-02 17:57:26 -04:00
Erik
923103dec8
change spm name 2016-09-02 17:33:12 -04:00
Erik Little
81a82aae64 Merge pull request #479 from KobeStronger/feature/macVersion
Modify mac version base mac os 10.9
2016-09-02 09:06:06 -04:00
Kobe
d3500d38ba Modify mac version base mac os 10.9 2016-09-02 10:46:39 +08:00
Erik
a950656112
open socket manager 2016-08-31 20:45:15 -04:00
Erik
c7d75b6b83
refactor 2016-08-31 19:58:40 -04:00
Erik
f5cf2b8de5
Fix swift3 errors that happened during merge 2016-08-31 18:19:24 -04:00
Erik
bd192b9af5
merge development 2016-08-31 18:13:31 -04:00
Erik
a412eef268
Merge branch 'development'
* development:
  Fix cocoapods name
2016-08-29 05:21:55 -04:00
Erik
7d07e55ce5
Fix cocoapods name 2016-08-29 05:21:45 -04:00
Erik
e8c3e22dc6
Merge branch 'development'
* development:
  fix sid bug
  Fix socketio/socket.io-client-swift#472
2016-08-29 05:10:58 -04:00
Erik
cf12865aa0
fix sid bug 2016-08-29 05:10:03 -04:00
Erik
2200972f4d
Fix socketio/socket.io-client-swift#472 2016-08-28 08:29:00 -04:00
Erik
c7c824c3c5
bump version 2016-08-27 13:08:09 -04:00
Erik
89ab458a5f
Merge branch 'development'
* development:
  Refactor engine. Fix infinite recursion in configuration
  Don't send whole packet to handleConnect
2016-08-27 13:07:26 -04:00
Erik
bd7f94333d
Refactor engine. Fix infinite recursion in configuration 2016-08-27 13:05:22 -04:00
Erik
4de7a48e87
Don't send whole packet to handleConnect 2016-08-27 11:37:13 -04:00
Erik
e3c8cc7fd9
Update readme 2016-08-27 11:15:27 -04:00
Erik
4a9013d986
bump version 2016-08-27 11:10:56 -04:00
Erik
2910355245
Merge branch 'development'
* development:
  update readme
  Renamed modules to make then consistent.
  rename engine init
  tweaks
  Add SocketIOClientConfiguration
  Rename variable
  refactor some reconnect code
  bump websocket version
  move extensions
  refactor out checking for base64
2016-08-27 11:08:30 -04:00
Erik
23eb9a4dae
Merge branch 'davbeck-swift3-any' into swift3
* davbeck-swift3-any:
  Switch to using Any instead of AnyObject
2016-08-24 06:54:57 -04:00
David Beck
59c158119a Merge branch 'swift3' of github.com:socketio/socket.io-client-swift into swift3
# Conflicts:
#	SocketIO-MacTests/SocketBasicPacketTest.swift
#	SocketIO-MacTests/SocketNamespacePacketTest.swift
#	Source/SocketExtensions.swift
#	Source/SocketPacket.swift
#	Source/WebSocket.swift
2016-08-23 10:53:50 -07:00
David Beck
536367392f Switch to using Any instead of AnyObject
In Swift 3 AnyObject is rarely what you want to use. Objective-C API gets imported as Any and while types like Array and Dictionary can be coerced to AnyObject, they prefer Any, which doesn’t require a manual cast.
2016-08-23 10:10:33 -07:00
Erik
f982e756c2
varios tweaks 2016-08-20 17:58:52 -04:00
Erik
29670af4d3
fix crash 2016-08-20 16:16:57 -04:00
Erik
70b870690e
Fix websocket 2016-08-20 15:30:07 -04:00
Erik
1232c34817
narrow down what's causing compiler crashes 2016-08-18 19:34:01 -04:00
Erik
9acae3b154
I'm not convinced this is right 2016-08-18 19:09:26 -04:00
Erik
0233f383bb
Fix tests, this is broken for obvious reasons 2016-08-15 19:24:10 -04:00
Erik
3bf7a09f98
Swift 3 beta6. Doesn't work, something in websocket.swift is segfaulting the compiler 2016-08-15 18:52:25 -04:00
Erik
5e1dc53304
update readme 2016-08-14 23:05:02 -04:00
Erik Little
e567067d44 Merge pull request #455 from drekka/development
Fixing inconsistent module names across iOS & tvOS
2016-08-14 23:03:27 -04:00
Derek Clarkson
518c256cc2 Renamed modules to make then consistent.
Remove base sources from test compiles.
2016-08-15 12:18:02 +10:00
Erik
07f2ca5f16
rename engine init 2016-08-14 11:06:55 -04:00
Erik
d2cb8f2d9a
fix conflict 2016-08-14 10:53:16 -04:00
Erik
b8d6c28ae4
merge development 2016-08-14 10:51:44 -04:00
Erik
c364f6a832
tweaks 2016-08-14 09:58:21 -04:00
Erik
e2bf84f576
Add SocketIOClientConfiguration 2016-08-13 14:55:33 -04:00
Erik
64b9774c83
Move helper method 2016-08-13 13:32:14 -04:00
Erik
ddd7003d89
merge development 2016-08-11 22:08:48 -04:00
Erik
437c983533
Rename variable 2016-08-11 21:26:01 -04:00
Erik
14b4df3836
refactor some reconnect code 2016-08-11 21:11:28 -04:00
Erik
b6cb0b2c7b
bump websocket version 2016-08-08 18:24:42 -04:00
Erik
81dfabbe15
Remove old files 2016-08-08 17:45:10 -04:00
Erik
3ec1b93f8e
move extensions 2016-08-02 20:35:41 -04:00
Erik
ee63c4e386
refactor out checking for base64 2016-08-02 20:14:04 -04:00
Erik
61a20cf27e
update for beta 4 2016-08-02 19:38:08 -04:00
Erik
a5db13c8b5
merge development 2016-07-29 20:06:43 -04:00
Erik
6147cda561
Merge branch 'development'
* development:
  bump version
  add check for bad paths
  Fix socketpollable crashing
  make nonobjc
  More privatisation
  Making publicKeyChainForTrust() private.
  api extensions doesn't seem to fail for me
  update readme
  don't use api extensions only
2016-07-29 19:38:16 -04:00
Erik
fcfb409282
bump version 2016-07-29 19:34:22 -04:00
Erik
d03d77aff8
add check for bad paths 2016-07-28 21:36:37 -04:00
Erik
637e0bb14c
Fix socketpollable crashing 2016-07-27 21:16:48 -04:00
Erik Little
32ba61fb09
Merge branch 'drekka-development' into development
* drekka-development:
  make nonobjc
  More privatisation
  Making publicKeyChainForTrust() private.
  api extensions doesn't seem to fail for me
  update readme
2016-07-27 11:50:55 -04:00
Erik Little
a9aa28ae77
make nonobjc 2016-07-27 11:50:44 -04:00
Derek Clarkson
99adb49736 More privatisation 2016-07-25 14:19:10 +10:00
Derek Clarkson
21d242ba6a Making publicKeyChainForTrust() private.
To Fixing issue when attempting to build for a objective-c project. Exposed API won’t compile so hiding internal method.
2016-07-25 13:41:26 +10:00
Erik
10d24c47ec
api extensions doesn't seem to fail for me 2016-07-24 09:52:44 -04:00
Erik
604c30bf28
Merge branch 'development' of https://github.com/socketio/socket.io-client-swift into development
* 'development' of https://github.com/socketio/socket.io-client-swift:
  don't use api extensions only
  don't try and start server
  change travis config
  remove log for dorequest
2016-07-24 09:50:04 -04:00
Erik
1d56759276
update readme 2016-07-24 09:49:07 -04:00
Erik Little
af77e984ab
don't use api extensions only 2016-07-22 09:13:03 -04:00
Erik Little
1af7bd842e
Revert "travis plz"
This reverts commit 7bd019fb283e3fd015bff85f451304f2eb3f365d.
2016-07-21 11:15:20 -04:00
Erik Little
7bd019fb28
travis plz 2016-07-21 11:15:07 -04:00
Erik Little
bb9ea1849a
Merge branch 'development' into swift3
* development:
  don't try and start server
2016-07-21 10:52:15 -04:00
Erik Little
cc449a49ea
don't try and start server 2016-07-21 10:49:32 -04:00
Erik Little
4c8bfb91eb
use a whitelist 2016-07-21 10:44:51 -04:00
Erik Little
3500211eed
Merge branch 'development' into swift3
* development:
  change travis config
  remove log for dorequest
2016-07-21 10:44:11 -04:00
Erik Little
b65b63a9f0
Merge branch 'master' into development
* master:
  change travis config
2016-07-21 10:42:30 -04:00
Erik Little
87c86f8aeb
change travis config 2016-07-21 10:42:14 -04:00
Erik Little
c9b60445ca
remove log for dorequest 2016-07-21 10:28:20 -04:00
Erik
4ad3a884a6
merge development 2016-07-20 11:39:37 -04:00
Erik
f15a6dc491
bump version 2016-07-20 11:25:45 -04:00
Erik
7fb2193032
fix swiftpm 2016-07-20 11:22:05 -04:00
Erik
8df6eeb85a
Merge branch 'aputinski-swift3' into swift3
* aputinski-swift3:
  update tests, add test for base64
  Fix Xcode 8 Beta 3 issues/warnings
  Use Legacy Swift Language Version
  Enable APPLICATION_EXTENSION_API_ONLY
2016-07-20 11:08:00 -04:00
Erik
4ad5025c77
update tests, add test for base64 2016-07-20 11:07:37 -04:00
Adam Putinski
777fa30c76 Fix Xcode 8 Beta 3 issues/warnings 2016-07-19 23:01:59 -04:00
Adam Putinski
f214de1407 Use Legacy Swift Language Version 2016-07-19 22:37:56 -04:00
Erik Little
e56741b669
rename variable 2016-07-19 15:03:03 -04:00
Adam Putinski
559fbc0286
Enable APPLICATION_EXTENSION_API_ONLY 2016-07-19 09:15:28 -04:00
Erik Little
dcf206b0f1 Merge pull request #422 from aputinski/api-extensions-only
Enable APPLICATION_EXTENSION_API_ONLY
2016-07-19 09:11:30 -04:00
Erik
e961e11487
change another method name 2016-07-16 22:27:50 -04:00
Erik
f140d7979e
change method name 2016-07-16 21:27:18 -04:00
Erik
afa27e4173
get readme ready for swift3 2016-07-16 21:06:22 -04:00
Erik Little
a9ac86ba3d
fix method call 2016-07-15 10:11:05 -04:00
Erik
f3d771641d some swift3 changes 2016-07-14 19:54:09 -04:00
Erik
f6dc11650d merge development 2016-07-14 19:36:48 -04:00
Erik
dce28b2dac fixes 2016-07-14 19:26:56 -04:00
Erik
8345eae28c don't stall queues 2016-07-14 19:25:48 -04:00
Erik
e8219e6b6a merge development 2016-07-14 19:12:03 -04:00
Erik
9cc60ab63d hopefully fix race condition in acks 2016-07-14 18:57:27 -04:00
Adam Putinski
3828211446 Enable APPLICATION_EXTENSION_API_ONLY 2016-07-13 06:34:02 -04:00
Erik
36aa57e89c beta2 2016-07-06 11:47:25 -04:00
Erik
22030e1153 refactors 2016-07-06 11:19:18 -04:00
Erik
73b042b41e Merge branch 'master' into development
* master:
  Update README.md
2016-07-01 17:06:59 -04:00
Erik Little
f52607f722 Update README.md 2016-07-01 17:06:37 -04:00
Erik
f00ed17783 refactors, rename file 2016-07-01 15:42:13 -04:00
Erik
5840d2b61b refactoring 2016-07-01 15:38:53 -04:00
Erik
17d3e659c1 refactor some serialization into methods 2016-07-01 15:36:06 -04:00
Erik
c129118496 merge development 2016-06-24 02:53:31 -04:00
Erik Little
05c0874f32 Merge pull request #408 from socketio/development
Development
2016-06-24 02:41:22 -04:00
Erik
2e5442d386 unknown message isn't fatal 2016-06-24 02:35:18 -04:00
Erik
f9ae0cfdb3 bump version 2016-06-24 02:22:23 -04:00
Erik
7ad90de184 Merge branch 'master' into development
* master:
  bump version
2016-06-24 02:21:54 -04:00
Erik
4383ddfe65 notify client when engine disconnects 2016-06-24 02:21:25 -04:00
Erik
2a0ce72792 small swift 3 changes 2016-06-22 10:04:27 -04:00
Erik
45373ad680 bump version 2016-06-17 10:05:20 -04:00
Erik Little
5ced8a5a9e Merge pull request #399 from socketio/development
Development
2016-06-17 10:03:50 -04:00
Erik
bddc9dc6aa fix logging 2016-06-15 11:00:21 -04:00
Erik
7c3de9f30a even more xcode 8 stuff. style changes 2016-06-15 10:13:44 -04:00
Erik
2adcf2d35d more xcode 8 stuff 2016-06-15 09:32:47 -04:00
Erik
9a4ec5a82a xcode 8 2016-06-14 20:41:59 -04:00
Erik
7500ea83a0 merge development 2016-06-14 19:51:56 -04:00
Erik
6fd3294fba Revert "swift 2.3"
This reverts commit bfa163f3c2e85776d8bcf0c24eca65b7398f403d.
2016-06-14 19:41:18 -04:00
Erik
bfa163f3c2 swift 2.3 2016-06-14 19:37:27 -04:00
Erik
d8826a9db3 allow access from objective-c 2016-06-14 16:19:40 -04:00
Erik
b9e3de2d50 add documentation 2016-06-14 16:13:01 -04:00
Erik
e163598ee6 add option for sslsecurity 2016-06-14 16:11:37 -04:00
Erik
2c059e1a6e log server 2016-06-14 09:38:35 -04:00
Erik
6f21059ff8 work on experimental manager 2016-06-11 12:38:35 -04:00
Erik
523ced2f9a merge development 2016-06-09 09:37:26 -04:00
Erik
58a5a17464 Move websocket to subfolder, don't combine websocket files 2016-06-09 09:28:40 -04:00
Erik
cb0a6f5460 rename method 2016-06-07 13:20:23 -04:00
Erik
b919d3e411 hopefully fix socket.io/socket.io-client-swift#374 2016-06-07 13:12:34 -04:00
Erik
02f30a81dd fix test 2016-06-06 16:25:37 -04:00
Erik
e57bcba47d encoding should already be done at this point 2016-06-06 15:41:19 -04:00
Erik
aae61f3b2e Merge development 2016-06-01 11:17:19 -04:00
Erik
d88bb43d9c some methods have discardableresults 2016-06-01 11:13:05 -04:00
Erik
71f9058723 refactors: refactor creating packet string, various other refactors 2016-05-30 21:42:00 -04:00
Erik
0564ded492 don't check type on each pass through loop 2016-05-25 08:47:50 -04:00
Erik
ff48d3a186 Merge branch 'master' into development
* master:
  Fix crash if error contains formatting strings.
2016-05-25 08:20:03 -04:00
Erik Little
4fa3225cba Merge pull request #372 from ATLCTO/master
Fix crash if error contains formatting strings.
2016-05-25 08:19:28 -04:00
Erik
ee24943c72 remove ios tests folder 2016-05-24 11:26:50 -04:00
Erik Little
31e4c60db8 Merge pull request #373 from socketio/development
Development
2016-05-24 11:18:31 -04:00
Erik
ab536e2279 bump version 2016-05-24 11:08:22 -04:00
Patrick Childers
3d47ff469f Fix crash if error contains formatting strings. 2016-05-23 17:03:51 -04:00
Erik
3b4a3828ba fix for ackemitter 2016-05-22 14:17:01 -04:00
Erik
c6d000972e add test 2016-05-22 14:10:43 -04:00
Erik
51ee4d3d1d try and avoid a bunch of as AnyObject nonsense 2016-05-22 14:05:01 -04:00
Erik
044d9c0746 remove 2016-05-21 12:41:08 -04:00
Erik
593db4cd8d update readme 2016-05-21 11:59:16 -04:00
Erik
f90ad8caeb update for latest swift 2016-05-21 11:45:35 -04:00
Erik
3401414430 bump websocket 2016-05-17 22:35:33 -04:00
Erik
50216647ca refactors 2016-05-11 13:40:45 -04:00
Erik
98063c8bf7 refactoring 2016-05-06 12:48:33 -04:00
Erik
9747cc4ddc allow reconnects after disconnecting 2016-05-06 10:17:43 -04:00
Erik
95cd24a124 remove swiftregex 2016-05-05 13:36:34 -04:00
Erik
6452f6a97a merge dev 2016-05-05 13:33:52 -04:00
Erik
7e23597351 no longer need swiftregex 2016-05-05 13:19:26 -04:00
Erik
437c0880e8 don't use placeholder strings for binary 2016-05-05 13:12:05 -04:00
Erik
e2db1a086d update for latest swift 3 2016-04-16 12:00:21 -04:00
Erik
9f8db42584 Merge branch 'development' into swift3
* development:
  expose ws
  rename file
  change to how server gives id
2016-04-16 11:11:05 -04:00
Erik
376e31bfca merge development and fix tests 2016-04-10 14:15:35 -04:00
Erik
3735dd0e6a Merge branch 'development' into swift3
* development:
  set targetted device family to 3
  use 7.3 image
2016-03-25 17:03:12 -04:00
Erik
199b9962f0 swift3 naming 2016-03-25 13:11:28 -04:00
Erik
4d4362b250 work on swift3 syntax 2016-03-25 12:59:50 -04:00
143 changed files with 36000 additions and 6071 deletions

19
.github/workflows/swift.yml vendored Normal file
View File

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

6
.gitignore vendored
View File

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

View File

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

View File

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

104
CHANGELOG.md Normal file
View File

@ -0,0 +1,104 @@
# 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

1
Cartfile Normal file
View File

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

1
Cartfile.resolved Normal file
View File

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

16
Package.resolved Normal file
View File

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

View File

@ -1,5 +1,17 @@
// swift-tools-version:5.4
import PackageDescription
let package = Package(
name: "SocketIOClientSwift"
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"]),
]
)

184
README.md
View File

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

View File

@ -1,21 +1,31 @@
Pod::Spec.new do |s|
s.name = "Socket.IO-Client-Swift"
s.module_name = "SocketIOClientSwift"
s.version = "6.1.1"
s.module_name = "SocketIO"
s.version = "16.1.1"
s.summary = "Socket.IO-client for iOS and OS X"
s.description = <<-DESC
Socket.IO-client for iOS and OS X.
Supports ws/wss/polling connections and binary.
For socket.io 1.0+ and Swift.
For socket.io 3.0+ and Swift.
DESC
s.homepage = "https://github.com/socketio/socket.io-client-swift"
s.license = { :type => 'MIT' }
s.author = { "Erik" => "nuclear.ace@gmail.com" }
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.tvos.deployment_target = '9.0'
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v6.1.1' }
s.source_files = "Source/**/*.swift"
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.requires_arc = true
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
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"
end

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -1,95 +0,0 @@
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

@ -1,10 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,15 +0,0 @@
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

@ -1,14 +0,0 @@
{
"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

@ -1,13 +0,0 @@
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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,47 +0,0 @@
//
// SocketObjectiveCTest.m
// Socket.IO-Client-Swift
//
// Created by Erik Little on 3/25/16.
//
// Merely tests whether the Objective-C api breaks
//
#import <XCTest/XCTest.h>
@import SocketIOClientSwift;
@interface SocketObjectiveCTest : XCTestCase
@property SocketIOClient* socket;
@end
@implementation SocketObjectiveCTest
- (void)setUp {
[super setUp];
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
self.socket = [[SocketIOClient alloc] initWithSocketURL:url options:nil];
}
- (void)testOnSyntax {
[self.socket on:@"someCallback" callback:^(NSArray* data, SocketAckEmitter* ack) {
[ack with:@[@1]];
}];
}
- (void)testEmitSyntax {
[self.socket emit:@"testEmit" withItems:@[@YES]];
}
- (void)testEmitWithAckSyntax {
[self.socket emitWithAck:@"testAckEmit" withItems:@[@YES]](0, ^(NSArray* data) {
});
}
- (void)testOffSyntax {
[self.socket off:@"test"];
}
@end

View File

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

View File

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

View File

@ -1,19 +0,0 @@
//
// 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

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

View File

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

View File

@ -1,31 +0,0 @@
//
// NSCharacterSet.swift
// Socket.IO-Client-Swift
//
// Created by Yannick Loriot on 5/4/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
extension NSCharacterSet {
class var allowedURLCharacterSet: NSCharacterSet {
return NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
}
}

View File

@ -1,47 +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 Foundation
public final class SocketAckEmitter : NSObject {
let socket: SocketIOClient
let ackNum: Int
init(socket: SocketIOClient, ackNum: Int) {
self.socket = socket
self.ackNum = ackNum
}
public func with(items: AnyObject...) {
guard ackNum != -1 else { return }
socket.emitAck(ackNum, withItems: items)
}
public func with(items: [AnyObject]) {
guard ackNum != -1 else { return }
socket.emitAck(ackNum, withItems: items)
}
}

View File

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

View File

@ -1,34 +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
@objc public protocol SocketEngineClient {
func engineDidError(reason: String)
func engineDidClose(reason: String)
optional func engineDidOpen(reason: String)
func parseEngineMessage(msg: String)
func parseEngineBinaryData(data: NSData)
}

View File

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

View File

@ -1,115 +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
@objc public protocol SocketEngineSpec {
weak var client: SocketEngineClient? { get set }
var closed: Bool { get }
var connected: Bool { get }
var connectParams: [String: AnyObject]? { get set }
var doubleEncodeUTF8: Bool { get }
var cookies: [NSHTTPCookie]? { get }
var extraHeaders: [String: String]? { get }
var fastUpgrade: Bool { get }
var forcePolling: Bool { get }
var forceWebsockets: Bool { get }
var parseQueue: dispatch_queue_t! { get }
var polling: Bool { get }
var probing: Bool { get }
var emitQueue: dispatch_queue_t! { get }
var handleQueue: dispatch_queue_t! { get }
var sid: String { get }
var socketPath: String { get }
var urlPolling: NSURL { get }
var urlWebSocket: NSURL { get }
var websocket: Bool { get }
var ws: WebSocket? { get }
init(client: SocketEngineClient, url: NSURL, options: NSDictionary?)
func connect()
func didError(error: String)
func disconnect(reason: String)
func doFastUpgrade()
func flushWaitingForPostToWebSocket()
func parseEngineData(data: NSData)
func parseEngineMessage(message: String, fromPolling: Bool)
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
}
extension SocketEngineSpec {
var urlPollingWithSid: NSURL {
let com = NSURLComponents(URL: urlPolling, resolvingAgainstBaseURL: false)!
com.percentEncodedQuery = com.percentEncodedQuery! + "&sid=\(sid.urlEncode()!)"
return com.URL!
}
var urlWebSocketWithSid: NSURL {
let com = NSURLComponents(URL: urlWebSocket, resolvingAgainstBaseURL: false)!
com.percentEncodedQuery = com.percentEncodedQuery! + (sid == "" ? "" : "&sid=\(sid.urlEncode()!)")
return com.URL!
}
func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
if websocket {
var byteArray = [UInt8](count: 1, repeatedValue: 0x4)
let mutData = NSMutableData(bytes: &byteArray, length: 1)
mutData.appendData(data)
return .Left(mutData)
} else {
let str = "b4" + data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return .Right(str)
}
}
func doubleEncodeUTF8(string: String) -> String {
if let latin1 = string.dataUsingEncoding(NSUTF8StringEncoding),
utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding) {
return utf8 as String
} else {
return string
}
}
func fixDoubleUTF8(string: String) -> String {
if let utf8 = string.dataUsingEncoding(NSISOLatin1StringEncoding),
latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding) {
return latin1 as String
} else {
return string
}
}
/// Send an engine message (4)
func send(msg: String, withData datas: [NSData]) {
write(msg, withType: .Message, withData: datas)
}
}

View File

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

View File

@ -0,0 +1,146 @@
//
// 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

@ -22,53 +22,67 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Dispatch
import Foundation
private struct SocketAck : Hashable, Equatable {
/// 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 {
let ack: Int
var callback: AckCallback!
var hashValue: Int {
return ack.hashValue
}
init(ack: Int) {
self.ack = ack
}
init(ack: Int, callback: AckCallback) {
init(ack: Int, callback: @escaping 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
}
}
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 {
class SocketAckManager {
private var acks = Set<SocketAck>(minimumCapacity: 1)
mutating func addAck(ack: Int, callback: AckCallback) {
func addAck(_ ack: Int, callback: @escaping AckCallback) {
acks.insert(SocketAck(ack: ack, callback: callback))
}
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 executeAck(_ ack: Int, with items: [Any]) {
acks.remove(SocketAck(ack: ack))?.callback(items)
}
mutating func timeoutAck(ack: Int) {
let callback = acks.remove(SocketAck(ack: ack))
dispatch_async(dispatch_get_main_queue()) {
callback?.callback(["NO ACK"])
}
/// Should be called on handle queue
func timeoutAck(_ ack: Int) {
acks.remove(SocketAck(ack: ack))?.callback?([SocketAckStatus.noAck.rawValue])
}
}

View File

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

View File

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

View File

@ -0,0 +1,549 @@
//
// 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

@ -0,0 +1,138 @@
//
// 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

@ -0,0 +1,241 @@
//
// 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

@ -0,0 +1,392 @@
//
// 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,5 +1,5 @@
//
// SocketIOClientStatus.swift
// SocketIOStatus.swift
// Socket.IO-Client-Swift
//
// Created by Erik Little on 8/14/15.
@ -24,9 +24,36 @@
import Foundation
/// **NotConnected**: initial state
///
/// **Disconnected**: connected before
@objc public enum SocketIOClientStatus : Int {
case NotConnected, Disconnected, Connecting, Connected
/// 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
}
public var description: String {
switch self {
case .connected: return "connected"
case .connecting: return "connecting"
case .disconnected: return "disconnected"
case .notConnected: return "notConnected"
}
}
}

View File

@ -0,0 +1,163 @@
//
// 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

@ -0,0 +1,778 @@
//
// 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

@ -0,0 +1,73 @@
//
// 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

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

View File

@ -0,0 +1,262 @@
//
// 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

@ -0,0 +1,209 @@
//
// 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

@ -0,0 +1,87 @@
//
// 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

@ -0,0 +1,613 @@
//
// 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

@ -0,0 +1,148 @@
//
// 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

@ -0,0 +1,250 @@
//
// 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

@ -0,0 +1,181 @@
//
// 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

@ -0,0 +1,132 @@
//
// 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

@ -24,33 +24,47 @@
import Foundation
public protocol SocketLogger : class {
/// 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
func log(message: String, type: String, args: AnyObject...)
///
/// - 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
func error(message: String, type: String, args: AnyObject...)
///
/// - 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 {
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]) {
/// Default implementation.
func log(_ message: @autoclosure () -> String, type: String) {
guard log else { return }
let newArgs = args.map({arg -> CVarArgType in String(arg)})
let replaced = String(format: message, arguments: newArgs)
NSLog("%@ %@: %@", logType, type, replaced)
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())
}
}

View File

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

View File

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

View File

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

View File

@ -1,43 +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.
protocol SocketIOClientSpec : class {
var nsp: String { get set }
var waitingPackets: [SocketPacket] { get set }
func didConnect()
func didDisconnect(reason: String)
func didError(reason: String)
func handleAck(ack: Int, data: [AnyObject])
func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
func joinNamespace(namespace: String)
}
extension SocketIOClientSpec {
func didError(reason: String) {
DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason)
handleEvent("error", data: [reason], isInternalMessage: true, withAck: -1)
}
}

View File

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

View File

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

View File

@ -1,34 +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
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

@ -1,31 +0,0 @@
//
// String.swift
// Socket.IO-Client-Swift
//
// Created by Yannick Loriot on 5/4/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
extension String {
func urlEncode() -> String? {
return stringByAddingPercentEncodingWithAllowedCharacters(.allowedURLCharacterSet)
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
//
// 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

@ -0,0 +1,215 @@
//
// 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

@ -0,0 +1,229 @@
//
// 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

@ -0,0 +1,46 @@
//
// 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

@ -0,0 +1,247 @@
//
// 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

@ -0,0 +1,206 @@
//
// 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

@ -7,27 +7,9 @@
//
import XCTest
@testable import SocketIOClientSwift
@testable import SocketIO
class SocketParserTest: XCTestCase {
let testSocket = SocketIOClient(socketURL: NSURL())
//Format key: message; namespace-data-binary-id
static let packetTypes: Dictionary<String, (String, [AnyObject], [NSData], Int)> = [
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
"25[\"test\"]": ("/", ["test"], [], 5),
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
"2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"]], [], -1),
"51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], -1),
"3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"]], [], 0),
"61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", [ [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], 19),
"4/swift,": ("/swift", [], [], -1),
"0/swift": ("/swift", [], [], -1),
"1/swift": ("/swift", [], [], -1),
"4\"ERROR\"": ("/", ["ERROR"], [], -1),
"4{\"test\":2}": ("/", [["test": 2]], [], -1),
"41": ("/", [1], [], -1)]
func testDisconnect() {
let message = "1"
validateParseResult(message)
@ -37,106 +19,129 @@ class SocketParserTest: XCTestCase {
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"
switch testSocket.parseString(message) {
case .Left(_):
return
case .Right(_):
XCTFail("Created packet when shouldn't have")
do {
let _ = try testManager.parseString(message)
XCTFail()
} catch {
}
}
func testGenericParser() {
var parser = SocketStringReader(message: "61-/swift,")
XCTAssertEqual(parser.read(1), "6")
XCTAssertEqual(parser.read(count: 1), "6")
XCTAssertEqual(parser.currentCharacter, "1")
XCTAssertEqual(parser.readUntilStringOccurence("-"), "1")
XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1")
XCTAssertEqual(parser.currentCharacter, "/")
}
func validateParseResult(message: String) {
func validateParseResult(_ message: String) {
let validValues = SocketParserTest.packetTypes[message]!
let packet = testSocket.parseString(message)
let type = message.substringWithRange(Range<String.Index>(message.startIndex..<message.startIndex.advancedBy(1)))
if case let .Right(packet) = packet {
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
XCTAssertEqual(packet.nsp, validValues.0)
XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1))
XCTAssertTrue((packet.binary as NSArray).isEqualToArray(validValues.2))
XCTAssertEqual(packet.id, validValues.3)
} else {
XCTFail()
}
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)
measureBlock({
for item in keys.enumerate() {
self.testSocket.parseString(item.element)
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

@ -0,0 +1,507 @@
//
// 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

@ -0,0 +1,13 @@
//
// 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)
}
}

109
Usage Docs/12to13.md Normal file
View File

@ -0,0 +1,109 @@
# 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.

35
Usage Docs/15to16.md Normal file
View File

@ -0,0 +1,35 @@
# 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

@ -0,0 +1,61 @@
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

44
Usage Docs/FAQ.md Normal file
View File

@ -0,0 +1,44 @@
## 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)
}
}
}
```

335
docs/12to13.html Normal file
View File

@ -0,0 +1,335 @@
<!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>

255
docs/15to16.html Normal file
View File

@ -0,0 +1,255 @@
<!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>

526
docs/Classes.html Normal file
View File

@ -0,0 +1,526 @@
<!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

@ -0,0 +1,337 @@
<!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

@ -0,0 +1,436 @@
<!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

@ -0,0 +1,518 @@
<!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

@ -0,0 +1,354 @@
<!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

@ -0,0 +1,472 @@
<!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

@ -0,0 +1,362 @@
<!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

@ -0,0 +1,532 @@
<!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>

453
docs/Enums.html Normal file
View File

@ -0,0 +1,453 @@
<!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>

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