├── .gitignore
├── .swift-version
├── ACKNOWLEDGEMENTS.md
├── LICENSE.md
├── Podfile
├── Podfile.lock
├── README.md
├── SignalR-Swift-Example
├── Podfile
├── Podfile.lock
├── SignalR-Swift-Example.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── jordan_camara.xcuserdatad
│ │ └── xcschemes
│ │ ├── SignalR-Swift-Example.xcscheme
│ │ └── xcschememanagement.plist
├── SignalR-Swift-Example.xcworkspace
│ └── contents.xcworkspacedata
├── SignalR-Swift-Example
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── ViewController.swift
└── SignalR-Swift-ExampleTests
│ ├── Info.plist
│ └── SignalR_Swift_ExampleTests.swift
├── SignalR-Swift.xcodeproj
├── project.pbxproj
└── xcuserdata
│ └── jordan_camara.xcuserdatad
│ └── xcschemes
│ ├── SignalR-Swift.xcscheme
│ └── xcschememanagement.plist
├── SignalR-Swift.xcworkspace
└── contents.xcworkspacedata
├── SignalR-Swift
├── Client
│ ├── Connection.swift
│ ├── Enums
│ │ └── ConnectionState.swift
│ ├── HeartbeatMonitor.swift
│ ├── Hubs
│ │ ├── HubConnection.swift
│ │ ├── HubInvocation.swift
│ │ ├── HubProxy.swift
│ │ └── HubResult.swift
│ ├── Infrastructure
│ │ ├── ExceptionHelper.swift
│ │ └── Version.swift
│ ├── KeepAliveData.swift
│ ├── NegotiationResponse.swift
│ └── Protocols
│ │ ├── ClientTransportProtocol.swift
│ │ ├── ConnectionDelegate.swift
│ │ ├── ConnectionProtocol.swift
│ │ ├── HubConnectionProtocol.swift
│ │ └── HubProxyProtocol.swift
├── Extensions
│ ├── Dictionary+Json.swift
│ └── String+Dictionary.swift
├── Info.plist
├── Models
│ └── ReceivedMessage.swift
├── SignalR-Swift.h
└── Transports
│ ├── AutoTransport.swift
│ ├── HttpTransport.swift
│ ├── LongPollingTransport.swift
│ ├── ServerSentEvents
│ ├── ChunkBuffer.swift
│ └── ServerSentEvent.swift
│ ├── ServerSentEventsTransport.swift
│ ├── WebSocketTransport.swift
│ └── WebSockets
│ └── WebSocketConnectionInfo.swift
├── SignalR-SwiftTests
├── Connection
│ └── ConnectionTests.swift
├── Info.plist
└── Mocks
│ └── MockClientTransport.swift
└── SignalRSwift.podspec
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 | .idea/modules.xml
69 | .idea/SignalR-Swift.iml
70 | .idea/vcs.xml
71 | .idea/workspace.xml
72 | .idea/xcode.xml
73 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/ACKNOWLEDGEMENTS.md:
--------------------------------------------------------------------------------
1 | ### Includes AlamoFire by the Alamofire Software Foundation.
2 |
3 | Copyright (c) 2014-2016 Alamofire Software Foundation (http://alamofire.org/)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
23 | ### Includes SwiftWebSocket by tidwall.
24 |
25 | Permission is hereby granted, free of charge, to any person obtaining a copy
26 | of this software and associated documentation files (the "Software"), to deal
27 | in the Software without restriction, including without limitation the rights
28 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 | copies of the Software, and to permit persons to whom the Software is
30 | furnished to do so, subject to the following conditions:
31 |
32 | The above copyright notice and this permission notice shall be included in
33 | all copies or substantial portions of the Software.
34 |
35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 | THE SOFTWARE.
42 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Autosoft
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '10.3'
3 |
4 | target 'SignalRSwift' do
5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for SignalR-Swift
9 | pod 'Alamofire', '~> 4.2'
10 | pod 'Starscream', '~> 3.0'
11 |
12 | target 'SignalR-SwiftTests' do
13 | inherit! :search_paths
14 | # Pods for testing
15 | pod 'Quick'
16 | pod 'Nimble'
17 | pod 'Mockit', '~> 1.3'
18 | end
19 |
20 | end
21 |
22 | post_install do |installer|
23 | installer.pods_project.targets.each do |target|
24 | if target.name == 'Mockit'
25 | target.build_configurations.each do |config|
26 | config.build_settings['SWIFT_VERSION'] = '3.2'
27 | end
28 | end
29 | end
30 | end
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (4.6.0)
3 | - Mockit (1.3.4)
4 | - Nimble (7.0.3)
5 | - Quick (1.2.0)
6 | - Starscream (3.0.3)
7 |
8 | DEPENDENCIES:
9 | - Alamofire (~> 4.2)
10 | - Mockit (~> 1.3)
11 | - Nimble
12 | - Quick
13 | - Starscream (~> 3.0)
14 |
15 | SPEC CHECKSUMS:
16 | Alamofire: f41a599bd63041760b26d393ec1069d9d7b917f4
17 | Mockit: 1b253f229dde898b268f8bd5dffcf2fd0151ff75
18 | Nimble: 7f5a9c447a33002645a071bddafbfb24ea70e0ac
19 | Quick: 58d203b1c5e27fff7229c4c1ae445ad7069a7a08
20 | Starscream: dfb1b3f39506717ee52b67fb48de0c8269504cbc
21 |
22 | PODFILE CHECKSUM: 79d0be02a68490c1ac445f39448ee90e8f37cad7
23 |
24 | COCOAPODS: 1.3.1
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | SignalR-Swift is a client library for iOS based on https://github.com/DyKnow/SignalR-ObjC by DyKnow. It's built on top of [AlamoFire](https://github.com/Alamofire/Alamofire) and [Starscream](https://github.com/daltoniam/Starscream).
3 | SignalR-Swift is intended to be used along side ASP.NET SignalR, a new library for ASP.NET developers that makes it incredibly simple to add real-time functionality to your applications. What is "real-time web" functionality? It's the ability to have your server-side code push content to the connected clients as it happens, in real-time.
4 |
5 | ## Installation
6 |
7 | ### Installation with CocoaPods
8 |
9 | [CocoaPods](https://cocoapods.org/) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like SignalR-Swift in your projects. See the ["Getting Started" guide for more information](https://guides.cocoapods.org/using/getting-started.html). You can install it with the following command:
10 |
11 | ```
12 | $ gem install cocoapods
13 | ```
14 |
15 | #### Podfile
16 |
17 | To integrate SignalR-Swift into your Xcode project using CocoaPods, specify it in your Podfile:
18 |
19 | ```
20 | source 'https://github.com/CocoaPods/Specs.git'
21 | platform :ios, '8.0'
22 |
23 | pod 'SignalRSwift', '~> 2.0.2'
24 | ```
25 |
26 | Then, run the following command:
27 |
28 | ```
29 | $ pod install
30 | ```
31 |
32 | ## Example Usage
33 | ### Persistent Connection
34 | ```c#
35 | using System.Threading.Tasks;
36 | using Microsoft.AspNet.SignalR;
37 |
38 | //Server
39 | public class MyConnection : PersistentConnection
40 | {
41 | protected override Task OnReceived(IRequest request, string connectionId, string data)
42 | {
43 | // Broadcast data to all clients
44 | return Connection.Broadcast(data);
45 | }
46 | }
47 | ```
48 |
49 | ```swift
50 | import SignalRSwift
51 |
52 | //Client
53 | var connection = Connection(withUrl: "http://localhost/endpoint/");
54 |
55 | // register for connection lifecycle events
56 | connection.started = {
57 | print("Connected")
58 | }
59 |
60 | connection.reconnecting = {
61 | print("Reconnecting...")
62 | }
63 |
64 | connection.reconnected = {
65 | print("Reconnected.")
66 | }
67 |
68 | connection.closed = {
69 | print("Disconnected")
70 | }
71 |
72 | connection.connectionSlow = { print("Connection slow...") }
73 |
74 | connection.error = { error in
75 | print("Error")
76 | }
77 |
78 | connection.start()
79 |
80 | ```
81 | ### Hubs
82 | ```c#
83 | //Server
84 | public class Chat : Hub
85 | {
86 | public void Send(string message)
87 | {
88 | // Call the addMessage method on all clients
89 | Clients.All.addMessage(message);
90 | }
91 | }
92 | ```
93 |
94 | ```Swift
95 | //Client
96 | import SignalRSwift
97 |
98 | // Connect to the service
99 | var hubConnection = HubConnection(withUrl: "http://localhost/endpoint")
100 |
101 | var chat = hubConnection.createHubProxy(hubName: "chat")
102 |
103 | chat.on(eventName: "addMessage") { (args) in
104 | if let message = args[0] {
105 | print("Message: \(message)")
106 | }
107 | }
108 |
109 | // register for connection lifecycle events
110 | hubConnection.started = {
111 | print("Connected")
112 | }
113 |
114 | hubConnection.reconnecting = {
115 | print("Reconnecting...")
116 | }
117 |
118 | hubConnection.reconnected = {
119 | print("Reconnected.")
120 | }
121 |
122 | hubConnection.closed = {
123 | print("Disconnected")
124 | }
125 |
126 | hubConnection.connectionSlow = { print("Connection slow...") }
127 |
128 | hubConnection.error = { error in
129 | print("Error")
130 | }
131 |
132 | hubConnection.start()
133 | ```
134 |
135 | ### Customizing Query Params
136 |
137 | #### Persistent Connections
138 | ```Swift
139 | let qs = [
140 | "param1": "1",
141 | "param2": "another"
142 | }
143 | var connection = Connection(withUrl: "http://localhost/endpoint", queryString: qs)
144 | ```
145 |
146 | #### Hub Connections
147 | ```Swift
148 | let qs = [
149 | "param1": "1",
150 | "param2": "another"
151 | }
152 | var hubConnection = HubConnection(withUrl: "http://localhost/endpoint", queryString: qs)
153 | ```
154 |
155 | ### Customizing Request Headers
156 |
157 | #### Persistent Connections
158 | ```Swift
159 | let headers = [
160 | "param1": "1",
161 | "param2": "another"
162 | ]
163 | var connection = Connection(withUrl: "http://localhost/endpoint", queryString: qs)
164 | connection.headers = headers
165 |
166 | // alternative usage
167 | var connection = Connection(withUrl: "http://localhost/endpoint", queryString: qs)
168 | connection.addValue(value: "1", forHttpHeaderField: "param1")
169 | connection.addValue(value: "another", forHttpHeaderField: "param2")
170 | ```
171 |
172 | #### Hub Connections
173 | ```Swift
174 | let headers = [
175 | "param1": "1",
176 | "param2": "another"
177 | }
178 | var hubConnection = HubConnection(withUrl: "http://localhost/endpoint", queryString: qs)
179 | hubConnection.headers = headers
180 |
181 | // alternative usage
182 | var hubConnection = HubConnection(withUrl: "http://localhost/endpoint", queryString: qs)
183 | hubConnection.addValue(value: "1", forHttpHeaderField: "param1")
184 | hubConnection.addValue(value: "another", forHttpHeaderField: "param2")
185 | ```
186 |
187 | ### Networking
188 |
189 | - SignalR-Swift uses [Alamofire](https://github.com/Alamofire/Alamofire). The minimum supported version of AlamoFire is 4.2.x
190 | - SignalR-Swift uses [Starscream](https://github.com/daltoniam/Starscream).
191 |
192 |
193 | ## LICENSE
194 |
195 | SignalR-Swift is available under the MIT license. See the [LICENSE](https://github.com/AutosoftDMS/SignalR-Swift/blob/master/LICENSE.md) file for more info.
196 | SignalR-Swift uses 3rd-party code which each have specific licenses, see [ACKNOWLEDGEMENTS](https://github.com/AutosoftDMS/SignalR-Swift/blob/master/ACKNOWLEDGEMENTS.md) for contributions
197 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '10.3'
3 |
4 | target 'SignalR-Swift-Example' do
5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for SignalR-Swift-Example
9 | pod 'SignalRSwift', :path => '../'
10 |
11 | target 'SignalR-Swift-ExampleTests' do
12 | inherit! :search_paths
13 | # Pods for testing
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (4.6.0)
3 | - SignalRSwift (2.0.1):
4 | - Alamofire (~> 4.2)
5 | - Starscream (~> 3.0)
6 | - Starscream (3.0.3)
7 |
8 | DEPENDENCIES:
9 | - SignalRSwift (from `../`)
10 |
11 | EXTERNAL SOURCES:
12 | SignalRSwift:
13 | :path: ../
14 |
15 | SPEC CHECKSUMS:
16 | Alamofire: f41a599bd63041760b26d393ec1069d9d7b917f4
17 | SignalRSwift: 92b0536d81f0dea4bb3f941adea7422dc26886e8
18 | Starscream: dfb1b3f39506717ee52b67fb48de0c8269504cbc
19 |
20 | PODFILE CHECKSUM: 0b670b9c4ac8d7df99f98ba1a30595cebc4466a9
21 |
22 | COCOAPODS: 1.3.1
23 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 715553CCD279348CB60CA3CA /* Pods_SignalR_Swift_ExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB5250B3C095B54B6A8372E7 /* Pods_SignalR_Swift_ExampleTests.framework */; };
11 | C9E64D701E27DC3300DEDC20 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E64D6F1E27DC3300DEDC20 /* AppDelegate.swift */; };
12 | C9E64D721E27DC3300DEDC20 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E64D711E27DC3300DEDC20 /* ViewController.swift */; };
13 | C9E64D771E27DC3300DEDC20 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9E64D761E27DC3300DEDC20 /* Assets.xcassets */; };
14 | C9E64D7A1E27DC3300DEDC20 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9E64D781E27DC3300DEDC20 /* LaunchScreen.storyboard */; };
15 | C9E64D851E27DC3400DEDC20 /* SignalR_Swift_ExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E64D841E27DC3400DEDC20 /* SignalR_Swift_ExampleTests.swift */; };
16 | C9E64D911E27E47800DEDC20 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C9E64D8F1E27E47800DEDC20 /* Main.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXContainerItemProxy section */
20 | C9E64D811E27DC3400DEDC20 /* PBXContainerItemProxy */ = {
21 | isa = PBXContainerItemProxy;
22 | containerPortal = C9E64D641E27DC3300DEDC20 /* Project object */;
23 | proxyType = 1;
24 | remoteGlobalIDString = C9E64D6B1E27DC3300DEDC20;
25 | remoteInfo = "SignalR-Swift-Example";
26 | };
27 | /* End PBXContainerItemProxy section */
28 |
29 | /* Begin PBXFileReference section */
30 | 26A458CE9EF8F3422E825CF9 /* Pods_SignalR_Swift_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalR_Swift_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
31 | 790AC94075959051C56799D5 /* Pods-SignalR-Swift-ExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalR-Swift-ExampleTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalR-Swift-ExampleTests/Pods-SignalR-Swift-ExampleTests.release.xcconfig"; sourceTree = ""; };
32 | 793E4C03DAB6B7009192E2EF /* Pods-SignalR-Swift-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalR-Swift-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalR-Swift-Example/Pods-SignalR-Swift-Example.release.xcconfig"; sourceTree = ""; };
33 | A2D0F25BF5CDF45777FDC3D3 /* Pods-SignalR-Swift-ExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalR-Swift-ExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalR-Swift-ExampleTests/Pods-SignalR-Swift-ExampleTests.debug.xcconfig"; sourceTree = ""; };
34 | BB5250B3C095B54B6A8372E7 /* Pods_SignalR_Swift_ExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalR_Swift_ExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
35 | C61CCEAF90DA9573CAF2F41D /* Pods-SignalR-Swift-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalR-Swift-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalR-Swift-Example/Pods-SignalR-Swift-Example.debug.xcconfig"; sourceTree = ""; };
36 | C9E64D6C1E27DC3300DEDC20 /* SignalR-Swift-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SignalR-Swift-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
37 | C9E64D6F1E27DC3300DEDC20 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
38 | C9E64D711E27DC3300DEDC20 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
39 | C9E64D761E27DC3300DEDC20 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
40 | C9E64D791E27DC3300DEDC20 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
41 | C9E64D7B1E27DC3300DEDC20 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
42 | C9E64D801E27DC3400DEDC20 /* SignalR-Swift-ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SignalR-Swift-ExampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
43 | C9E64D841E27DC3400DEDC20 /* SignalR_Swift_ExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalR_Swift_ExampleTests.swift; sourceTree = ""; };
44 | C9E64D861E27DC3400DEDC20 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | C9E64D901E27E47800DEDC20 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
46 | /* End PBXFileReference section */
47 |
48 | /* Begin PBXFrameworksBuildPhase section */
49 | C9E64D691E27DC3300DEDC20 /* Frameworks */ = {
50 | isa = PBXFrameworksBuildPhase;
51 | buildActionMask = 2147483647;
52 | files = (
53 | );
54 | runOnlyForDeploymentPostprocessing = 0;
55 | };
56 | C9E64D7D1E27DC3400DEDC20 /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | 715553CCD279348CB60CA3CA /* Pods_SignalR_Swift_ExampleTests.framework in Frameworks */,
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | /* End PBXFrameworksBuildPhase section */
65 |
66 | /* Begin PBXGroup section */
67 | 3074C68C23B280A1578C9624 /* Frameworks */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 26A458CE9EF8F3422E825CF9 /* Pods_SignalR_Swift_Example.framework */,
71 | BB5250B3C095B54B6A8372E7 /* Pods_SignalR_Swift_ExampleTests.framework */,
72 | );
73 | name = Frameworks;
74 | sourceTree = "";
75 | };
76 | 781EA09133FDDDA08190CC4A /* Pods */ = {
77 | isa = PBXGroup;
78 | children = (
79 | C61CCEAF90DA9573CAF2F41D /* Pods-SignalR-Swift-Example.debug.xcconfig */,
80 | 793E4C03DAB6B7009192E2EF /* Pods-SignalR-Swift-Example.release.xcconfig */,
81 | A2D0F25BF5CDF45777FDC3D3 /* Pods-SignalR-Swift-ExampleTests.debug.xcconfig */,
82 | 790AC94075959051C56799D5 /* Pods-SignalR-Swift-ExampleTests.release.xcconfig */,
83 | );
84 | name = Pods;
85 | sourceTree = "";
86 | };
87 | C9E64D631E27DC3300DEDC20 = {
88 | isa = PBXGroup;
89 | children = (
90 | C9E64D6E1E27DC3300DEDC20 /* SignalR-Swift-Example */,
91 | C9E64D831E27DC3400DEDC20 /* SignalR-Swift-ExampleTests */,
92 | C9E64D6D1E27DC3300DEDC20 /* Products */,
93 | 781EA09133FDDDA08190CC4A /* Pods */,
94 | 3074C68C23B280A1578C9624 /* Frameworks */,
95 | );
96 | sourceTree = "";
97 | };
98 | C9E64D6D1E27DC3300DEDC20 /* Products */ = {
99 | isa = PBXGroup;
100 | children = (
101 | C9E64D6C1E27DC3300DEDC20 /* SignalR-Swift-Example.app */,
102 | C9E64D801E27DC3400DEDC20 /* SignalR-Swift-ExampleTests.xctest */,
103 | );
104 | name = Products;
105 | sourceTree = "";
106 | };
107 | C9E64D6E1E27DC3300DEDC20 /* SignalR-Swift-Example */ = {
108 | isa = PBXGroup;
109 | children = (
110 | C9E64D6F1E27DC3300DEDC20 /* AppDelegate.swift */,
111 | C9E64D711E27DC3300DEDC20 /* ViewController.swift */,
112 | C9E64D761E27DC3300DEDC20 /* Assets.xcassets */,
113 | C9E64D781E27DC3300DEDC20 /* LaunchScreen.storyboard */,
114 | C9E64D8F1E27E47800DEDC20 /* Main.storyboard */,
115 | C9E64D7B1E27DC3300DEDC20 /* Info.plist */,
116 | );
117 | path = "SignalR-Swift-Example";
118 | sourceTree = "";
119 | };
120 | C9E64D831E27DC3400DEDC20 /* SignalR-Swift-ExampleTests */ = {
121 | isa = PBXGroup;
122 | children = (
123 | C9E64D841E27DC3400DEDC20 /* SignalR_Swift_ExampleTests.swift */,
124 | C9E64D861E27DC3400DEDC20 /* Info.plist */,
125 | );
126 | path = "SignalR-Swift-ExampleTests";
127 | sourceTree = "";
128 | };
129 | /* End PBXGroup section */
130 |
131 | /* Begin PBXNativeTarget section */
132 | C9E64D6B1E27DC3300DEDC20 /* SignalR-Swift-Example */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = C9E64D891E27DC3400DEDC20 /* Build configuration list for PBXNativeTarget "SignalR-Swift-Example" */;
135 | buildPhases = (
136 | 0C3202FEE06CE733AE264351 /* [CP] Check Pods Manifest.lock */,
137 | C9E64D681E27DC3300DEDC20 /* Sources */,
138 | C9E64D691E27DC3300DEDC20 /* Frameworks */,
139 | C9E64D6A1E27DC3300DEDC20 /* Resources */,
140 | 6F42A1175AEEF087513135D6 /* [CP] Embed Pods Frameworks */,
141 | 3B0F052C7D6CDBE56E5190EC /* [CP] Copy Pods Resources */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = "SignalR-Swift-Example";
148 | productName = "SignalR-Swift-Example";
149 | productReference = C9E64D6C1E27DC3300DEDC20 /* SignalR-Swift-Example.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | C9E64D7F1E27DC3400DEDC20 /* SignalR-Swift-ExampleTests */ = {
153 | isa = PBXNativeTarget;
154 | buildConfigurationList = C9E64D8C1E27DC3400DEDC20 /* Build configuration list for PBXNativeTarget "SignalR-Swift-ExampleTests" */;
155 | buildPhases = (
156 | B721394EE4F0D4E64AB5B418 /* [CP] Check Pods Manifest.lock */,
157 | C9E64D7C1E27DC3400DEDC20 /* Sources */,
158 | C9E64D7D1E27DC3400DEDC20 /* Frameworks */,
159 | C9E64D7E1E27DC3400DEDC20 /* Resources */,
160 | 10D9A3292E3B053C4B1F1E8B /* [CP] Embed Pods Frameworks */,
161 | 77521BBF68CE60E8E2BA4051 /* [CP] Copy Pods Resources */,
162 | );
163 | buildRules = (
164 | );
165 | dependencies = (
166 | C9E64D821E27DC3400DEDC20 /* PBXTargetDependency */,
167 | );
168 | name = "SignalR-Swift-ExampleTests";
169 | productName = "SignalR-Swift-ExampleTests";
170 | productReference = C9E64D801E27DC3400DEDC20 /* SignalR-Swift-ExampleTests.xctest */;
171 | productType = "com.apple.product-type.bundle.unit-test";
172 | };
173 | /* End PBXNativeTarget section */
174 |
175 | /* Begin PBXProject section */
176 | C9E64D641E27DC3300DEDC20 /* Project object */ = {
177 | isa = PBXProject;
178 | attributes = {
179 | LastSwiftUpdateCheck = 0820;
180 | LastUpgradeCheck = 0900;
181 | ORGANIZATIONNAME = "Jordan Camara";
182 | TargetAttributes = {
183 | C9E64D6B1E27DC3300DEDC20 = {
184 | CreatedOnToolsVersion = 8.2.1;
185 | DevelopmentTeam = 8Z35TU97D6;
186 | ProvisioningStyle = Automatic;
187 | };
188 | C9E64D7F1E27DC3400DEDC20 = {
189 | CreatedOnToolsVersion = 8.2.1;
190 | DevelopmentTeam = 8Z35TU97D6;
191 | ProvisioningStyle = Automatic;
192 | TestTargetID = C9E64D6B1E27DC3300DEDC20;
193 | };
194 | };
195 | };
196 | buildConfigurationList = C9E64D671E27DC3300DEDC20 /* Build configuration list for PBXProject "SignalR-Swift-Example" */;
197 | compatibilityVersion = "Xcode 3.2";
198 | developmentRegion = English;
199 | hasScannedForEncodings = 0;
200 | knownRegions = (
201 | en,
202 | Base,
203 | );
204 | mainGroup = C9E64D631E27DC3300DEDC20;
205 | productRefGroup = C9E64D6D1E27DC3300DEDC20 /* Products */;
206 | projectDirPath = "";
207 | projectRoot = "";
208 | targets = (
209 | C9E64D6B1E27DC3300DEDC20 /* SignalR-Swift-Example */,
210 | C9E64D7F1E27DC3400DEDC20 /* SignalR-Swift-ExampleTests */,
211 | );
212 | };
213 | /* End PBXProject section */
214 |
215 | /* Begin PBXResourcesBuildPhase section */
216 | C9E64D6A1E27DC3300DEDC20 /* Resources */ = {
217 | isa = PBXResourcesBuildPhase;
218 | buildActionMask = 2147483647;
219 | files = (
220 | C9E64D911E27E47800DEDC20 /* Main.storyboard in Resources */,
221 | C9E64D7A1E27DC3300DEDC20 /* LaunchScreen.storyboard in Resources */,
222 | C9E64D771E27DC3300DEDC20 /* Assets.xcassets in Resources */,
223 | );
224 | runOnlyForDeploymentPostprocessing = 0;
225 | };
226 | C9E64D7E1E27DC3400DEDC20 /* Resources */ = {
227 | isa = PBXResourcesBuildPhase;
228 | buildActionMask = 2147483647;
229 | files = (
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | /* End PBXResourcesBuildPhase section */
234 |
235 | /* Begin PBXShellScriptBuildPhase section */
236 | 0C3202FEE06CE733AE264351 /* [CP] Check Pods Manifest.lock */ = {
237 | isa = PBXShellScriptBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | );
241 | inputPaths = (
242 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
243 | "${PODS_ROOT}/Manifest.lock",
244 | );
245 | name = "[CP] Check Pods Manifest.lock";
246 | outputPaths = (
247 | "$(DERIVED_FILE_DIR)/Pods-SignalR-Swift-Example-checkManifestLockResult.txt",
248 | );
249 | runOnlyForDeploymentPostprocessing = 0;
250 | shellPath = /bin/sh;
251 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
252 | showEnvVarsInLog = 0;
253 | };
254 | 10D9A3292E3B053C4B1F1E8B /* [CP] Embed Pods Frameworks */ = {
255 | isa = PBXShellScriptBuildPhase;
256 | buildActionMask = 2147483647;
257 | files = (
258 | );
259 | inputPaths = (
260 | );
261 | name = "[CP] Embed Pods Frameworks";
262 | outputPaths = (
263 | );
264 | runOnlyForDeploymentPostprocessing = 0;
265 | shellPath = /bin/sh;
266 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalR-Swift-ExampleTests/Pods-SignalR-Swift-ExampleTests-frameworks.sh\"\n";
267 | showEnvVarsInLog = 0;
268 | };
269 | 3B0F052C7D6CDBE56E5190EC /* [CP] Copy Pods Resources */ = {
270 | isa = PBXShellScriptBuildPhase;
271 | buildActionMask = 2147483647;
272 | files = (
273 | );
274 | inputPaths = (
275 | );
276 | name = "[CP] Copy Pods Resources";
277 | outputPaths = (
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | shellPath = /bin/sh;
281 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalR-Swift-Example/Pods-SignalR-Swift-Example-resources.sh\"\n";
282 | showEnvVarsInLog = 0;
283 | };
284 | 6F42A1175AEEF087513135D6 /* [CP] Embed Pods Frameworks */ = {
285 | isa = PBXShellScriptBuildPhase;
286 | buildActionMask = 2147483647;
287 | files = (
288 | );
289 | inputPaths = (
290 | "${SRCROOT}/Pods/Target Support Files/Pods-SignalR-Swift-Example/Pods-SignalR-Swift-Example-frameworks.sh",
291 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
292 | "${BUILT_PRODUCTS_DIR}/SignalRSwift/SignalRSwift.framework",
293 | "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework",
294 | );
295 | name = "[CP] Embed Pods Frameworks";
296 | outputPaths = (
297 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
298 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SignalRSwift.framework",
299 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework",
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | shellPath = /bin/sh;
303 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalR-Swift-Example/Pods-SignalR-Swift-Example-frameworks.sh\"\n";
304 | showEnvVarsInLog = 0;
305 | };
306 | 77521BBF68CE60E8E2BA4051 /* [CP] Copy Pods Resources */ = {
307 | isa = PBXShellScriptBuildPhase;
308 | buildActionMask = 2147483647;
309 | files = (
310 | );
311 | inputPaths = (
312 | );
313 | name = "[CP] Copy Pods Resources";
314 | outputPaths = (
315 | );
316 | runOnlyForDeploymentPostprocessing = 0;
317 | shellPath = /bin/sh;
318 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalR-Swift-ExampleTests/Pods-SignalR-Swift-ExampleTests-resources.sh\"\n";
319 | showEnvVarsInLog = 0;
320 | };
321 | B721394EE4F0D4E64AB5B418 /* [CP] Check Pods Manifest.lock */ = {
322 | isa = PBXShellScriptBuildPhase;
323 | buildActionMask = 2147483647;
324 | files = (
325 | );
326 | inputPaths = (
327 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
328 | "${PODS_ROOT}/Manifest.lock",
329 | );
330 | name = "[CP] Check Pods Manifest.lock";
331 | outputPaths = (
332 | "$(DERIVED_FILE_DIR)/Pods-SignalR-Swift-ExampleTests-checkManifestLockResult.txt",
333 | );
334 | runOnlyForDeploymentPostprocessing = 0;
335 | shellPath = /bin/sh;
336 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
337 | showEnvVarsInLog = 0;
338 | };
339 | /* End PBXShellScriptBuildPhase section */
340 |
341 | /* Begin PBXSourcesBuildPhase section */
342 | C9E64D681E27DC3300DEDC20 /* Sources */ = {
343 | isa = PBXSourcesBuildPhase;
344 | buildActionMask = 2147483647;
345 | files = (
346 | C9E64D721E27DC3300DEDC20 /* ViewController.swift in Sources */,
347 | C9E64D701E27DC3300DEDC20 /* AppDelegate.swift in Sources */,
348 | );
349 | runOnlyForDeploymentPostprocessing = 0;
350 | };
351 | C9E64D7C1E27DC3400DEDC20 /* Sources */ = {
352 | isa = PBXSourcesBuildPhase;
353 | buildActionMask = 2147483647;
354 | files = (
355 | C9E64D851E27DC3400DEDC20 /* SignalR_Swift_ExampleTests.swift in Sources */,
356 | );
357 | runOnlyForDeploymentPostprocessing = 0;
358 | };
359 | /* End PBXSourcesBuildPhase section */
360 |
361 | /* Begin PBXTargetDependency section */
362 | C9E64D821E27DC3400DEDC20 /* PBXTargetDependency */ = {
363 | isa = PBXTargetDependency;
364 | target = C9E64D6B1E27DC3300DEDC20 /* SignalR-Swift-Example */;
365 | targetProxy = C9E64D811E27DC3400DEDC20 /* PBXContainerItemProxy */;
366 | };
367 | /* End PBXTargetDependency section */
368 |
369 | /* Begin PBXVariantGroup section */
370 | C9E64D781E27DC3300DEDC20 /* LaunchScreen.storyboard */ = {
371 | isa = PBXVariantGroup;
372 | children = (
373 | C9E64D791E27DC3300DEDC20 /* Base */,
374 | );
375 | name = LaunchScreen.storyboard;
376 | sourceTree = "";
377 | };
378 | C9E64D8F1E27E47800DEDC20 /* Main.storyboard */ = {
379 | isa = PBXVariantGroup;
380 | children = (
381 | C9E64D901E27E47800DEDC20 /* Base */,
382 | );
383 | name = Main.storyboard;
384 | sourceTree = "";
385 | };
386 | /* End PBXVariantGroup section */
387 |
388 | /* Begin XCBuildConfiguration section */
389 | C9E64D871E27DC3400DEDC20 /* Debug */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | ALWAYS_SEARCH_USER_PATHS = NO;
393 | CLANG_ANALYZER_NONNULL = YES;
394 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
395 | CLANG_CXX_LIBRARY = "libc++";
396 | CLANG_ENABLE_MODULES = YES;
397 | CLANG_ENABLE_OBJC_ARC = YES;
398 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
399 | CLANG_WARN_BOOL_CONVERSION = YES;
400 | CLANG_WARN_COMMA = YES;
401 | CLANG_WARN_CONSTANT_CONVERSION = YES;
402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
403 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
404 | CLANG_WARN_EMPTY_BODY = YES;
405 | CLANG_WARN_ENUM_CONVERSION = YES;
406 | CLANG_WARN_INFINITE_RECURSION = YES;
407 | CLANG_WARN_INT_CONVERSION = YES;
408 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
411 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
412 | CLANG_WARN_STRICT_PROTOTYPES = YES;
413 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
414 | CLANG_WARN_UNREACHABLE_CODE = YES;
415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
417 | COPY_PHASE_STRIP = NO;
418 | DEBUG_INFORMATION_FORMAT = dwarf;
419 | ENABLE_STRICT_OBJC_MSGSEND = YES;
420 | ENABLE_TESTABILITY = YES;
421 | GCC_C_LANGUAGE_STANDARD = gnu99;
422 | GCC_DYNAMIC_NO_PIC = NO;
423 | GCC_NO_COMMON_BLOCKS = YES;
424 | GCC_OPTIMIZATION_LEVEL = 0;
425 | GCC_PREPROCESSOR_DEFINITIONS = (
426 | "DEBUG=1",
427 | "$(inherited)",
428 | );
429 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
430 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
431 | GCC_WARN_UNDECLARED_SELECTOR = YES;
432 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
433 | GCC_WARN_UNUSED_FUNCTION = YES;
434 | GCC_WARN_UNUSED_VARIABLE = YES;
435 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
436 | MTL_ENABLE_DEBUG_INFO = YES;
437 | ONLY_ACTIVE_ARCH = YES;
438 | SDKROOT = iphoneos;
439 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
440 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
441 | TARGETED_DEVICE_FAMILY = "1,2";
442 | };
443 | name = Debug;
444 | };
445 | C9E64D881E27DC3400DEDC20 /* Release */ = {
446 | isa = XCBuildConfiguration;
447 | buildSettings = {
448 | ALWAYS_SEARCH_USER_PATHS = NO;
449 | CLANG_ANALYZER_NONNULL = YES;
450 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
451 | CLANG_CXX_LIBRARY = "libc++";
452 | CLANG_ENABLE_MODULES = YES;
453 | CLANG_ENABLE_OBJC_ARC = YES;
454 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
455 | CLANG_WARN_BOOL_CONVERSION = YES;
456 | CLANG_WARN_COMMA = YES;
457 | CLANG_WARN_CONSTANT_CONVERSION = YES;
458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
459 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
460 | CLANG_WARN_EMPTY_BODY = YES;
461 | CLANG_WARN_ENUM_CONVERSION = YES;
462 | CLANG_WARN_INFINITE_RECURSION = YES;
463 | CLANG_WARN_INT_CONVERSION = YES;
464 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
467 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
468 | CLANG_WARN_STRICT_PROTOTYPES = YES;
469 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
470 | CLANG_WARN_UNREACHABLE_CODE = YES;
471 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
472 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
473 | COPY_PHASE_STRIP = NO;
474 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
475 | ENABLE_NS_ASSERTIONS = NO;
476 | ENABLE_STRICT_OBJC_MSGSEND = YES;
477 | GCC_C_LANGUAGE_STANDARD = gnu99;
478 | GCC_NO_COMMON_BLOCKS = YES;
479 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
480 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
481 | GCC_WARN_UNDECLARED_SELECTOR = YES;
482 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
483 | GCC_WARN_UNUSED_FUNCTION = YES;
484 | GCC_WARN_UNUSED_VARIABLE = YES;
485 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
486 | MTL_ENABLE_DEBUG_INFO = NO;
487 | SDKROOT = iphoneos;
488 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
489 | TARGETED_DEVICE_FAMILY = "1,2";
490 | VALIDATE_PRODUCT = YES;
491 | };
492 | name = Release;
493 | };
494 | C9E64D8A1E27DC3400DEDC20 /* Debug */ = {
495 | isa = XCBuildConfiguration;
496 | baseConfigurationReference = C61CCEAF90DA9573CAF2F41D /* Pods-SignalR-Swift-Example.debug.xcconfig */;
497 | buildSettings = {
498 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
499 | DEVELOPMENT_TEAM = 8Z35TU97D6;
500 | INFOPLIST_FILE = "SignalR-Swift-Example/Info.plist";
501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
502 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-Swift-Example";
503 | PRODUCT_NAME = "$(TARGET_NAME)";
504 | SWIFT_VERSION = 4.0;
505 | };
506 | name = Debug;
507 | };
508 | C9E64D8B1E27DC3400DEDC20 /* Release */ = {
509 | isa = XCBuildConfiguration;
510 | baseConfigurationReference = 793E4C03DAB6B7009192E2EF /* Pods-SignalR-Swift-Example.release.xcconfig */;
511 | buildSettings = {
512 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
513 | DEVELOPMENT_TEAM = 8Z35TU97D6;
514 | INFOPLIST_FILE = "SignalR-Swift-Example/Info.plist";
515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
516 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-Swift-Example";
517 | PRODUCT_NAME = "$(TARGET_NAME)";
518 | SWIFT_VERSION = 4.0;
519 | };
520 | name = Release;
521 | };
522 | C9E64D8D1E27DC3400DEDC20 /* Debug */ = {
523 | isa = XCBuildConfiguration;
524 | baseConfigurationReference = A2D0F25BF5CDF45777FDC3D3 /* Pods-SignalR-Swift-ExampleTests.debug.xcconfig */;
525 | buildSettings = {
526 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
527 | BUNDLE_LOADER = "$(TEST_HOST)";
528 | DEVELOPMENT_TEAM = 8Z35TU97D6;
529 | INFOPLIST_FILE = "SignalR-Swift-ExampleTests/Info.plist";
530 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
531 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-Swift-ExampleTests";
532 | PRODUCT_NAME = "$(TARGET_NAME)";
533 | SWIFT_VERSION = 4.0;
534 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SignalR-Swift-Example.app/SignalR-Swift-Example";
535 | };
536 | name = Debug;
537 | };
538 | C9E64D8E1E27DC3400DEDC20 /* Release */ = {
539 | isa = XCBuildConfiguration;
540 | baseConfigurationReference = 790AC94075959051C56799D5 /* Pods-SignalR-Swift-ExampleTests.release.xcconfig */;
541 | buildSettings = {
542 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
543 | BUNDLE_LOADER = "$(TEST_HOST)";
544 | DEVELOPMENT_TEAM = 8Z35TU97D6;
545 | INFOPLIST_FILE = "SignalR-Swift-ExampleTests/Info.plist";
546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
547 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-Swift-ExampleTests";
548 | PRODUCT_NAME = "$(TARGET_NAME)";
549 | SWIFT_VERSION = 4.0;
550 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SignalR-Swift-Example.app/SignalR-Swift-Example";
551 | };
552 | name = Release;
553 | };
554 | /* End XCBuildConfiguration section */
555 |
556 | /* Begin XCConfigurationList section */
557 | C9E64D671E27DC3300DEDC20 /* Build configuration list for PBXProject "SignalR-Swift-Example" */ = {
558 | isa = XCConfigurationList;
559 | buildConfigurations = (
560 | C9E64D871E27DC3400DEDC20 /* Debug */,
561 | C9E64D881E27DC3400DEDC20 /* Release */,
562 | );
563 | defaultConfigurationIsVisible = 0;
564 | defaultConfigurationName = Release;
565 | };
566 | C9E64D891E27DC3400DEDC20 /* Build configuration list for PBXNativeTarget "SignalR-Swift-Example" */ = {
567 | isa = XCConfigurationList;
568 | buildConfigurations = (
569 | C9E64D8A1E27DC3400DEDC20 /* Debug */,
570 | C9E64D8B1E27DC3400DEDC20 /* Release */,
571 | );
572 | defaultConfigurationIsVisible = 0;
573 | defaultConfigurationName = Release;
574 | };
575 | C9E64D8C1E27DC3400DEDC20 /* Build configuration list for PBXNativeTarget "SignalR-Swift-ExampleTests" */ = {
576 | isa = XCConfigurationList;
577 | buildConfigurations = (
578 | C9E64D8D1E27DC3400DEDC20 /* Debug */,
579 | C9E64D8E1E27DC3400DEDC20 /* Release */,
580 | );
581 | defaultConfigurationIsVisible = 0;
582 | defaultConfigurationName = Release;
583 | };
584 | /* End XCConfigurationList section */
585 | };
586 | rootObject = C9E64D641E27DC3300DEDC20 /* Project object */;
587 | }
588 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example.xcodeproj/xcuserdata/jordan_camara.xcuserdatad/xcschemes/SignalR-Swift-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example.xcodeproj/xcuserdata/jordan_camara.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SignalR-Swift-Example.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | C9E64D6B1E27DC3300DEDC20
16 |
17 | primary
18 |
19 |
20 | C9E64D7F1E27DC3400DEDC20
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SignalR-Swift-Example
4 | //
5 | // Created by Jordan Camara on 1/12/17.
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
74 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | NSAppTransportSecurity
45 |
46 | NSAllowsArbitraryLoads
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SignalR-Swift-Example
4 | //
5 | // Created by Jordan Camara on 1/12/17.
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SignalRSwift
11 |
12 | class ViewController: UIViewController {
13 |
14 | @IBOutlet weak var sendButton: UIButton!
15 | @IBOutlet weak var messageTextField: UITextField!
16 | @IBOutlet weak var chatTextView: UITextView!
17 | @IBOutlet weak var statusLabel: UILabel!
18 | @IBOutlet weak var startButton: UIBarButtonItem!
19 |
20 | var chatHub: HubProxy!
21 | var connection: HubConnection!
22 | var name: String!
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 |
27 | connection = HubConnection(withUrl: "http://swiftr.azurewebsites.net") //SignalR("http://swiftr.azurewebsites.net")
28 | // connection.signalRVersion = .v2_2_0
29 |
30 | chatHub = self.connection.createHubProxy(hubName: "chatHub")
31 | _ = chatHub.on(eventName: "broadcastMessage") { (args) in
32 | if let name = args[0] as? String, let message = args[1] as? String, let text = self.chatTextView.text {
33 | self.chatTextView.text = "\(text)\n\n\(name): \(message)"
34 | }
35 | }
36 |
37 | // SignalR events
38 |
39 | connection.started = { [unowned self] in
40 | self.statusLabel.text = "Connected"
41 | self.startButton.isEnabled = true
42 | self.startButton.title = "Stop"
43 | self.sendButton.isEnabled = true
44 | }
45 |
46 | connection.reconnecting = { [unowned self] in
47 | self.statusLabel.text = "Reconnecting..."
48 | }
49 |
50 | connection.reconnected = { [unowned self] in
51 | self.statusLabel.text = "Reconnected. Connection ID: \(self.connection!.connectionId!)"
52 | self.startButton.isEnabled = true
53 | self.startButton.title = "Stop"
54 | self.sendButton.isEnabled = true
55 | }
56 |
57 | connection.closed = { [unowned self] in
58 | self.statusLabel.text = "Disconnected"
59 | self.startButton.isEnabled = true
60 | self.startButton.title = "Start"
61 | self.sendButton.isEnabled = false
62 | }
63 |
64 | connection.connectionSlow = { print("Connection slow...") }
65 |
66 | connection.error = { [unowned self] error in
67 | let anError = error as NSError
68 | if anError.code == NSURLErrorTimedOut {
69 | self.connection.start()
70 | }
71 | }
72 |
73 | connection.start()
74 | }
75 |
76 | override func viewDidAppear(_ animated: Bool) {
77 | let alertController = UIAlertController(title: "Name", message: "Please enter your name", preferredStyle: .alert)
78 |
79 | let okAction = UIAlertAction(title: "OK", style: .default) { [weak self] _ in
80 | self?.name = alertController.textFields?.first?.text
81 |
82 | if let name = self?.name , name.isEmpty {
83 | self?.name = "Anonymous"
84 | }
85 |
86 | alertController.textFields?.first?.resignFirstResponder()
87 | }
88 |
89 | alertController.addTextField { textField in
90 | textField.placeholder = "Your Name"
91 | }
92 |
93 | alertController.addAction(okAction)
94 | present(alertController, animated: true, completion: nil)
95 | }
96 |
97 | override func didReceiveMemoryWarning() {
98 | super.didReceiveMemoryWarning()
99 | // Dispose of any resources that can be recreated.
100 | }
101 |
102 | @IBAction func send(_ sender: AnyObject?) {
103 | if let hub = chatHub, let message = messageTextField.text {
104 | hub.invoke(method: "send", withArgs: [name, message])
105 | }
106 | messageTextField.resignFirstResponder()
107 | }
108 |
109 | @IBAction func startStop(_ sender: AnyObject?) {
110 | if startButton.title == "Start" {
111 | connection.start()
112 | } else {
113 | connection.stop()
114 | }
115 | }
116 |
117 | /*
118 | // MARK: - Navigation
119 |
120 | // In a storyboard-based application, you will often want to do a little preparation before navigation
121 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
122 | // Get the new view controller using segue.destinationViewController.
123 | // Pass the selected object to the new view controller.
124 | }
125 | */
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-ExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SignalR-Swift-Example/SignalR-Swift-ExampleTests/SignalR_Swift_ExampleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignalR_Swift_ExampleTests.swift
3 | // SignalR-Swift-ExampleTests
4 | //
5 | // Created by Jordan Camara on 1/12/17.
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SignalR_Swift_Example
11 |
12 | class SignalR_Swift_ExampleTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/SignalR-Swift.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 03D89CA2D29AD16BE22FB404 /* Pods_SignalRSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E3DD50F71B5A709F5EC093E9 /* Pods_SignalRSwift.framework */; };
11 | 563B87161F1FA11100D75CEF /* ServerSentEventsTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563B87151F1FA11100D75CEF /* ServerSentEventsTransport.swift */; };
12 | 568A77191F223CB2004F5D1C /* ChunkBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 568A77181F223CB2004F5D1C /* ChunkBuffer.swift */; };
13 | 568A771B1F223CF0004F5D1C /* ServerSentEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 568A771A1F223CF0004F5D1C /* ServerSentEvent.swift */; };
14 | AA049197DB8438E88C7B3D5D /* Pods_SignalR_SwiftTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 291C54976E982A542BA4B4C3 /* Pods_SignalR_SwiftTests.framework */; };
15 | C91154631E24113F007C0DD9 /* WebSocketTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154621E24113F007C0DD9 /* WebSocketTransport.swift */; };
16 | C91154661E241239007C0DD9 /* WebSocketConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154651E241239007C0DD9 /* WebSocketConnectionInfo.swift */; };
17 | C91154681E243082007C0DD9 /* ReceivedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154671E243082007C0DD9 /* ReceivedMessage.swift */; };
18 | C911546A1E253B1B007C0DD9 /* LongPollingTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154691E253B1B007C0DD9 /* LongPollingTransport.swift */; };
19 | C911546C1E255CB2007C0DD9 /* ExceptionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C911546B1E255CB2007C0DD9 /* ExceptionHelper.swift */; };
20 | C911546F1E256491007C0DD9 /* HubConnectionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C911546E1E256491007C0DD9 /* HubConnectionProtocol.swift */; };
21 | C91154711E2564C1007C0DD9 /* HubResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154701E2564C1007C0DD9 /* HubResult.swift */; };
22 | C91154731E2566DC007C0DD9 /* HubConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154721E2566DC007C0DD9 /* HubConnection.swift */; };
23 | C91154751E256721007C0DD9 /* HubProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154741E256721007C0DD9 /* HubProxy.swift */; };
24 | C91154771E256741007C0DD9 /* HubProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91154761E256741007C0DD9 /* HubProxyProtocol.swift */; };
25 | C911547B1E256F98007C0DD9 /* HubInvocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C911547A1E256F98007C0DD9 /* HubInvocation.swift */; };
26 | C92AD2591E2EBCB9009686E2 /* Dictionary+Json.swift in Sources */ = {isa = PBXBuildFile; fileRef = C92AD2581E2EBCB9009686E2 /* Dictionary+Json.swift */; };
27 | C9330B321E1FE59A00B1F2D5 /* SignalRSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9330B281E1FE59A00B1F2D5 /* SignalRSwift.framework */; };
28 | C9330B391E1FE59A00B1F2D5 /* SignalR-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = C9330B2B1E1FE59A00B1F2D5 /* SignalR-Swift.h */; settings = {ATTRIBUTES = (Public, ); }; };
29 | C944563A1E76C02F000FF744 /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94456391E76C02F000FF744 /* ConnectionTests.swift */; };
30 | C944563C1E76C555000FF744 /* MockClientTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C944563B1E76C555000FF744 /* MockClientTransport.swift */; };
31 | C9B9229D1E295AD7007C2266 /* String+Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B9229C1E295AD7007C2266 /* String+Dictionary.swift */; };
32 | C9E1C9F81E1FEEF800335B1E /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1C9F71E1FEEF800335B1E /* Connection.swift */; };
33 | C9E1C9FB1E1FF03400335B1E /* ConnectionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1C9FA1E1FF03400335B1E /* ConnectionState.swift */; };
34 | C9E1CA041E1FF3B700335B1E /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1CA031E1FF3B700335B1E /* Version.swift */; };
35 | C9E1CA061E1FFADA00335B1E /* HeartbeatMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1CA051E1FFADA00335B1E /* HeartbeatMonitor.swift */; };
36 | C9E1CA081E1FFB0C00335B1E /* ConnectionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1CA071E1FFB0C00335B1E /* ConnectionProtocol.swift */; };
37 | C9E1CA0A1E1FFB6600335B1E /* KeepAliveData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1CA091E1FFB6600335B1E /* KeepAliveData.swift */; };
38 | C9E1CA0C1E1FFDA800335B1E /* ClientTransportProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1CA0B1E1FFDA800335B1E /* ClientTransportProtocol.swift */; };
39 | C9E1CA0E1E1FFE0400335B1E /* NegotiationResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E1CA0D1E1FFE0400335B1E /* NegotiationResponse.swift */; };
40 | C9FC2D951E2025B80027FE59 /* AutoTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FC2D941E2025B80027FE59 /* AutoTransport.swift */; };
41 | C9FC2D971E2025DB0027FE59 /* HttpTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FC2D961E2025DB0027FE59 /* HttpTransport.swift */; };
42 | C9FC2D991E23BC600027FE59 /* ConnectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FC2D981E23BC600027FE59 /* ConnectionDelegate.swift */; };
43 | /* End PBXBuildFile section */
44 |
45 | /* Begin PBXContainerItemProxy section */
46 | C9330B331E1FE59A00B1F2D5 /* PBXContainerItemProxy */ = {
47 | isa = PBXContainerItemProxy;
48 | containerPortal = C9330B1F1E1FE59A00B1F2D5 /* Project object */;
49 | proxyType = 1;
50 | remoteGlobalIDString = C9330B271E1FE59A00B1F2D5;
51 | remoteInfo = "SignalR-Swift";
52 | };
53 | /* End PBXContainerItemProxy section */
54 |
55 | /* Begin PBXFileReference section */
56 | 291C54976E982A542BA4B4C3 /* Pods_SignalR_SwiftTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalR_SwiftTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
57 | 42E40FC4FECA749AD861D67E /* Pods-SignalRSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalRSwift.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalRSwift/Pods-SignalRSwift.debug.xcconfig"; sourceTree = ""; };
58 | 563B87151F1FA11100D75CEF /* ServerSentEventsTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerSentEventsTransport.swift; sourceTree = ""; };
59 | 568A77181F223CB2004F5D1C /* ChunkBuffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChunkBuffer.swift; path = "SignalR-Swift/Transports/ServerSentEvents/ChunkBuffer.swift"; sourceTree = SOURCE_ROOT; };
60 | 568A771A1F223CF0004F5D1C /* ServerSentEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ServerSentEvent.swift; path = "SignalR-Swift/Transports/ServerSentEvents/ServerSentEvent.swift"; sourceTree = SOURCE_ROOT; };
61 | 65B59CFA9FAF15B46BDCDEC1 /* Pods-SignalR-SwiftTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalR-SwiftTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalR-SwiftTests/Pods-SignalR-SwiftTests.debug.xcconfig"; sourceTree = ""; };
62 | B5E080DF752A22D635CE38CF /* Pods-SignalR-SwiftTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalR-SwiftTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalR-SwiftTests/Pods-SignalR-SwiftTests.release.xcconfig"; sourceTree = ""; };
63 | B9B048FC932F5933F9447DCE /* Pods-SignalRSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalRSwift.release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalRSwift/Pods-SignalRSwift.release.xcconfig"; sourceTree = ""; };
64 | C91154621E24113F007C0DD9 /* WebSocketTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketTransport.swift; sourceTree = ""; };
65 | C91154651E241239007C0DD9 /* WebSocketConnectionInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketConnectionInfo.swift; sourceTree = ""; };
66 | C91154671E243082007C0DD9 /* ReceivedMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceivedMessage.swift; sourceTree = ""; };
67 | C91154691E253B1B007C0DD9 /* LongPollingTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongPollingTransport.swift; sourceTree = ""; };
68 | C911546B1E255CB2007C0DD9 /* ExceptionHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExceptionHelper.swift; sourceTree = ""; };
69 | C911546E1E256491007C0DD9 /* HubConnectionProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubConnectionProtocol.swift; sourceTree = ""; };
70 | C91154701E2564C1007C0DD9 /* HubResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubResult.swift; sourceTree = ""; };
71 | C91154721E2566DC007C0DD9 /* HubConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubConnection.swift; sourceTree = ""; };
72 | C91154741E256721007C0DD9 /* HubProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubProxy.swift; sourceTree = ""; };
73 | C91154761E256741007C0DD9 /* HubProxyProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubProxyProtocol.swift; sourceTree = ""; };
74 | C911547A1E256F98007C0DD9 /* HubInvocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HubInvocation.swift; sourceTree = ""; };
75 | C92AD2581E2EBCB9009686E2 /* Dictionary+Json.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Json.swift"; sourceTree = ""; };
76 | C9330B281E1FE59A00B1F2D5 /* SignalRSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SignalRSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
77 | C9330B2B1E1FE59A00B1F2D5 /* SignalR-Swift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalR-Swift.h"; sourceTree = ""; };
78 | C9330B2C1E1FE59A00B1F2D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
79 | C9330B311E1FE59A00B1F2D5 /* SignalR-SwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SignalR-SwiftTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
80 | C9330B381E1FE59A00B1F2D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
81 | C94456391E76C02F000FF744 /* ConnectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConnectionTests.swift; path = "SignalR-SwiftTests/Connection/ConnectionTests.swift"; sourceTree = SOURCE_ROOT; };
82 | C944563B1E76C555000FF744 /* MockClientTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockClientTransport.swift; sourceTree = ""; };
83 | C9B9229C1E295AD7007C2266 /* String+Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Dictionary.swift"; sourceTree = ""; };
84 | C9E1C9F71E1FEEF800335B1E /* Connection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Connection.swift; sourceTree = ""; };
85 | C9E1C9FA1E1FF03400335B1E /* ConnectionState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionState.swift; sourceTree = ""; };
86 | C9E1CA031E1FF3B700335B1E /* Version.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Version.swift; sourceTree = ""; };
87 | C9E1CA051E1FFADA00335B1E /* HeartbeatMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeartbeatMonitor.swift; sourceTree = ""; };
88 | C9E1CA071E1FFB0C00335B1E /* ConnectionProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionProtocol.swift; sourceTree = ""; };
89 | C9E1CA091E1FFB6600335B1E /* KeepAliveData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeepAliveData.swift; sourceTree = ""; };
90 | C9E1CA0B1E1FFDA800335B1E /* ClientTransportProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClientTransportProtocol.swift; sourceTree = ""; };
91 | C9E1CA0D1E1FFE0400335B1E /* NegotiationResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NegotiationResponse.swift; sourceTree = ""; };
92 | C9FC2D941E2025B80027FE59 /* AutoTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoTransport.swift; sourceTree = ""; };
93 | C9FC2D961E2025DB0027FE59 /* HttpTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpTransport.swift; sourceTree = ""; };
94 | C9FC2D981E23BC600027FE59 /* ConnectionDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionDelegate.swift; sourceTree = ""; };
95 | E3DD50F71B5A709F5EC093E9 /* Pods_SignalRSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalRSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
96 | /* End PBXFileReference section */
97 |
98 | /* Begin PBXFrameworksBuildPhase section */
99 | C9330B241E1FE59A00B1F2D5 /* Frameworks */ = {
100 | isa = PBXFrameworksBuildPhase;
101 | buildActionMask = 2147483647;
102 | files = (
103 | 03D89CA2D29AD16BE22FB404 /* Pods_SignalRSwift.framework in Frameworks */,
104 | );
105 | runOnlyForDeploymentPostprocessing = 0;
106 | };
107 | C9330B2E1E1FE59A00B1F2D5 /* Frameworks */ = {
108 | isa = PBXFrameworksBuildPhase;
109 | buildActionMask = 2147483647;
110 | files = (
111 | C9330B321E1FE59A00B1F2D5 /* SignalRSwift.framework in Frameworks */,
112 | AA049197DB8438E88C7B3D5D /* Pods_SignalR_SwiftTests.framework in Frameworks */,
113 | );
114 | runOnlyForDeploymentPostprocessing = 0;
115 | };
116 | /* End PBXFrameworksBuildPhase section */
117 |
118 | /* Begin PBXGroup section */
119 | 316A9BF3DEFAB629DD2C78FD /* Frameworks */ = {
120 | isa = PBXGroup;
121 | children = (
122 | E3DD50F71B5A709F5EC093E9 /* Pods_SignalRSwift.framework */,
123 | 291C54976E982A542BA4B4C3 /* Pods_SignalR_SwiftTests.framework */,
124 | );
125 | name = Frameworks;
126 | sourceTree = "";
127 | };
128 | 5686CBB81F7C03B3008CA187 /* ServerSentEvents */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 568A77181F223CB2004F5D1C /* ChunkBuffer.swift */,
132 | 568A771A1F223CF0004F5D1C /* ServerSentEvent.swift */,
133 | );
134 | path = ServerSentEvents;
135 | sourceTree = "";
136 | };
137 | C4B90292188059B3970F0902 /* Pods */ = {
138 | isa = PBXGroup;
139 | children = (
140 | 65B59CFA9FAF15B46BDCDEC1 /* Pods-SignalR-SwiftTests.debug.xcconfig */,
141 | B5E080DF752A22D635CE38CF /* Pods-SignalR-SwiftTests.release.xcconfig */,
142 | 42E40FC4FECA749AD861D67E /* Pods-SignalRSwift.debug.xcconfig */,
143 | B9B048FC932F5933F9447DCE /* Pods-SignalRSwift.release.xcconfig */,
144 | );
145 | name = Pods;
146 | sourceTree = "";
147 | };
148 | C911545F1E23D205007C0DD9 /* Models */ = {
149 | isa = PBXGroup;
150 | children = (
151 | C91154671E243082007C0DD9 /* ReceivedMessage.swift */,
152 | );
153 | path = Models;
154 | sourceTree = "";
155 | };
156 | C91154641E24122C007C0DD9 /* WebSockets */ = {
157 | isa = PBXGroup;
158 | children = (
159 | C91154651E241239007C0DD9 /* WebSocketConnectionInfo.swift */,
160 | );
161 | path = WebSockets;
162 | sourceTree = "";
163 | };
164 | C911546D1E25643D007C0DD9 /* Hubs */ = {
165 | isa = PBXGroup;
166 | children = (
167 | C91154701E2564C1007C0DD9 /* HubResult.swift */,
168 | C91154721E2566DC007C0DD9 /* HubConnection.swift */,
169 | C91154741E256721007C0DD9 /* HubProxy.swift */,
170 | C911547A1E256F98007C0DD9 /* HubInvocation.swift */,
171 | );
172 | path = Hubs;
173 | sourceTree = "";
174 | };
175 | C9330B1E1E1FE59A00B1F2D5 = {
176 | isa = PBXGroup;
177 | children = (
178 | C9330B2A1E1FE59A00B1F2D5 /* SignalR-Swift */,
179 | C9330B351E1FE59A00B1F2D5 /* SignalR-SwiftTests */,
180 | C9330B291E1FE59A00B1F2D5 /* Products */,
181 | C4B90292188059B3970F0902 /* Pods */,
182 | 316A9BF3DEFAB629DD2C78FD /* Frameworks */,
183 | );
184 | sourceTree = "";
185 | };
186 | C9330B291E1FE59A00B1F2D5 /* Products */ = {
187 | isa = PBXGroup;
188 | children = (
189 | C9330B281E1FE59A00B1F2D5 /* SignalRSwift.framework */,
190 | C9330B311E1FE59A00B1F2D5 /* SignalR-SwiftTests.xctest */,
191 | );
192 | name = Products;
193 | sourceTree = "";
194 | };
195 | C9330B2A1E1FE59A00B1F2D5 /* SignalR-Swift */ = {
196 | isa = PBXGroup;
197 | children = (
198 | C9B9229B1E295A78007C2266 /* Extensions */,
199 | C911545F1E23D205007C0DD9 /* Models */,
200 | C9E1C9F61E1FEEBE00335B1E /* Client */,
201 | C9FC2D931E2025990027FE59 /* Transports */,
202 | C9330B2B1E1FE59A00B1F2D5 /* SignalR-Swift.h */,
203 | C9330B2C1E1FE59A00B1F2D5 /* Info.plist */,
204 | );
205 | path = "SignalR-Swift";
206 | sourceTree = "";
207 | };
208 | C9330B351E1FE59A00B1F2D5 /* SignalR-SwiftTests */ = {
209 | isa = PBXGroup;
210 | children = (
211 | C94456361E76BFCB000FF744 /* Mocks */,
212 | C94456371E76BFCB000FF744 /* Transport */,
213 | C94456381E76BFCB000FF744 /* Connection */,
214 | C9330B381E1FE59A00B1F2D5 /* Info.plist */,
215 | );
216 | path = "SignalR-SwiftTests";
217 | sourceTree = "";
218 | };
219 | C94456361E76BFCB000FF744 /* Mocks */ = {
220 | isa = PBXGroup;
221 | children = (
222 | C944563B1E76C555000FF744 /* MockClientTransport.swift */,
223 | );
224 | path = Mocks;
225 | sourceTree = "";
226 | };
227 | C94456371E76BFCB000FF744 /* Transport */ = {
228 | isa = PBXGroup;
229 | children = (
230 | );
231 | path = Transport;
232 | sourceTree = "";
233 | };
234 | C94456381E76BFCB000FF744 /* Connection */ = {
235 | isa = PBXGroup;
236 | children = (
237 | C94456391E76C02F000FF744 /* ConnectionTests.swift */,
238 | );
239 | path = Connection;
240 | sourceTree = "";
241 | };
242 | C9B9229B1E295A78007C2266 /* Extensions */ = {
243 | isa = PBXGroup;
244 | children = (
245 | C9B9229C1E295AD7007C2266 /* String+Dictionary.swift */,
246 | C92AD2581E2EBCB9009686E2 /* Dictionary+Json.swift */,
247 | );
248 | path = Extensions;
249 | sourceTree = "";
250 | };
251 | C9E1C9F61E1FEEBE00335B1E /* Client */ = {
252 | isa = PBXGroup;
253 | children = (
254 | C911546D1E25643D007C0DD9 /* Hubs */,
255 | C9E1CA021E1FF3B700335B1E /* Infrastructure */,
256 | C9E1C9F91E1FF02200335B1E /* Enums */,
257 | C9E1C9FC1E1FF1B100335B1E /* Protocols */,
258 | C9E1C9F71E1FEEF800335B1E /* Connection.swift */,
259 | C9E1CA051E1FFADA00335B1E /* HeartbeatMonitor.swift */,
260 | C9E1CA091E1FFB6600335B1E /* KeepAliveData.swift */,
261 | C9E1CA0D1E1FFE0400335B1E /* NegotiationResponse.swift */,
262 | );
263 | path = Client;
264 | sourceTree = "";
265 | };
266 | C9E1C9F91E1FF02200335B1E /* Enums */ = {
267 | isa = PBXGroup;
268 | children = (
269 | C9E1C9FA1E1FF03400335B1E /* ConnectionState.swift */,
270 | );
271 | path = Enums;
272 | sourceTree = "";
273 | };
274 | C9E1C9FC1E1FF1B100335B1E /* Protocols */ = {
275 | isa = PBXGroup;
276 | children = (
277 | C9E1CA071E1FFB0C00335B1E /* ConnectionProtocol.swift */,
278 | C9E1CA0B1E1FFDA800335B1E /* ClientTransportProtocol.swift */,
279 | C9FC2D981E23BC600027FE59 /* ConnectionDelegate.swift */,
280 | C911546E1E256491007C0DD9 /* HubConnectionProtocol.swift */,
281 | C91154761E256741007C0DD9 /* HubProxyProtocol.swift */,
282 | );
283 | path = Protocols;
284 | sourceTree = "";
285 | };
286 | C9E1CA021E1FF3B700335B1E /* Infrastructure */ = {
287 | isa = PBXGroup;
288 | children = (
289 | C9E1CA031E1FF3B700335B1E /* Version.swift */,
290 | C911546B1E255CB2007C0DD9 /* ExceptionHelper.swift */,
291 | );
292 | path = Infrastructure;
293 | sourceTree = "";
294 | };
295 | C9FC2D931E2025990027FE59 /* Transports */ = {
296 | isa = PBXGroup;
297 | children = (
298 | 5686CBB81F7C03B3008CA187 /* ServerSentEvents */,
299 | C91154641E24122C007C0DD9 /* WebSockets */,
300 | C9FC2D941E2025B80027FE59 /* AutoTransport.swift */,
301 | C9FC2D961E2025DB0027FE59 /* HttpTransport.swift */,
302 | C91154621E24113F007C0DD9 /* WebSocketTransport.swift */,
303 | C91154691E253B1B007C0DD9 /* LongPollingTransport.swift */,
304 | 563B87151F1FA11100D75CEF /* ServerSentEventsTransport.swift */,
305 | );
306 | path = Transports;
307 | sourceTree = "";
308 | };
309 | /* End PBXGroup section */
310 |
311 | /* Begin PBXHeadersBuildPhase section */
312 | C9330B251E1FE59A00B1F2D5 /* Headers */ = {
313 | isa = PBXHeadersBuildPhase;
314 | buildActionMask = 2147483647;
315 | files = (
316 | C9330B391E1FE59A00B1F2D5 /* SignalR-Swift.h in Headers */,
317 | );
318 | runOnlyForDeploymentPostprocessing = 0;
319 | };
320 | /* End PBXHeadersBuildPhase section */
321 |
322 | /* Begin PBXNativeTarget section */
323 | C9330B271E1FE59A00B1F2D5 /* SignalRSwift */ = {
324 | isa = PBXNativeTarget;
325 | buildConfigurationList = C9330B3C1E1FE59A00B1F2D5 /* Build configuration list for PBXNativeTarget "SignalRSwift" */;
326 | buildPhases = (
327 | 8893B2F1770B24873610B1CA /* [CP] Check Pods Manifest.lock */,
328 | C9330B231E1FE59A00B1F2D5 /* Sources */,
329 | C9330B241E1FE59A00B1F2D5 /* Frameworks */,
330 | C9330B251E1FE59A00B1F2D5 /* Headers */,
331 | C9330B261E1FE59A00B1F2D5 /* Resources */,
332 | BE9A67E61EA448B742E04260 /* [CP] Copy Pods Resources */,
333 | );
334 | buildRules = (
335 | );
336 | dependencies = (
337 | );
338 | name = SignalRSwift;
339 | productName = "SignalR-Swift";
340 | productReference = C9330B281E1FE59A00B1F2D5 /* SignalRSwift.framework */;
341 | productType = "com.apple.product-type.framework";
342 | };
343 | C9330B301E1FE59A00B1F2D5 /* SignalR-SwiftTests */ = {
344 | isa = PBXNativeTarget;
345 | buildConfigurationList = C9330B3F1E1FE59A00B1F2D5 /* Build configuration list for PBXNativeTarget "SignalR-SwiftTests" */;
346 | buildPhases = (
347 | F71AD12E7750A42FE3671D48 /* [CP] Check Pods Manifest.lock */,
348 | C9330B2D1E1FE59A00B1F2D5 /* Sources */,
349 | C9330B2E1E1FE59A00B1F2D5 /* Frameworks */,
350 | C9330B2F1E1FE59A00B1F2D5 /* Resources */,
351 | 1408BA98AFE158F7832B6F37 /* [CP] Embed Pods Frameworks */,
352 | E29934DC4C7132EA079822B1 /* [CP] Copy Pods Resources */,
353 | );
354 | buildRules = (
355 | );
356 | dependencies = (
357 | C9330B341E1FE59A00B1F2D5 /* PBXTargetDependency */,
358 | );
359 | name = "SignalR-SwiftTests";
360 | productName = "SignalR-SwiftTests";
361 | productReference = C9330B311E1FE59A00B1F2D5 /* SignalR-SwiftTests.xctest */;
362 | productType = "com.apple.product-type.bundle.unit-test";
363 | };
364 | /* End PBXNativeTarget section */
365 |
366 | /* Begin PBXProject section */
367 | C9330B1F1E1FE59A00B1F2D5 /* Project object */ = {
368 | isa = PBXProject;
369 | attributes = {
370 | LastSwiftUpdateCheck = 0820;
371 | LastUpgradeCheck = 0820;
372 | ORGANIZATIONNAME = "Jordan Camara";
373 | TargetAttributes = {
374 | C9330B271E1FE59A00B1F2D5 = {
375 | CreatedOnToolsVersion = 8.2.1;
376 | DevelopmentTeam = 8Z35TU97D6;
377 | LastSwiftMigration = 0820;
378 | ProvisioningStyle = Automatic;
379 | };
380 | C9330B301E1FE59A00B1F2D5 = {
381 | CreatedOnToolsVersion = 8.2.1;
382 | DevelopmentTeam = 8Z35TU97D6;
383 | LastSwiftMigration = 0820;
384 | ProvisioningStyle = Automatic;
385 | };
386 | };
387 | };
388 | buildConfigurationList = C9330B221E1FE59A00B1F2D5 /* Build configuration list for PBXProject "SignalR-Swift" */;
389 | compatibilityVersion = "Xcode 3.2";
390 | developmentRegion = English;
391 | hasScannedForEncodings = 0;
392 | knownRegions = (
393 | en,
394 | );
395 | mainGroup = C9330B1E1E1FE59A00B1F2D5;
396 | productRefGroup = C9330B291E1FE59A00B1F2D5 /* Products */;
397 | projectDirPath = "";
398 | projectRoot = "";
399 | targets = (
400 | C9330B271E1FE59A00B1F2D5 /* SignalRSwift */,
401 | C9330B301E1FE59A00B1F2D5 /* SignalR-SwiftTests */,
402 | );
403 | };
404 | /* End PBXProject section */
405 |
406 | /* Begin PBXResourcesBuildPhase section */
407 | C9330B261E1FE59A00B1F2D5 /* Resources */ = {
408 | isa = PBXResourcesBuildPhase;
409 | buildActionMask = 2147483647;
410 | files = (
411 | );
412 | runOnlyForDeploymentPostprocessing = 0;
413 | };
414 | C9330B2F1E1FE59A00B1F2D5 /* Resources */ = {
415 | isa = PBXResourcesBuildPhase;
416 | buildActionMask = 2147483647;
417 | files = (
418 | );
419 | runOnlyForDeploymentPostprocessing = 0;
420 | };
421 | /* End PBXResourcesBuildPhase section */
422 |
423 | /* Begin PBXShellScriptBuildPhase section */
424 | 1408BA98AFE158F7832B6F37 /* [CP] Embed Pods Frameworks */ = {
425 | isa = PBXShellScriptBuildPhase;
426 | buildActionMask = 2147483647;
427 | files = (
428 | );
429 | inputPaths = (
430 | "${SRCROOT}/Pods/Target Support Files/Pods-SignalR-SwiftTests/Pods-SignalR-SwiftTests-frameworks.sh",
431 | "${BUILT_PRODUCTS_DIR}/Mockit/Mockit.framework",
432 | "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework",
433 | "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework",
434 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
435 | "${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework",
436 | );
437 | name = "[CP] Embed Pods Frameworks";
438 | outputPaths = (
439 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mockit.framework",
440 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework",
441 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework",
442 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
443 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework",
444 | );
445 | runOnlyForDeploymentPostprocessing = 0;
446 | shellPath = /bin/sh;
447 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalR-SwiftTests/Pods-SignalR-SwiftTests-frameworks.sh\"\n";
448 | showEnvVarsInLog = 0;
449 | };
450 | 8893B2F1770B24873610B1CA /* [CP] Check Pods Manifest.lock */ = {
451 | isa = PBXShellScriptBuildPhase;
452 | buildActionMask = 2147483647;
453 | files = (
454 | );
455 | inputPaths = (
456 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
457 | "${PODS_ROOT}/Manifest.lock",
458 | );
459 | name = "[CP] Check Pods Manifest.lock";
460 | outputPaths = (
461 | "$(DERIVED_FILE_DIR)/Pods-SignalRSwift-checkManifestLockResult.txt",
462 | );
463 | runOnlyForDeploymentPostprocessing = 0;
464 | shellPath = /bin/sh;
465 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
466 | showEnvVarsInLog = 0;
467 | };
468 | BE9A67E61EA448B742E04260 /* [CP] Copy Pods Resources */ = {
469 | isa = PBXShellScriptBuildPhase;
470 | buildActionMask = 2147483647;
471 | files = (
472 | );
473 | inputPaths = (
474 | );
475 | name = "[CP] Copy Pods Resources";
476 | outputPaths = (
477 | );
478 | runOnlyForDeploymentPostprocessing = 0;
479 | shellPath = /bin/sh;
480 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalRSwift/Pods-SignalRSwift-resources.sh\"\n";
481 | showEnvVarsInLog = 0;
482 | };
483 | E29934DC4C7132EA079822B1 /* [CP] Copy Pods Resources */ = {
484 | isa = PBXShellScriptBuildPhase;
485 | buildActionMask = 2147483647;
486 | files = (
487 | );
488 | inputPaths = (
489 | );
490 | name = "[CP] Copy Pods Resources";
491 | outputPaths = (
492 | );
493 | runOnlyForDeploymentPostprocessing = 0;
494 | shellPath = /bin/sh;
495 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalR-SwiftTests/Pods-SignalR-SwiftTests-resources.sh\"\n";
496 | showEnvVarsInLog = 0;
497 | };
498 | F71AD12E7750A42FE3671D48 /* [CP] Check Pods Manifest.lock */ = {
499 | isa = PBXShellScriptBuildPhase;
500 | buildActionMask = 2147483647;
501 | files = (
502 | );
503 | inputPaths = (
504 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
505 | "${PODS_ROOT}/Manifest.lock",
506 | );
507 | name = "[CP] Check Pods Manifest.lock";
508 | outputPaths = (
509 | "$(DERIVED_FILE_DIR)/Pods-SignalR-SwiftTests-checkManifestLockResult.txt",
510 | );
511 | runOnlyForDeploymentPostprocessing = 0;
512 | shellPath = /bin/sh;
513 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
514 | showEnvVarsInLog = 0;
515 | };
516 | /* End PBXShellScriptBuildPhase section */
517 |
518 | /* Begin PBXSourcesBuildPhase section */
519 | C9330B231E1FE59A00B1F2D5 /* Sources */ = {
520 | isa = PBXSourcesBuildPhase;
521 | buildActionMask = 2147483647;
522 | files = (
523 | C9E1C9F81E1FEEF800335B1E /* Connection.swift in Sources */,
524 | C91154731E2566DC007C0DD9 /* HubConnection.swift in Sources */,
525 | C9B9229D1E295AD7007C2266 /* String+Dictionary.swift in Sources */,
526 | C9E1CA061E1FFADA00335B1E /* HeartbeatMonitor.swift in Sources */,
527 | 568A771B1F223CF0004F5D1C /* ServerSentEvent.swift in Sources */,
528 | C911546C1E255CB2007C0DD9 /* ExceptionHelper.swift in Sources */,
529 | 568A77191F223CB2004F5D1C /* ChunkBuffer.swift in Sources */,
530 | C9E1CA0A1E1FFB6600335B1E /* KeepAliveData.swift in Sources */,
531 | C91154711E2564C1007C0DD9 /* HubResult.swift in Sources */,
532 | C9E1CA0C1E1FFDA800335B1E /* ClientTransportProtocol.swift in Sources */,
533 | C9E1CA0E1E1FFE0400335B1E /* NegotiationResponse.swift in Sources */,
534 | C9E1CA041E1FF3B700335B1E /* Version.swift in Sources */,
535 | C911546A1E253B1B007C0DD9 /* LongPollingTransport.swift in Sources */,
536 | C92AD2591E2EBCB9009686E2 /* Dictionary+Json.swift in Sources */,
537 | C9E1C9FB1E1FF03400335B1E /* ConnectionState.swift in Sources */,
538 | C9FC2D971E2025DB0027FE59 /* HttpTransport.swift in Sources */,
539 | C91154661E241239007C0DD9 /* WebSocketConnectionInfo.swift in Sources */,
540 | C91154771E256741007C0DD9 /* HubProxyProtocol.swift in Sources */,
541 | C9FC2D951E2025B80027FE59 /* AutoTransport.swift in Sources */,
542 | C911546F1E256491007C0DD9 /* HubConnectionProtocol.swift in Sources */,
543 | 563B87161F1FA11100D75CEF /* ServerSentEventsTransport.swift in Sources */,
544 | C9E1CA081E1FFB0C00335B1E /* ConnectionProtocol.swift in Sources */,
545 | C91154681E243082007C0DD9 /* ReceivedMessage.swift in Sources */,
546 | C9FC2D991E23BC600027FE59 /* ConnectionDelegate.swift in Sources */,
547 | C91154751E256721007C0DD9 /* HubProxy.swift in Sources */,
548 | C91154631E24113F007C0DD9 /* WebSocketTransport.swift in Sources */,
549 | C911547B1E256F98007C0DD9 /* HubInvocation.swift in Sources */,
550 | );
551 | runOnlyForDeploymentPostprocessing = 0;
552 | };
553 | C9330B2D1E1FE59A00B1F2D5 /* Sources */ = {
554 | isa = PBXSourcesBuildPhase;
555 | buildActionMask = 2147483647;
556 | files = (
557 | C944563C1E76C555000FF744 /* MockClientTransport.swift in Sources */,
558 | C944563A1E76C02F000FF744 /* ConnectionTests.swift in Sources */,
559 | );
560 | runOnlyForDeploymentPostprocessing = 0;
561 | };
562 | /* End PBXSourcesBuildPhase section */
563 |
564 | /* Begin PBXTargetDependency section */
565 | C9330B341E1FE59A00B1F2D5 /* PBXTargetDependency */ = {
566 | isa = PBXTargetDependency;
567 | target = C9330B271E1FE59A00B1F2D5 /* SignalRSwift */;
568 | targetProxy = C9330B331E1FE59A00B1F2D5 /* PBXContainerItemProxy */;
569 | };
570 | /* End PBXTargetDependency section */
571 |
572 | /* Begin XCBuildConfiguration section */
573 | C9330B3A1E1FE59A00B1F2D5 /* Debug */ = {
574 | isa = XCBuildConfiguration;
575 | buildSettings = {
576 | ALWAYS_SEARCH_USER_PATHS = NO;
577 | CLANG_ANALYZER_NONNULL = YES;
578 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
579 | CLANG_CXX_LIBRARY = "libc++";
580 | CLANG_ENABLE_MODULES = YES;
581 | CLANG_ENABLE_OBJC_ARC = YES;
582 | CLANG_WARN_BOOL_CONVERSION = YES;
583 | CLANG_WARN_CONSTANT_CONVERSION = YES;
584 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
585 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
586 | CLANG_WARN_EMPTY_BODY = YES;
587 | CLANG_WARN_ENUM_CONVERSION = YES;
588 | CLANG_WARN_INFINITE_RECURSION = YES;
589 | CLANG_WARN_INT_CONVERSION = YES;
590 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
591 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
592 | CLANG_WARN_UNREACHABLE_CODE = YES;
593 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
594 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
595 | COPY_PHASE_STRIP = NO;
596 | CURRENT_PROJECT_VERSION = 1;
597 | DEBUG_INFORMATION_FORMAT = dwarf;
598 | ENABLE_STRICT_OBJC_MSGSEND = YES;
599 | ENABLE_TESTABILITY = YES;
600 | GCC_C_LANGUAGE_STANDARD = gnu99;
601 | GCC_DYNAMIC_NO_PIC = NO;
602 | GCC_NO_COMMON_BLOCKS = YES;
603 | GCC_OPTIMIZATION_LEVEL = 0;
604 | GCC_PREPROCESSOR_DEFINITIONS = (
605 | "DEBUG=1",
606 | "$(inherited)",
607 | );
608 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
609 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
610 | GCC_WARN_UNDECLARED_SELECTOR = YES;
611 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
612 | GCC_WARN_UNUSED_FUNCTION = YES;
613 | GCC_WARN_UNUSED_VARIABLE = YES;
614 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
615 | MTL_ENABLE_DEBUG_INFO = YES;
616 | ONLY_ACTIVE_ARCH = YES;
617 | SDKROOT = iphoneos;
618 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
619 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
620 | TARGETED_DEVICE_FAMILY = "1,2";
621 | VERSIONING_SYSTEM = "apple-generic";
622 | VERSION_INFO_PREFIX = "";
623 | };
624 | name = Debug;
625 | };
626 | C9330B3B1E1FE59A00B1F2D5 /* Release */ = {
627 | isa = XCBuildConfiguration;
628 | buildSettings = {
629 | ALWAYS_SEARCH_USER_PATHS = NO;
630 | CLANG_ANALYZER_NONNULL = YES;
631 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
632 | CLANG_CXX_LIBRARY = "libc++";
633 | CLANG_ENABLE_MODULES = YES;
634 | CLANG_ENABLE_OBJC_ARC = YES;
635 | CLANG_WARN_BOOL_CONVERSION = YES;
636 | CLANG_WARN_CONSTANT_CONVERSION = YES;
637 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
638 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
639 | CLANG_WARN_EMPTY_BODY = YES;
640 | CLANG_WARN_ENUM_CONVERSION = YES;
641 | CLANG_WARN_INFINITE_RECURSION = YES;
642 | CLANG_WARN_INT_CONVERSION = YES;
643 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
644 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
645 | CLANG_WARN_UNREACHABLE_CODE = YES;
646 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
647 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
648 | COPY_PHASE_STRIP = NO;
649 | CURRENT_PROJECT_VERSION = 1;
650 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
651 | ENABLE_NS_ASSERTIONS = NO;
652 | ENABLE_STRICT_OBJC_MSGSEND = YES;
653 | GCC_C_LANGUAGE_STANDARD = gnu99;
654 | GCC_NO_COMMON_BLOCKS = YES;
655 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
656 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
657 | GCC_WARN_UNDECLARED_SELECTOR = YES;
658 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
659 | GCC_WARN_UNUSED_FUNCTION = YES;
660 | GCC_WARN_UNUSED_VARIABLE = YES;
661 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
662 | MTL_ENABLE_DEBUG_INFO = NO;
663 | SDKROOT = iphoneos;
664 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
665 | TARGETED_DEVICE_FAMILY = "1,2";
666 | VALIDATE_PRODUCT = YES;
667 | VERSIONING_SYSTEM = "apple-generic";
668 | VERSION_INFO_PREFIX = "";
669 | };
670 | name = Release;
671 | };
672 | C9330B3D1E1FE59A00B1F2D5 /* Debug */ = {
673 | isa = XCBuildConfiguration;
674 | baseConfigurationReference = 42E40FC4FECA749AD861D67E /* Pods-SignalRSwift.debug.xcconfig */;
675 | buildSettings = {
676 | CLANG_ENABLE_MODULES = YES;
677 | CODE_SIGN_IDENTITY = "";
678 | DEFINES_MODULE = YES;
679 | DEVELOPMENT_TEAM = 8Z35TU97D6;
680 | DYLIB_COMPATIBILITY_VERSION = 1;
681 | DYLIB_CURRENT_VERSION = 1;
682 | DYLIB_INSTALL_NAME_BASE = "@rpath";
683 | INFOPLIST_FILE = "SignalR-Swift/Info.plist";
684 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
685 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
686 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
687 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-Swift";
688 | PRODUCT_NAME = "$(TARGET_NAME)";
689 | SKIP_INSTALL = YES;
690 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
691 | SWIFT_VERSION = 4.0;
692 | };
693 | name = Debug;
694 | };
695 | C9330B3E1E1FE59A00B1F2D5 /* Release */ = {
696 | isa = XCBuildConfiguration;
697 | baseConfigurationReference = B9B048FC932F5933F9447DCE /* Pods-SignalRSwift.release.xcconfig */;
698 | buildSettings = {
699 | CLANG_ENABLE_MODULES = YES;
700 | CODE_SIGN_IDENTITY = "";
701 | DEFINES_MODULE = YES;
702 | DEVELOPMENT_TEAM = 8Z35TU97D6;
703 | DYLIB_COMPATIBILITY_VERSION = 1;
704 | DYLIB_CURRENT_VERSION = 1;
705 | DYLIB_INSTALL_NAME_BASE = "@rpath";
706 | INFOPLIST_FILE = "SignalR-Swift/Info.plist";
707 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
708 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
709 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
710 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-Swift";
711 | PRODUCT_NAME = "$(TARGET_NAME)";
712 | SKIP_INSTALL = YES;
713 | SWIFT_VERSION = 4.0;
714 | };
715 | name = Release;
716 | };
717 | C9330B401E1FE59A00B1F2D5 /* Debug */ = {
718 | isa = XCBuildConfiguration;
719 | baseConfigurationReference = 65B59CFA9FAF15B46BDCDEC1 /* Pods-SignalR-SwiftTests.debug.xcconfig */;
720 | buildSettings = {
721 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
722 | CLANG_ENABLE_MODULES = YES;
723 | DEVELOPMENT_TEAM = 8Z35TU97D6;
724 | INFOPLIST_FILE = "SignalR-SwiftTests/Info.plist";
725 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
726 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-SwiftTests";
727 | PRODUCT_NAME = "$(TARGET_NAME)";
728 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
729 | SWIFT_VERSION = 4.0;
730 | };
731 | name = Debug;
732 | };
733 | C9330B411E1FE59A00B1F2D5 /* Release */ = {
734 | isa = XCBuildConfiguration;
735 | baseConfigurationReference = B5E080DF752A22D635CE38CF /* Pods-SignalR-SwiftTests.release.xcconfig */;
736 | buildSettings = {
737 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
738 | CLANG_ENABLE_MODULES = YES;
739 | DEVELOPMENT_TEAM = 8Z35TU97D6;
740 | INFOPLIST_FILE = "SignalR-SwiftTests/Info.plist";
741 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
742 | PRODUCT_BUNDLE_IDENTIFIER = "com.autosoftdms.SignalR-SwiftTests";
743 | PRODUCT_NAME = "$(TARGET_NAME)";
744 | SWIFT_VERSION = 4.0;
745 | };
746 | name = Release;
747 | };
748 | /* End XCBuildConfiguration section */
749 |
750 | /* Begin XCConfigurationList section */
751 | C9330B221E1FE59A00B1F2D5 /* Build configuration list for PBXProject "SignalR-Swift" */ = {
752 | isa = XCConfigurationList;
753 | buildConfigurations = (
754 | C9330B3A1E1FE59A00B1F2D5 /* Debug */,
755 | C9330B3B1E1FE59A00B1F2D5 /* Release */,
756 | );
757 | defaultConfigurationIsVisible = 0;
758 | defaultConfigurationName = Release;
759 | };
760 | C9330B3C1E1FE59A00B1F2D5 /* Build configuration list for PBXNativeTarget "SignalRSwift" */ = {
761 | isa = XCConfigurationList;
762 | buildConfigurations = (
763 | C9330B3D1E1FE59A00B1F2D5 /* Debug */,
764 | C9330B3E1E1FE59A00B1F2D5 /* Release */,
765 | );
766 | defaultConfigurationIsVisible = 0;
767 | defaultConfigurationName = Release;
768 | };
769 | C9330B3F1E1FE59A00B1F2D5 /* Build configuration list for PBXNativeTarget "SignalR-SwiftTests" */ = {
770 | isa = XCConfigurationList;
771 | buildConfigurations = (
772 | C9330B401E1FE59A00B1F2D5 /* Debug */,
773 | C9330B411E1FE59A00B1F2D5 /* Release */,
774 | );
775 | defaultConfigurationIsVisible = 0;
776 | defaultConfigurationName = Release;
777 | };
778 | /* End XCConfigurationList section */
779 | };
780 | rootObject = C9330B1F1E1FE59A00B1F2D5 /* Project object */;
781 | }
782 |
--------------------------------------------------------------------------------
/SignalR-Swift.xcodeproj/xcuserdata/jordan_camara.xcuserdatad/xcschemes/SignalR-Swift.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/SignalR-Swift.xcodeproj/xcuserdata/jordan_camara.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SignalR-Swift.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | C9330B271E1FE59A00B1F2D5
16 |
17 | primary
18 |
19 |
20 | C9330B301E1FE59A00B1F2D5
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/SignalR-Swift.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Connection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Connection.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import Alamofire
12 |
13 | public typealias ConnectionStartedClosure = (() -> ())
14 | public typealias ConnectionReceivedClosure = ((Any) -> ())
15 | public typealias ConnectionErrorClosure = ((Error) -> ())
16 | public typealias ConnectionClosedClosure = (() -> ())
17 | public typealias ConnectionReconnectingClosure = (() -> ())
18 | public typealias ConnectionReconnectedClosure = (() -> ())
19 | public typealias ConnectionStateChangedClosure = ((ConnectionState) -> ())
20 | public typealias ConnectionConnectionSlowClosure = (() -> ())
21 |
22 | public class Connection: ConnectionProtocol {
23 | var defaultAbortTimeout = 30.0
24 | var assemblyVersion: Version?
25 | var disconnectTimeout: Double?
26 | var disconnectTimeoutOperation: BlockOperation!
27 |
28 | public var state = ConnectionState.disconnected
29 | public var url: String
30 |
31 | public var items = [String : Any]()
32 | public let queryString: [String: String]?
33 |
34 | var connectionData: String?
35 | var monitor: HeartbeatMonitor?
36 |
37 | public var version = Version(major: 1, minor: 3)
38 |
39 | public var connectionId: String?
40 | public var connectionToken: String?
41 | public var groupsToken: String?
42 | public var messageId: String?
43 |
44 | public var headers = HTTPHeaders()
45 | public var keepAliveData: KeepAliveData?
46 | public var webSocketAllowsSelfSignedSSL = false
47 | public internal(set) var sessionManager: SessionManager
48 |
49 | public var transport: ClientTransportProtocol?
50 | public var transportConnectTimeout = 0.0
51 |
52 | public var started: ConnectionStartedClosure?
53 | public var received: ConnectionReceivedClosure?
54 | public var error: ConnectionErrorClosure?
55 | public var closed: ConnectionClosedClosure?
56 | public var reconnecting: ConnectionReconnectingClosure?
57 | public var reconnected: ConnectionReconnectedClosure?
58 | public var stateChanged: ConnectionStateChangedClosure?
59 | public var connectionSlow: ConnectionConnectionSlowClosure?
60 |
61 | weak var delegate: ConnectionDelegate?
62 |
63 | static func ensureReconnecting(connection: ConnectionProtocol) -> Bool {
64 | if connection.changeState(oldState: .connected, toState: .reconnecting) {
65 | connection.willReconnect()
66 | }
67 |
68 | return connection.state == .reconnecting
69 | }
70 |
71 | public init(withUrl url: String, queryString: [String: String]? = nil, sessionManager: SessionManager = .default) {
72 | self.url = url.hasSuffix("/") ? url : url.appending("/")
73 | self.queryString = queryString
74 | self.sessionManager = sessionManager
75 | }
76 |
77 | // MARK: - Connection management
78 |
79 | public func start() {
80 | self.start(transport: AutoTransport())
81 | }
82 |
83 | public func start(transport: ClientTransportProtocol) {
84 | if !self.changeState(oldState: .disconnected, toState: .connecting) {
85 | return
86 | }
87 |
88 | self.monitor = HeartbeatMonitor(withConnection: self)
89 | self.transport = transport
90 |
91 | self.negotiate(transport: transport)
92 | }
93 |
94 | func negotiate(transport: ClientTransportProtocol) {
95 | self.connectionData = self.onSending()
96 |
97 | transport.negotiate(connection: self, connectionData: self.connectionData, completionHandler: { [unowned self] (response, error) in
98 | if let error = error {
99 | self.didReceiveError(error: error)
100 | self.stopButDoNotCallServer()
101 | return
102 | }
103 |
104 | defer { self.startTransport() }
105 |
106 | guard let response = response else { return }
107 |
108 | self.verifyProtocolVersion(versionString: response.protocolVersion)
109 |
110 | self.connectionId = response.connectionId
111 | self.connectionToken = response.connectionToken
112 | self.disconnectTimeout = response.disconnectTimeout
113 |
114 | if let transportTimeout = response.transportConnectTimeout {
115 | self.transportConnectTimeout += transportTimeout
116 | }
117 |
118 | if let keepAlive = response.keepAliveTimeout {
119 | self.keepAliveData = KeepAliveData(timeout: keepAlive)
120 | }
121 | })
122 | }
123 |
124 | func startTransport() {
125 | self.transport?.start(connection: self, connectionData: self.connectionData, completionHandler: { [unowned self] (response, error) in
126 | if let error = error {
127 | self.didReceiveError(error: error)
128 | self.stopButDoNotCallServer()
129 | return
130 | }
131 |
132 | _ = self.changeState(oldState: .connecting, toState: .connected)
133 |
134 | if self.keepAliveData != nil, let transport = self.transport, transport.supportsKeepAlive {
135 | self.monitor?.start()
136 | }
137 |
138 | self.started?()
139 | self.delegate?.connectionDidOpen(connection: self)
140 | })
141 | }
142 |
143 | public func changeState(oldState: ConnectionState, toState newState: ConnectionState) -> Bool {
144 | guard self.state == oldState else { /* invalid transition */ return false }
145 |
146 | self.state = newState
147 | self.stateChanged?(self.state)
148 | self.delegate?.connection(connection: self, didChangeState: oldState, newState: newState)
149 |
150 | return true
151 | }
152 |
153 | func verifyProtocolVersion(versionString: String) {
154 | if Version(string: versionString) != self.version {
155 | NSException.raise(.internalInconsistencyException, format: NSLocalizedString("Incompatible Protocol Version", comment: "internal inconsistency exception"), arguments: getVaList(["nil"]))
156 | }
157 | }
158 |
159 | func stopAndCallServer() {
160 | self.stop(withTimeout: self.defaultAbortTimeout)
161 | }
162 |
163 | func stopButDoNotCallServer() {
164 | self.stop(withTimeout: -1.0)
165 | }
166 |
167 | public func stop() {
168 | self.stopAndCallServer()
169 | }
170 |
171 | func stop(withTimeout timeout: Double) {
172 | guard self.state != .disconnected else { return }
173 |
174 | self.monitor?.stop()
175 | self.monitor = nil
176 |
177 | self.transport?.abort(connection: self, timeout: timeout, connectionData: self.connectionData)
178 | self.disconnect()
179 |
180 | self.transport = nil
181 | }
182 |
183 | public func disconnect() {
184 | guard self.state != .disconnected else { return }
185 |
186 | self.state = .disconnected
187 |
188 | self.monitor?.stop()
189 | self.monitor = nil
190 |
191 | // clear the state for this connection
192 | self.connectionId = nil
193 | self.connectionToken = nil
194 | self.groupsToken = nil
195 | self.messageId = nil
196 |
197 | self.didClose()
198 | }
199 |
200 | // MARK: - Sending Data
201 |
202 | public func onSending() -> String? {
203 | return nil
204 | }
205 |
206 | public func send(object: Any, completionHandler: ((Any?, Error?) -> ())?) {
207 | if self.state == .disconnected {
208 | let userInfo = [
209 | NSLocalizedFailureReasonErrorKey: NSExceptionName.internalInconsistencyException.rawValue,
210 | NSLocalizedDescriptionKey: NSLocalizedString("Start must be called before data can be sent.", comment: "start order exception")
211 | ]
212 |
213 | let error = NSError(domain: "com.autosoftdms.SignalR-Swift.\(type(of: self))", code: 0, userInfo: userInfo)
214 | self.didReceiveError(error: error)
215 | completionHandler?(nil, error)
216 |
217 | return
218 | }
219 |
220 | if self.state == .connecting {
221 | let userInfo = [
222 | NSLocalizedFailureReasonErrorKey: NSExceptionName.internalInconsistencyException.rawValue,
223 | NSLocalizedDescriptionKey: NSLocalizedString("The connection has not been established.", comment: "connection not established exception")
224 | ]
225 |
226 | let error = NSError(domain: "com.autosoftdms.SignalR-Swift.\(type(of: self))", code: 0, userInfo: userInfo)
227 | self.didReceiveError(error: error)
228 | completionHandler?(nil, error)
229 | return
230 | }
231 |
232 | self.transport?.send(connection: self, data: object, connectionData: self.connectionData, completionHandler: completionHandler)
233 | }
234 |
235 | // MARK: - Received Data
236 |
237 | public func didReceiveData(data: Any) {
238 | self.received?(data)
239 | self.delegate?.connection(connection: self, didReceiveData: data)
240 | }
241 |
242 | public func didReceiveError(error: Error) {
243 | self.error?(error)
244 | self.delegate?.connection(connection: self, didReceiveError: error)
245 | }
246 |
247 | public func willReconnect() {
248 | if let disconnectTimeout = self.disconnectTimeout {
249 | self.disconnectTimeoutOperation = BlockOperation(block: { [weak self] in self?.stopButDoNotCallServer() })
250 | self.disconnectTimeoutOperation.perform(#selector(BlockOperation.start), with: nil, afterDelay: disconnectTimeout)
251 | }
252 |
253 | if let reconnecting = self.reconnecting {
254 | reconnecting()
255 | }
256 |
257 | self.delegate?.connectionWillReconnect(connection: self)
258 | }
259 |
260 | public func didReconnect() {
261 | NSObject.cancelPreviousPerformRequests(withTarget: self.disconnectTimeoutOperation, selector: #selector(BlockOperation.start), object: nil)
262 | self.disconnectTimeoutOperation = nil
263 |
264 | self.reconnected?()
265 |
266 | self.delegate?.connectionDidReconnect(connection: self)
267 |
268 | self.updateLastKeepAlive()
269 | }
270 |
271 | public func connectionDidSlow() {
272 | self.connectionSlow?()
273 | self.delegate?.connectionDidSlow(connection: self)
274 | }
275 |
276 | func didClose() {
277 | self.closed?()
278 | self.delegate?.connectionDidClose(connection: self)
279 | }
280 |
281 | // MARK: - Prepare Request
282 |
283 | public func addValue(value: String, forHttpHeaderField field: String) {
284 | self.headers[field] = value
285 | }
286 |
287 | public func updateLastKeepAlive() {
288 | self.keepAliveData?.lastKeepAlive = Date()
289 | }
290 |
291 | public func getRequest(url: URLConvertible, httpMethod: HTTPMethod, encoding: ParameterEncoding, parameters: Parameters?) -> DataRequest {
292 | return self.getRequest(url: url, httpMethod: httpMethod, encoding: encoding, parameters: parameters, timeout: 30.0, headers: [:])
293 | }
294 |
295 | public func getRequest(url: URLConvertible, httpMethod: HTTPMethod, encoding: ParameterEncoding, parameters: Parameters?, timeout: Double) -> DataRequest {
296 | return self.getRequest(url: url, httpMethod: httpMethod, encoding: encoding, parameters: parameters, timeout: timeout, headers: [:])
297 | }
298 |
299 | public func getRequest(url: URLConvertible, httpMethod: HTTPMethod, encoding: ParameterEncoding, parameters: Parameters?, timeout: Double, headers: HTTPHeaders) -> DataRequest {
300 | var globalHeaders = self.headers
301 | globalHeaders["User-Agent"] = self.createUserAgentString(client: "SignalR.Client.iOS")
302 |
303 | for (httpHeader, value) in headers {
304 | globalHeaders[httpHeader] = value
305 | }
306 |
307 | var urlRequest = try? URLRequest(url: url.asURL(), method: httpMethod, headers: globalHeaders)
308 | urlRequest?.timeoutInterval = timeout
309 |
310 | let encodedURLRequest = try? encoding.encode(urlRequest!, with: parameters)
311 | return sessionManager.request(encodedURLRequest!)
312 | }
313 |
314 | func createUserAgentString(client: String) -> String {
315 | if self.assemblyVersion == nil {
316 | self.assemblyVersion = Version(major: 2, minor: 0)
317 | }
318 |
319 | return "\(client)/\(self.assemblyVersion!) (\(UIDevice.current.localizedModel) \(UIDevice.current.systemVersion))"
320 | }
321 |
322 | public func processResponse(response: Data, shouldReconnect: inout Bool, disconnected: inout Bool) {
323 | self.updateLastKeepAlive()
324 |
325 | shouldReconnect = false
326 | disconnected = false
327 |
328 | guard let json = try? JSONSerialization.jsonObject(with: response),
329 | let message = ReceivedMessage(jsonObject: json) else { return }
330 |
331 | if message.result != nil {
332 | self.didReceiveData(data: json)
333 | }
334 |
335 | if let reconnect = message.shouldReconnect {
336 | shouldReconnect = reconnect
337 | }
338 |
339 | if disconnected, let disconnect = message.disconnected {
340 | disconnected = disconnect
341 | return
342 | }
343 |
344 | if let groupsToken = message.groupsToken {
345 | self.groupsToken = groupsToken
346 | }
347 |
348 | if let messages = message.messages {
349 | if let messageId = message.messageId {
350 | self.messageId = messageId
351 | }
352 |
353 | messages.forEach(self.didReceiveData)
354 | }
355 | }
356 |
357 | deinit {
358 | if self.state != .disconnected {
359 | self.stop()
360 | }
361 | }
362 | }
363 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Enums/ConnectionState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectionState.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum ConnectionState : Int {
12 | case connecting
13 | case connected
14 | case reconnecting
15 | case disconnected
16 | }
17 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/HeartbeatMonitor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HeartbeatMonitor.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public final class HeartbeatMonitor {
12 |
13 | private(set) var hasBeenWarned = false
14 | private(set) var didTimeOut = false
15 | private var timer: Timer?
16 | private unowned let connection: ConnectionProtocol
17 |
18 | init(withConnection connection: ConnectionProtocol) {
19 | self.connection = connection
20 | }
21 |
22 | func start() {
23 | self.connection.updateLastKeepAlive()
24 | self.hasBeenWarned = false
25 | self.didTimeOut = false
26 | if let interval = self.connection.keepAliveData?.checkInterval {
27 | self.timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(heartBeat(_:)), userInfo: nil, repeats: true)
28 | }
29 | }
30 |
31 | @objc func heartBeat(_ timer: Timer) {
32 | guard let lastKeepAlive = connection.keepAliveData?.lastKeepAlive else { return }
33 |
34 | let timeElapsed = Date().timeIntervalSince(lastKeepAlive)
35 | self.beat(timeElapsed: timeElapsed)
36 | }
37 |
38 | func beat(timeElapsed: Double) {
39 | guard self.connection.state == .connected, let keepAlive = self.connection.keepAliveData else { return }
40 |
41 | if timeElapsed >= keepAlive.timeout {
42 | if !self.didTimeOut {
43 | self.didTimeOut = true
44 | self.connection.transport?.lostConnection(connection: self.connection)
45 | }
46 | } else if timeElapsed >= keepAlive.timeoutWarning {
47 | if !self.hasBeenWarned {
48 | self.hasBeenWarned = true
49 | self.connection.connectionDidSlow()
50 | }
51 | } else {
52 | self.hasBeenWarned = false
53 | self.didTimeOut = false
54 | }
55 | }
56 |
57 | func stop() {
58 | self.timer?.invalidate()
59 | self.timer = nil
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Hubs/HubConnection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HubConnection.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Alamofire
11 |
12 | public class HubConnection: Connection, HubConnectionProtocol {
13 |
14 | private var hubs = [String: HubProxy]()
15 | private var callbacks = [String: HubConnectionHubResultClosure]()
16 | private var callbackId = UInt.min
17 |
18 | public init(withUrl url: String,
19 | queryString: [String: String]? = nil,
20 | sessionManager: SessionManager = .default,
21 | useDefault: Bool = true) {
22 | super.init(withUrl: HubConnection.getUrl(url: url, useDefault: useDefault),
23 | queryString: queryString,
24 | sessionManager: sessionManager)
25 | }
26 |
27 | public func createHubProxy(hubName: String) -> HubProxy? {
28 | if self.state != .disconnected {
29 | NSException.raise(.internalInconsistencyException, format: NSLocalizedString("Proxies cannot be added after the connection has been started.", comment: "proxy added after connection starts exception"), arguments: getVaList(["nil"]))
30 | }
31 |
32 | let hubName = hubName.lowercased()
33 |
34 | guard self.hubs[hubName] == nil else { return nil }
35 |
36 | let proxy = HubProxy(connection: self, hubName: hubName)
37 | self.hubs[hubName] = proxy
38 | return proxy
39 | }
40 |
41 | public func registerCallback(callback: @escaping HubConnectionHubResultClosure) -> String {
42 | let newId = String(self.callbackId)
43 | self.callbacks[newId] = callback
44 | self.callbackId += 1
45 |
46 | return newId
47 | }
48 |
49 | public func removeCallback(callbackId: String) {
50 | self.callbacks.removeValue(forKey: callbackId)
51 | }
52 |
53 | func clearInvocationCallbacks(error: String?) {
54 | let result = HubResult(error: error)
55 |
56 | for (_, callback) in self.callbacks {
57 | callback(result)
58 | }
59 |
60 | self.callbacks.removeAll()
61 | }
62 |
63 | // MARK: - Private
64 |
65 | static func getUrl(url: String, useDefault: Bool) -> String {
66 | let urlResult = url.hasSuffix("/") ? url : url.appending("/")
67 | return useDefault ? urlResult.appending("signalr") : urlResult
68 | }
69 |
70 | // MARK - Sending Data
71 |
72 | override public func onSending() -> String {
73 | let hubNames = self.hubs.map { (key, _) in ["Name": key] }
74 | let data = try! JSONSerialization.data(withJSONObject: hubNames)
75 | return String(data: data, encoding: .utf8)!
76 | }
77 |
78 | // MARK: - Received Data
79 |
80 | override public func didReceiveData(data: Any) {
81 | guard let dict = data as? [String: Any] else { return }
82 |
83 | if dict["I"] != nil {
84 | let result = HubResult(jsonObject: dict)
85 | if let callback = self.callbacks[result.id!] {
86 | callback(result)
87 | return
88 | }
89 | }
90 |
91 | let invocation = HubInvocation(jsonObject: dict)
92 |
93 | if let hubProxy = self.hubs[invocation.hub.lowercased()] {
94 | invocation.state.forEach { (key, value) in hubProxy.state[key] = value }
95 |
96 | hubProxy.invokeEvent(eventName: invocation.method, withArgs: invocation.args)
97 | }
98 |
99 | super.didReceiveData(data: data)
100 | }
101 |
102 | override public func willReconnect() {
103 | self.clearInvocationCallbacks(error: "Connection started reconnecting before invocation result was received.")
104 | super.willReconnect()
105 | }
106 |
107 | override func didClose() {
108 | self.clearInvocationCallbacks(error: "Connection was disconnected before invocation result was received.")
109 | super.didClose()
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Hubs/HubInvocation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HubInvocation.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | private let kCallbackId = "I"
12 | private let kHub = "H"
13 | private let kMethod = "M"
14 | private let kArgs = "A"
15 | private let kState = "S"
16 |
17 | struct HubInvocation {
18 |
19 | let callbackId: String
20 | let hub: String
21 | let method: String
22 | let args: [Any]
23 | let state: [String: Any]
24 |
25 | init(callbackId: String, hub: String, method: String, args: [Any], state: [String: Any] = [:]) {
26 | self.callbackId = callbackId
27 | self.hub = hub
28 | self.method = method
29 | self.args = args
30 | self.state = state
31 | }
32 |
33 | init(jsonObject dict: [String: Any]) {
34 | callbackId = dict[kCallbackId] as? String ?? ""
35 | hub = dict[kHub] as? String ?? ""
36 | method = dict[kMethod] as? String ?? ""
37 | args = dict[kArgs] as? [Any] ?? []
38 | state = dict[kState] as? [String: Any] ?? [:]
39 | }
40 |
41 | func toJSONString() -> String? {
42 | let json: [String: Any] = [
43 | kCallbackId: callbackId,
44 | kHub: hub,
45 | kMethod: method,
46 | kArgs: args,
47 | kState: state
48 | ]
49 | return json.toJSONString()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Hubs/HubProxy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HubProxy.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class HubProxy: HubProxyProtocol {
12 |
13 | public var state = [String: Any]()
14 |
15 | private weak var connection: HubConnectionProtocol?
16 | private let hubName: String
17 | private var subscriptions = [String: Subscription]()
18 |
19 | // MARK: - Init
20 |
21 | public init(connection: HubConnectionProtocol, hubName: String) {
22 | self.connection = connection
23 | self.hubName = hubName
24 | }
25 |
26 | // MARK: - Subscribe
27 |
28 | public func on(eventName: String, handler: @escaping Subscription) -> Subscription? {
29 | guard !eventName.isEmpty else {
30 | NSException.raise(.invalidArgumentException, format: NSLocalizedString("Argument eventName is null", comment: "null event name exception"), arguments: getVaList(["nil"]))
31 | return nil
32 | }
33 |
34 | return self.subscriptions[eventName] ?? self.subscriptions.updateValue(handler, forKey: eventName) ?? handler
35 | }
36 |
37 | public func invokeEvent(eventName: String, withArgs args: [Any]) {
38 | if let subscription = self.subscriptions[eventName] {
39 | subscription(args)
40 | }
41 | }
42 |
43 | // MARK: - Publish
44 |
45 | public func invoke(method: String, withArgs args: [Any]) {
46 | self.invoke(method: method, withArgs: args, completionHandler: nil)
47 | }
48 |
49 | public func invoke(method: String, withArgs args: [Any], completionHandler: ((Any?, Error?) -> ())?) {
50 | guard !method.isEmpty else {
51 | NSException.raise(.invalidArgumentException, format: NSLocalizedString("Argument method is null", comment: "null event name exception"), arguments: getVaList(["nil"]))
52 | return
53 | }
54 |
55 | guard let connection = self.connection else { return }
56 |
57 | let callbackId = connection.registerCallback { result in
58 | guard let hubResult = result else { return }
59 | hubResult.state?.forEach { (key, value) in self.state[key] = value }
60 | completionHandler?(hubResult.result, nil)
61 | }
62 |
63 | let hubData = HubInvocation(callbackId: callbackId,
64 | hub: self.hubName,
65 | method: method,
66 | args: args,
67 | state: self.state)
68 |
69 | connection.send(object: hubData.toJSONString()!, completionHandler: completionHandler)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Hubs/HubResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HubResult.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | private let kId = "I"
12 | private let kResult = "R"
13 | private let kHubException = "H"
14 | private let kError = "E"
15 | private let kErrorData = "D"
16 | private let kState = "S"
17 |
18 | public struct HubResult {
19 | let id: String?
20 | let result: Any?
21 | let hubException: Bool
22 | let error: String?
23 | let errorData: Any?
24 | let state: [String: Any]?
25 |
26 | init(id: String? = nil, result: Any? = nil, hubException: Bool = false, error: String? = nil, errorData: Any? = nil, state: [String: Any]? = nil) {
27 | self.id = id
28 | self.result = result
29 | self.hubException = hubException
30 | self.error = error
31 | self.errorData = errorData
32 | self.state = state
33 | }
34 |
35 | init(jsonObject dict: [String: Any]) {
36 | id = dict[kId] as? String
37 | result = dict[kResult]
38 | hubException = dict[kHubException] as? Bool ?? false
39 | error = dict[kError] as? String
40 | errorData = dict[kErrorData]
41 | state = dict[kState] as? [String: Any]
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Infrastructure/ExceptionHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExceptionHelper.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class ExceptionHelper {
12 |
13 | static func isRequestAborted(error: NSError?) -> Bool {
14 | return error != nil && error!.code == NSURLErrorCancelled
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Infrastructure/Version.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Version.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public struct Version : Equatable, CustomStringConvertible {
13 | let major: UInt
14 | let minor: UInt
15 |
16 | public init(major: UInt = 0, minor: UInt = 0) {
17 | self.major = major
18 | self.minor = minor
19 | }
20 |
21 | public init?(string input: String) {
22 | let components = input.components(separatedBy: ".")
23 | guard (2...4) ~= components.count, let major = UInt(components[0]), let minor = UInt(components[1]) else {
24 | return nil }
25 |
26 | self.major = major
27 | self.minor = minor
28 | }
29 |
30 | public static func == (lhs: Version, rhs: Version) -> Bool {
31 | return lhs.major == rhs.major && lhs.minor == rhs.minor
32 | }
33 |
34 | public var description: String {
35 | return "\(self.major).\(self.minor)"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/KeepAliveData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeepAliveData.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class KeepAliveData {
12 | var lastKeepAlive: Date?
13 | var timeout: Double!
14 | var timeoutWarning: Double!
15 | var checkInterval: Double!
16 |
17 | init(timeout: Double) {
18 | self.timeout = timeout
19 | self.timeoutWarning = timeout * (2 / 3)
20 | self.checkInterval = timeout - self.timeoutWarning / 3.0
21 | }
22 |
23 | init(withLastKeepAlive lastKeepAlive: Date, timeout: Double, timeoutWarning: Double, checkInterval: Double) {
24 | self.lastKeepAlive = lastKeepAlive
25 | self.timeout = timeout
26 | self.timeoutWarning = timeoutWarning
27 | self.checkInterval = checkInterval
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/NegotiationResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NegotiationResponse.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | private let kConnectionId = "ConnectionId"
12 | private let kConnectionToken = "ConnectionToken"
13 | private let kUrl = "Url"
14 | private let kProtocolVersion = "ProtocolVersion"
15 | private let kDisconnectTimeout = "DisconnectTimeout"
16 | private let kTryWebSockets = "TryWebSockets"
17 | private let kKeepAliveTimeout = "KeepAliveTimeout"
18 | private let kTransportConnectTimeout = "TransportConnectTimeout"
19 |
20 | public struct NegotiationResponse {
21 | let connectionId: String
22 | let connectionToken: String
23 | let url: String
24 | let protocolVersion: String
25 | let disconnectTimeout: Double
26 | let tryWebSockets: Bool
27 | let keepAliveTimeout: Double?
28 | let transportConnectTimeout: Double?
29 |
30 | init(jsonObject dict: [String: Any]) {
31 | connectionId = dict[kConnectionId] as? String ?? ""
32 | connectionToken = dict[kConnectionToken] as? String ?? ""
33 | url = dict[kUrl] as? String ?? ""
34 | protocolVersion = dict[kProtocolVersion] as? String ?? ""
35 | disconnectTimeout = dict[kDisconnectTimeout] as? Double ?? 0.0
36 | tryWebSockets = dict[kTryWebSockets] as? Bool ?? false
37 | keepAliveTimeout = dict[kKeepAliveTimeout] as? Double
38 | transportConnectTimeout = dict[kTransportConnectTimeout] as? Double
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Protocols/ClientTransportProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ClientTransportProtocol.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol ClientTransportProtocol {
12 | var name: String? { get }
13 | var supportsKeepAlive: Bool { get }
14 | func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((_ response: NegotiationResponse?, _ error: Error?) -> ())?)
15 | func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((_ response: Any?, _ error: Error?) -> ())?)
16 | func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((_ response: Any?, _ error: Error?) -> ())?)
17 |
18 | func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?)
19 | func lostConnection(connection: ConnectionProtocol)
20 | }
21 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Protocols/ConnectionDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectionDelegate.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol ConnectionDelegate: class {
12 | func connectionDidOpen(connection: ConnectionProtocol)
13 | func connectionDidClose(connection: ConnectionProtocol)
14 | func connectionWillReconnect(connection: ConnectionProtocol)
15 | func connectionDidReconnect(connection: ConnectionProtocol)
16 | func connection(connection: ConnectionProtocol, didReceiveData data: Any)
17 | func connection(connection: ConnectionProtocol, didReceiveError error: Error)
18 | func connection(connection: ConnectionProtocol, didChangeState oldState: ConnectionState, newState: ConnectionState)
19 | func connectionDidSlow(connection: ConnectionProtocol)
20 | }
21 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Protocols/ConnectionProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectionProtocol.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import Alamofire
12 |
13 | public protocol ConnectionProtocol: class {
14 | var version: Version { get set }
15 | var transportConnectTimeout: Double { get set }
16 | var keepAliveData: KeepAliveData? { get set }
17 | var messageId: String? { get set }
18 | var groupsToken: String? { get set }
19 | var items: [String: Any] { get set }
20 | var connectionId: String? { get set }
21 | var connectionToken: String? { get set }
22 | var url: String { get }
23 | var queryString: [String: String]? { get }
24 | var state: ConnectionState { get }
25 | var transport: ClientTransportProtocol? { get }
26 | var headers: HTTPHeaders { get set }
27 | var sessionManager: SessionManager { get }
28 | var webSocketAllowsSelfSignedSSL: Bool { get set }
29 |
30 | func onSending() -> String?
31 |
32 | func changeState(oldState: ConnectionState, toState newState: ConnectionState) -> Bool
33 | func stop()
34 | func disconnect()
35 |
36 | func send(object: Any, completionHandler: ((Any?, Error?) -> ())?)
37 |
38 | func didReceiveData(data: Any)
39 | func didReceiveError(error: Error)
40 | func willReconnect()
41 | func didReconnect()
42 | func connectionDidSlow()
43 |
44 | func updateLastKeepAlive()
45 |
46 | func getRequest(url: URLConvertible, httpMethod: HTTPMethod, encoding: ParameterEncoding, parameters: Parameters?) -> DataRequest
47 | func getRequest(url: URLConvertible, httpMethod: HTTPMethod, encoding: ParameterEncoding, parameters: Parameters?, timeout: Double) -> DataRequest
48 | func getRequest(url: URLConvertible, httpMethod: HTTPMethod, encoding: ParameterEncoding, parameters: Parameters?, timeout: Double, headers: HTTPHeaders) -> DataRequest
49 | func processResponse(response: Data, shouldReconnect: inout Bool, disconnected: inout Bool)
50 | }
51 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Protocols/HubConnectionProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HubConnectionProtocol.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public typealias HubConnectionHubResultClosure = (HubResult?) -> ()
12 |
13 | public protocol HubConnectionProtocol: ConnectionProtocol {
14 | func registerCallback(callback: @escaping HubConnectionHubResultClosure) -> String
15 | func removeCallback(callbackId: String)
16 | }
17 |
--------------------------------------------------------------------------------
/SignalR-Swift/Client/Protocols/HubProxyProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HubProxyProtocol.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public typealias Subscription = ([Any]) -> ()
12 |
13 | protocol HubProxyProtocol {
14 | func on(eventName: String, handler: @escaping Subscription) -> Subscription?
15 |
16 | func invoke(method: String, withArgs args: [Any])
17 |
18 | func invoke(method: String, withArgs args: [Any], completionHandler: ((_ response: Any?, _ error: Error?) -> ())?)
19 | }
20 |
--------------------------------------------------------------------------------
/SignalR-Swift/Extensions/Dictionary+Json.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+Json.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Dictionary where Key: ExpressibleByStringLiteral {
12 | func toJSONString() -> String? {
13 | do {
14 | return String(data: try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted), encoding: .utf8)
15 | } catch {
16 | print(error.localizedDescription)
17 | }
18 |
19 | return nil
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SignalR-Swift/Extensions/String+Dictionary.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+Dictionary.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension String {
12 | func toDictionary() -> [String: Any]? {
13 | if let data = self.data(using: .utf8) {
14 | do {
15 | return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
16 | } catch {
17 | print(error.localizedDescription)
18 | }
19 | }
20 |
21 | return nil
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SignalR-Swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SignalR-Swift/Models/ReceivedMessage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Message.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct ReceivedMessage {
12 |
13 | let result: String?
14 | let shouldReconnect: Bool?
15 | let disconnected: Bool?
16 | let groupsToken: String?
17 | let messageId: String?
18 | let messages: [Any]?
19 |
20 | init?(jsonObject: Any) {
21 |
22 | guard let dict = jsonObject as? [String: Any] else { return nil }
23 |
24 | result = dict["I"] as? String
25 | shouldReconnect = dict["T"] as? Bool
26 | disconnected = dict["D"] as? Bool
27 | groupsToken = dict["G"] as? String
28 | messageId = dict["C"] as? String
29 | messages = dict["M"] as? [Any]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SignalR-Swift/SignalR-Swift.h:
--------------------------------------------------------------------------------
1 | //
2 | // SignalR-Swift.h
3 | // SignalR-Swift
4 | //
5 | // Created by Jordan Camara on 1/6/17.
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SignalR-Swift.
12 | FOUNDATION_EXPORT double SignalR_SwiftVersionNumber;
13 |
14 | //! Project version string for SignalR-Swift.
15 | FOUNDATION_EXPORT const unsigned char SignalR_SwiftVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SignalR-Swift/Transports/AutoTransport.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AutoTransport.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class AutoTransport: HttpTransport {
12 | var transports = [ClientTransportProtocol]()
13 | var transport: ClientTransportProtocol?
14 |
15 | override convenience init() {
16 | let transports = [
17 | WebSocketTransport(),
18 | ServerSentEventsTransport(),
19 | LongPollingTransport()
20 | ]
21 |
22 | self.init(withTransports: transports)
23 | }
24 |
25 | init(withTransports transports: [ClientTransportProtocol]) {
26 | self.transports = transports
27 | }
28 |
29 | // MARK: - Client Transport Protocol
30 |
31 | override public var name: String? {
32 | return self.transport?.name
33 | }
34 |
35 | override public var supportsKeepAlive: Bool {
36 | return self.transport?.supportsKeepAlive ?? false
37 | }
38 |
39 | override public func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((NegotiationResponse?, Error?) -> ())?) {
40 | super.negotiate(connection: connection, connectionData: connectionData) { [weak self] (response, error) in
41 | guard let strongRef = self else { return }
42 |
43 | if error == nil,
44 | let tryWebSockets = response?.tryWebSockets, !tryWebSockets,
45 | let invalidIndex = strongRef.transports.index(where: { $0.name == "webSockets" }) {
46 | strongRef.transports.remove(at: invalidIndex)
47 | }
48 |
49 | completionHandler?(response, error)
50 | }
51 | }
52 |
53 | override public func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
54 | self.start(connection: connection, connectionData: connectionData, transportIndex: 0, completionHandler: completionHandler)
55 | }
56 |
57 | func start(connection: ConnectionProtocol, connectionData: String?, transportIndex index: Int, completionHandler: ((String?, Error?) -> ())?) {
58 | let transport = self.transports[index]
59 | transport.start(connection: connection, connectionData: connectionData) { [weak self] (response, error) in
60 | guard let strongRef = self else { return }
61 |
62 | if error != nil {
63 | let nextIndex = index + 1
64 |
65 | if nextIndex < strongRef.transports.count {
66 | strongRef.start(connection: connection, connectionData: connectionData, transportIndex: nextIndex, completionHandler: completionHandler)
67 | } else {
68 | let userInfo = [
69 | NSLocalizedFailureReasonErrorKey: NSExceptionName.internalInconsistencyException.rawValue,
70 | NSLocalizedDescriptionKey: NSLocalizedString("No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.", comment: "no transport initialized")
71 | ]
72 |
73 | let error = NSError(domain: "com.autosoftdms.SignalR-Swift.\(type(of: self))", code: 0, userInfo: userInfo)
74 |
75 | completionHandler?(nil, error)
76 | }
77 | } else {
78 | strongRef.transport = transport
79 |
80 | completionHandler?(nil, nil)
81 | }
82 | }
83 | }
84 |
85 | override public func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
86 | self.transport?.send(connection: connection, data: data, connectionData: connectionData, completionHandler: completionHandler)
87 | }
88 |
89 | override public func lostConnection(connection: ConnectionProtocol) {
90 | self.transport?.lostConnection(connection: connection)
91 | }
92 |
93 | public override func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?) {
94 | self.transport?.abort(connection: connection, timeout: timeout, connectionData: connectionData)
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/SignalR-Swift/Transports/HttpTransport.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HttpTransport.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Alamofire
11 |
12 | public class HttpTransport: ClientTransportProtocol {
13 |
14 | public var name: String? {
15 | return ""
16 | }
17 |
18 | public var supportsKeepAlive: Bool {
19 | return false
20 | }
21 |
22 | var startedAbort: Bool = false
23 |
24 | public func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((NegotiationResponse?, Error?) -> ())?) {
25 | let url = connection.url.appending("negotiate")
26 |
27 | let parameters = self.getConnectionParameters(connection: connection, connectionData: connectionData)
28 |
29 | let encodedRequest = connection.getRequest(url: url, httpMethod: .get, encoding: URLEncoding.default, parameters: parameters, timeout: 30.0)
30 |
31 | encodedRequest.validate().responseJSON { (response: DataResponse) in
32 | switch response.result {
33 | case .success(let result):
34 | if let json = result as? [String: Any] {
35 | completionHandler?(NegotiationResponse(jsonObject: json), nil)
36 | }
37 | else {
38 | completionHandler?(nil, AFError.responseSerializationFailed(reason: .inputDataNil))
39 | }
40 | case .failure(let error):
41 | completionHandler?(nil, error)
42 | }
43 | }
44 | }
45 |
46 | public func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
47 |
48 | }
49 |
50 | public func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
51 | let url = connection.url.appending("send")
52 |
53 | let parameters = self.getConnectionParameters(connection: connection, connectionData: connectionData)
54 |
55 | var encodedRequestURL = url
56 | do {
57 | let originalRequest = try URLRequest(url: url, method: .get, headers: nil)
58 | encodedRequestURL = try URLEncoding.queryString.encode(originalRequest, with: parameters).url!.absoluteString
59 | } catch {
60 | }
61 |
62 | var requestParams = [String: Any]()
63 |
64 | if let dataString = data as? String {
65 | requestParams["data"] = dataString
66 | } else if let dataDict = data as? [String: Any] {
67 | requestParams = dataDict
68 | }
69 |
70 | let request = connection.getRequest(url: encodedRequestURL, httpMethod: .post, encoding: URLEncoding.httpBody, parameters: requestParams)
71 | request.validate().responseJSON { (response: DataResponse) in
72 | switch response.result {
73 | case .success(let result):
74 | connection.didReceiveData(data: result)
75 |
76 | if let handler = completionHandler {
77 | handler(result, nil)
78 | }
79 | case .failure(let error):
80 | connection.didReceiveError(error: error)
81 |
82 | if let handler = completionHandler {
83 | handler(nil, error)
84 | }
85 | }
86 | }
87 | }
88 |
89 | func completeAbort() {
90 | self.startedAbort = true
91 | }
92 |
93 | func tryCompleteAbort() -> Bool {
94 | return startedAbort
95 | }
96 |
97 | public func lostConnection(connection: ConnectionProtocol) {
98 |
99 | }
100 |
101 | public func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?) {
102 | guard timeout > 0, !self.startedAbort else { return }
103 |
104 | self.startedAbort = true
105 |
106 | let url = connection.url.appending("abort")
107 |
108 | let parameters = self.getConnectionParameters(connection: connection, connectionData: connectionData)
109 |
110 | let encodedRequest = connection.getRequest(url: url, httpMethod: .get, encoding: URLEncoding.default, parameters: parameters, timeout: 2.0)
111 |
112 | let request = connection.getRequest(url: encodedRequest.request!.url!.absoluteString, httpMethod: .post, encoding: URLEncoding.httpBody, parameters: nil)
113 | request.validate().response { response in
114 | if response.error != nil {
115 | self.completeAbort()
116 | }
117 | }
118 | }
119 |
120 | func getConnectionParameters(connection: ConnectionProtocol, connectionData: String?) -> [String: Any] {
121 | var parameters: [String: Any] = [
122 | "clientProtocol": connection.version.description,
123 | "transport": self.name ?? "",
124 | "connectionData": connectionData ?? "",
125 | "connectionToken": connection.connectionToken ?? "",
126 | ]
127 |
128 | if let queryString = connection.queryString {
129 | for (key, value) in queryString {
130 | parameters[key] = value
131 | }
132 | }
133 |
134 | return parameters
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/SignalR-Swift/Transports/LongPollingTransport.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LongPollingTransport.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Alamofire
11 |
12 | public class LongPollingTransport: HttpTransport {
13 | var reconnectDelay = 5.0
14 | var errorDelay = 2.0
15 | var pollingQueue = DispatchQueue(label: "com.autosoftdms.SignalR-Swift.serial")
16 |
17 | // MARK: - Client Transport Protocol
18 |
19 | override public var name: String? {
20 | return "longPolling"
21 | }
22 |
23 | override public var supportsKeepAlive: Bool {
24 | return false
25 | }
26 |
27 | override public func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((NegotiationResponse?, Error?) -> ())?) {
28 | super.negotiate(connection: connection, connectionData: connectionData, completionHandler: completionHandler)
29 | }
30 |
31 | override public func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
32 | self.poll(connection: connection, connectionData: connectionData, completionHandler: completionHandler)
33 | }
34 |
35 | override public func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
36 | super.send(connection: connection, data: data, connectionData: connectionData, completionHandler: completionHandler)
37 | }
38 |
39 | override public func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?) {
40 | super.abort(connection: connection, timeout: timeout, connectionData: connectionData)
41 | }
42 |
43 | override public func lostConnection(connection: ConnectionProtocol) {
44 |
45 | }
46 |
47 | // MARK: - Long Polling
48 |
49 | func poll(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((_ response: String?, _ error: Error?) -> ())?) {
50 | var canReconnect = true
51 |
52 | var url = connection.url
53 | if connection.messageId == nil {
54 | url = url.appending("connect")
55 | } else if self.isConnectionReconnecting(connection: connection) {
56 | url = url.appending("reconnect")
57 | } else {
58 | url = url.appending("poll")
59 | }
60 |
61 | self.delayConnectionReconnect(connection: connection, canReconnect: &canReconnect)
62 |
63 | var parameters: [String: Any] = [
64 | "transport": self.name!,
65 | "connectionToken": connection.connectionToken ?? "",
66 | "connectionData": connectionData ?? "",
67 | "groupsToken": connection.groupsToken ?? "",
68 | "messageId": connection.messageId ?? ""
69 | ]
70 |
71 | if let queryString = connection.queryString {
72 | for (key, value) in queryString {
73 | parameters[key] = value
74 | }
75 | }
76 |
77 | let encodedRequest = connection.getRequest(url: url, httpMethod: .get, encoding: URLEncoding.default, parameters: parameters, timeout: 240)
78 |
79 | _ = self.pollingQueue.sync {
80 | encodedRequest.validate().responseData(completionHandler: { [weak self, weak connection] response in
81 | guard let strongSelf = self, let strongConnection = connection else { return }
82 |
83 | switch response.result {
84 | case .success(let result):
85 |
86 | var shouldReconnect = false
87 | var disconnectedReceived = false
88 |
89 | strongConnection.processResponse(response: result, shouldReconnect: &shouldReconnect, disconnected: &disconnectedReceived)
90 |
91 | if let handler = completionHandler {
92 | handler(nil, nil)
93 | }
94 |
95 | if strongSelf.isConnectionReconnecting(connection: strongConnection) {
96 | strongSelf.connectionReconnect(connection: strongConnection, canReconnect: canReconnect)
97 | }
98 |
99 | if shouldReconnect {
100 | _ = Connection.ensureReconnecting(connection: strongConnection)
101 | }
102 |
103 | if disconnectedReceived {
104 | strongConnection.disconnect()
105 | }
106 |
107 | if !strongSelf.tryCompleteAbort() {
108 | canReconnect = true
109 | strongSelf.poll(connection: strongConnection, connectionData: connectionData, completionHandler: nil)
110 | }
111 | case .failure(let error):
112 | canReconnect = false
113 |
114 | _ = Connection.ensureReconnecting(connection: strongConnection)
115 |
116 | if !strongSelf.tryCompleteAbort() && !ExceptionHelper.isRequestAborted(error: (error as NSError)) {
117 | strongConnection.didReceiveError(error: error)
118 |
119 | canReconnect = true
120 |
121 | _ = BlockOperation(block: {
122 | strongSelf.poll(connection: strongConnection, connectionData: connectionData, completionHandler: nil)
123 | }).perform(#selector(BlockOperation.start), with: nil, afterDelay: strongSelf.errorDelay)
124 | } else {
125 | strongSelf.completeAbort()
126 | if let handler = completionHandler {
127 | handler(nil, error)
128 | }
129 | }
130 | }
131 | })
132 | }
133 | }
134 |
135 | func delayConnectionReconnect(connection: ConnectionProtocol, canReconnect: inout Bool) {
136 | if self.isConnectionReconnecting(connection: connection) {
137 | let canReconnectCopy = canReconnect
138 | if canReconnect {
139 | canReconnect = false
140 |
141 | _ = BlockOperation(block: { [weak self, weak connection] in
142 | guard let strongSelf = self, let strongConnection = connection else { return }
143 | strongSelf.connectionReconnect(connection: strongConnection, canReconnect: canReconnectCopy)
144 | }).perform(#selector(BlockOperation.start), with: nil, afterDelay: self.reconnectDelay)
145 | }
146 | }
147 | }
148 |
149 | func connectionReconnect(connection: ConnectionProtocol, canReconnect: Bool) {
150 | if canReconnect {
151 | if connection.changeState(oldState: .reconnecting, toState: .connected) {
152 | connection.didReconnect()
153 | }
154 | }
155 | }
156 |
157 | func isConnectionReconnecting(connection: ConnectionProtocol) -> Bool {
158 | return connection.state == .reconnecting
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/SignalR-Swift/Transports/ServerSentEvents/ChunkBuffer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChunkBuffer.swift
3 | // SignalR-Swift
4 | //
5 | // Created by Vladimir Kushelkov on 21/07/2017.
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | final class ChunkBuffer {
12 | private var buffer = String()
13 |
14 | var hasChunks: Bool {
15 | return !buffer.isEmpty
16 | }
17 |
18 | func append(data: Data) {
19 | guard let newChunk = String(data: data, encoding: .utf8), !newChunk.isEmpty else { return }
20 | buffer.append(newChunk)
21 | }
22 |
23 | func readLine() -> String? {
24 | var line: String?
25 |
26 | while let endIndex = buffer.index(of: "\n") {
27 | let substring = buffer[.. ServerSentEvent {
25 | return ServerSentEvent(event: Event(rawValue: fields["event"]!)!,
26 | identifier: fields["id"],
27 | data: fields["data"],
28 | retry: fields["retry"],
29 | userInfo: nil)
30 | }
31 |
32 | static func tryParse(line: String) -> ServerSentEvent? {
33 | if line.hasPrefix("data:") {
34 | let data = line["data:".endIndex.. ()
13 |
14 | public class ServerSentEventsTransport: HttpTransport {
15 | private var stop = false
16 | private var connectTimeoutOperation: BlockOperation?
17 | private var completionHandler: CompletionHandler?
18 | private let sseQueue = DispatchQueue(label: "com.autosoftdms.SignalR-Swift.serverSentEvents", qos: .userInitiated)
19 |
20 | var reconnectDelay: TimeInterval = 2.0
21 |
22 | override public var name: String? {
23 | return "serverSentEvents"
24 | }
25 |
26 | override public var supportsKeepAlive: Bool {
27 | return true
28 | }
29 |
30 | override public func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((NegotiationResponse?, Error?) -> ())?) {
31 | super.negotiate(connection: connection, connectionData: connectionData, completionHandler: nil)
32 | }
33 |
34 | override public func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
35 | self.completionHandler = completionHandler
36 |
37 | self.connectTimeoutOperation = BlockOperation { [weak self] in
38 | guard let strongSelf = self, let completionHandler = strongSelf.completionHandler else { return }
39 |
40 | let userInfo = [
41 | NSLocalizedDescriptionKey: NSLocalizedString("Connection timed out.", comment: "timeout error description"),
42 | NSLocalizedFailureReasonErrorKey: NSLocalizedString("Connection did not receive initialized message before the timeout.", comment: "timeout error reason"),
43 | NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString("Retry or switch transports.", comment: "timeout error retry suggestion")
44 | ]
45 | let error = NSError(domain: "com.autosoftdms.SignalR-Swift.\(type(of: strongSelf))", code: NSURLErrorTimedOut, userInfo: userInfo)
46 | completionHandler(nil, error)
47 | strongSelf.completionHandler = nil
48 | }
49 |
50 | self.connectTimeoutOperation!.perform(#selector(BlockOperation.start), with: nil, afterDelay: connection.transportConnectTimeout)
51 |
52 | self.open(connection: connection, connectionData: connectionData, isReconnecting: false)
53 | }
54 |
55 | override public func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
56 | super.send(connection: connection, data: data, connectionData: connectionData, completionHandler: completionHandler)
57 | }
58 |
59 | override public func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?) {
60 | self.stop = true
61 | super.abort(connection: connection, timeout: timeout, connectionData: connectionData)
62 | }
63 |
64 | override public func lostConnection(connection: ConnectionProtocol) {
65 |
66 | }
67 |
68 | // MARK: - SSE Transport
69 |
70 | private let buffer = ChunkBuffer()
71 |
72 | private func open(connection: ConnectionProtocol, connectionData: String?, isReconnecting: Bool) {
73 | var parameters = connection.queryString ?? [:]
74 | parameters["transport"] = self.name!
75 | parameters["connectionToken"] = connection.connectionToken ?? ""
76 | parameters["messageId"] = connection.messageId ?? ""
77 | parameters["groupsToken"] = connection.groupsToken ?? ""
78 | parameters["connectionData"] = connectionData ?? ""
79 |
80 | let url = isReconnecting ? connection.url.appending("reconnect") : connection.url.appending("connect")
81 |
82 | connection.getRequest(url: url,
83 | httpMethod: .get,
84 | encoding: URLEncoding.default,
85 | parameters: parameters,
86 | timeout: 240,
87 | headers: ["Connection": "Keep-Alive"])
88 | .stream { [weak self] data in
89 | self?.sseQueue.async { [weak connection] in
90 | guard let strongSelf = self, let strongConnection = connection else { return }
91 |
92 | strongSelf.buffer.append(data: data)
93 |
94 | while let line = strongSelf.buffer.readLine() {
95 | guard let message = ServerSentEvent.tryParse(line: line) else { continue }
96 | DispatchQueue.main.async { strongSelf.process(message: message, connection: strongConnection) }
97 | }
98 | }
99 | }.validate().response() { [weak self, weak connection] dataResponse in
100 | guard let strongSelf = self, let strongConnection = connection else { return }
101 |
102 | strongSelf.cancelTimeoutOperation()
103 |
104 | if let error = dataResponse.error as NSError?, error.code != NSURLErrorCancelled {
105 | strongConnection.didReceiveError(error: error)
106 | }
107 |
108 | if strongSelf.stop {
109 | strongSelf.completeAbort()
110 | } else if !strongSelf.tryCompleteAbort() && !isReconnecting {
111 | strongSelf.reconnect(connection: strongConnection, data: connectionData)
112 | }
113 | }
114 | }
115 |
116 | private func process(message: ServerSentEvent, connection: ConnectionProtocol) {
117 | guard message.event == .data else { return }
118 |
119 | if message.data == "initialized" {
120 | if connection.changeState(oldState: .reconnecting, toState: .connected) {
121 | connection.didReconnect()
122 | }
123 |
124 | return
125 | }
126 |
127 | guard let data = message.data?.data(using: .utf8) else { return }
128 |
129 | var shouldReconnect = false
130 | var disconnected = false
131 | connection.processResponse(response: data, shouldReconnect: &shouldReconnect, disconnected: &disconnected)
132 |
133 | cancelTimeoutOperation()
134 |
135 | if disconnected {
136 | stop = true
137 | connection.disconnect()
138 | }
139 | }
140 |
141 | private func cancelTimeoutOperation() {
142 | guard let completionHandler = self.completionHandler,
143 | let timeoutOperation = connectTimeoutOperation else { return }
144 |
145 | NSObject.cancelPreviousPerformRequests(withTarget: timeoutOperation, selector: #selector(BlockOperation.start), object: nil)
146 | connectTimeoutOperation = nil
147 | completionHandler(nil, nil)
148 | self.completionHandler = nil
149 | }
150 |
151 | private func reconnect(connection: ConnectionProtocol, data: String?) {
152 | _ = BlockOperation { [weak self, weak connection] in
153 | if let strongSelf = self, let strongConnection = connection,
154 | strongConnection.state != .disconnected, Connection.ensureReconnecting(connection: strongConnection) {
155 | strongSelf.open(connection: strongConnection, connectionData: data, isReconnecting: true)
156 | }
157 | }.perform(#selector(BlockOperation.start), with: nil, afterDelay: self.reconnectDelay)
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/SignalR-Swift/Transports/WebSocketTransport.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebSocketTransport.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Starscream
11 | import Alamofire
12 |
13 | private typealias WebSocketStartClosure = (String?, Error?) -> ()
14 |
15 | public class WebSocketTransport: HttpTransport, WebSocketDelegate {
16 | var reconnectDelay = 2.0
17 | private var connectionInfo: WebSocketConnectionInfo?
18 | private var webSocket: WebSocket?
19 | private var startClosure: WebSocketStartClosure?
20 | private var connectTimeoutOperation: BlockOperation?
21 |
22 | override public var name: String? {
23 | return "webSockets"
24 | }
25 |
26 | override public var supportsKeepAlive: Bool {
27 | return true
28 | }
29 |
30 | override public func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((NegotiationResponse?, Error?) -> ())?) {
31 | super.negotiate(connection: connection, connectionData: connectionData, completionHandler: completionHandler)
32 | }
33 |
34 | override public func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
35 | self.connectionInfo = WebSocketConnectionInfo(connection: connection, data: connectionData)
36 |
37 | // perform connection
38 | self.performConnect(completionHandler: completionHandler)
39 | }
40 |
41 | override public func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((Any?, Error?) -> ())?) {
42 | if let dataString = data as? String {
43 | self.webSocket?.write(string: dataString)
44 | } else if let dataDict = data as? [String: Any] {
45 | self.webSocket?.write(string: dataDict.toJSONString()!)
46 | }
47 |
48 | completionHandler?(nil, nil)
49 | }
50 |
51 | override public func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?) {
52 | self.stopWebSocket()
53 | super.abort(connection: connection, timeout: timeout, connectionData: connectionData)
54 | }
55 |
56 | override public func lostConnection(connection: ConnectionProtocol) {
57 | self.stopWebSocket()
58 |
59 | if self.tryCompleteAbort() {
60 | return
61 | }
62 |
63 | self.reconnect(connection: self.connectionInfo?.connection)
64 | }
65 |
66 | private func stopWebSocket() {
67 | self.webSocket?.delegate = nil
68 | self.webSocket?.disconnect()
69 | self.webSocket = nil
70 | }
71 |
72 | // MARK: - WebSockets transport
73 |
74 | func performConnect(completionHandler: ((_ response: String?, _ error: Error?) -> ())?) {
75 | self.performConnect(reconnecting: false, completionHandler: completionHandler)
76 | }
77 |
78 | func performConnect(reconnecting: Bool, completionHandler: ((_ response: String?, _ error: Error?) -> ())?) {
79 | let connection = self.connectionInfo?.connection
80 | var parameters: [String: Any] = [
81 | "transport": self.name!,
82 | "connectionToken": connection?.connectionToken ?? "",
83 | "messageId": connection?.messageId ?? "",
84 | "groupsToken": connection?.groupsToken ?? "",
85 | "connectionData": self.connectionInfo?.data ?? ""
86 | ]
87 |
88 | if let queryString = self.connectionInfo?.connection?.queryString {
89 | for (key, value) in queryString {
90 | parameters[key] = value
91 | }
92 | }
93 |
94 | var urlComponents = URLComponents(string: connection!.url)
95 | if let urlScheme = urlComponents?.scheme {
96 | if urlScheme.hasPrefix("https") {
97 | urlComponents?.scheme = "wss"
98 | } else if urlScheme.hasPrefix("http") {
99 | urlComponents?.scheme = "ws"
100 | }
101 | }
102 |
103 | do {
104 | let baseUrl = try urlComponents?.asURL()
105 |
106 | let url = reconnecting ? baseUrl!.absoluteString.appending("reconnect") : baseUrl!.absoluteString.appending("connect")
107 |
108 | let request = connection?.getRequest(url: url, httpMethod: .get, encoding: URLEncoding.default, parameters: parameters, timeout: 30)
109 |
110 | self.startClosure = completionHandler
111 | if let startClosure = self.startClosure {
112 | self.connectTimeoutOperation = BlockOperation(block: { [weak self] in
113 | guard let strongSelf = self else { return }
114 |
115 | let userInfo = [
116 | NSLocalizedDescriptionKey: NSLocalizedString("Connection timed out.", comment: "timeout error description"),
117 | NSLocalizedFailureReasonErrorKey: NSLocalizedString("Connection did not receive initialized message before the timeout.", comment: "timeout error reason"),
118 | NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString("Retry or switch transports.", comment: "timeout error retry suggestion")
119 | ]
120 | let error = NSError(domain: "com.autosoftdms.SignalR-Swift.\(type(of: strongSelf))", code: NSURLErrorTimedOut, userInfo: userInfo)
121 | strongSelf.stopWebSocket()
122 |
123 | strongSelf.startClosure = nil
124 | startClosure(nil, error)
125 | })
126 |
127 | self.connectTimeoutOperation?.perform(#selector(BlockOperation.start), with: nil, afterDelay: connection!.transportConnectTimeout)
128 | }
129 |
130 | if let encodedRequest = request?.request {
131 | self.webSocket = WebSocket(request: encodedRequest)
132 | self.webSocket!.disableSSLCertValidation = connection?.webSocketAllowsSelfSignedSSL ?? false
133 | self.webSocket!.delegate = self
134 | self.webSocket!.connect()
135 | }
136 | } catch {
137 |
138 | }
139 | }
140 |
141 | func reconnect(connection: ConnectionProtocol?) {
142 | _ = BlockOperation { [weak self] in
143 | if let strongSelf = self, let connection = connection, Connection.ensureReconnecting(connection: connection) {
144 | strongSelf.performConnect(reconnecting: true, completionHandler: nil)
145 | }
146 | }.perform(#selector(BlockOperation.start), with: nil, afterDelay: self.reconnectDelay)
147 | }
148 |
149 | // MARK: - WebSocketDelegate
150 |
151 | public func websocketDidConnect(socket: WebSocketClient){
152 | if let connection = self.connectionInfo?.connection, connection.changeState(oldState: .reconnecting, toState: .connected) {
153 | connection.didReconnect()
154 | }
155 | }
156 |
157 | public func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
158 | if let error = error {
159 | webSocketError(error)
160 | }
161 | else if !self.tryCompleteAbort() {
162 | self.reconnect(connection: self.connectionInfo?.connection)
163 | }
164 | }
165 |
166 | private func webSocketError(_ error: Error) {
167 | if let startClosure = self.startClosure, let connectTimeoutOperation = self.connectTimeoutOperation {
168 | NSObject.cancelPreviousPerformRequests(withTarget: connectTimeoutOperation, selector: #selector(BlockOperation.start), object: nil)
169 |
170 | self.connectTimeoutOperation = nil
171 | self.stopWebSocket()
172 |
173 | self.startClosure = nil
174 | startClosure(nil, error)
175 | } else if !self.startedAbort {
176 | self.reconnect(connection: self.connectionInfo?.connection)
177 | }
178 | }
179 |
180 | public func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
181 | var timedOut = false
182 | var disconnected = false
183 |
184 | if let connection = self.connectionInfo?.connection, let data = text.data(using: .utf8) {
185 | connection.processResponse(response: data, shouldReconnect: &timedOut, disconnected: &disconnected)
186 | }
187 |
188 | if let startClosure = self.startClosure, let connectTimeoutOperation = self.connectTimeoutOperation {
189 | NSObject.cancelPreviousPerformRequests(withTarget: connectTimeoutOperation, selector: #selector(BlockOperation.start), object: nil)
190 | self.connectTimeoutOperation = nil
191 |
192 | self.startClosure = nil
193 | startClosure(nil, nil)
194 | }
195 |
196 | if disconnected {
197 | self.connectionInfo?.connection?.disconnect()
198 | self.stopWebSocket()
199 | }
200 | }
201 |
202 | public func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/SignalR-Swift/Transports/WebSockets/WebSocketConnectionInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebSocketConnectionInfo.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class WebSocketConnectionInfo {
12 | weak var connection: ConnectionProtocol?
13 | var data: String?
14 |
15 | init(connection: ConnectionProtocol, data: String?) {
16 | self.connection = connection
17 | self.data = data
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SignalR-SwiftTests/Connection/ConnectionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConnectionTests.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Quick
11 | import Nimble
12 | import Mockit
13 | import XCTest
14 | @testable import SignalRSwift
15 |
16 | class ConnectionTests: QuickSpec {
17 | var connection: Connection!
18 | var mockClientTransport: MockClientTransport!
19 |
20 | override func spec() {
21 | beforeEach {
22 | self.mockClientTransport = MockClientTransport(testCase: self)
23 | self.connection = Connection(withUrl: "http://localhost:0000")
24 | }
25 |
26 | it("should cause a closed event when transport error occurs") {
27 | self.connection.start(transport: self.mockClientTransport)
28 | self.expectation(description: "gets closed when transport errors out")
29 |
30 | self.waitForExpectations(timeout: 5.0, handler: { error in
31 | if let theError = error {
32 | print("Sub-Timeout Error: \(theError)")
33 | }
34 | })
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SignalR-SwiftTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SignalR-SwiftTests/Mocks/MockClientTransport.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockClientTransport.swift
3 | // SignalR-Swift
4 | //
5 | //
6 | // Copyright © 2017 Jordan Camara. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Mockit
11 | import XCTest
12 | @testable import SignalRSwift
13 |
14 | class MockClientTransport: ClientTransportProtocol, Mock {
15 | public var callHandler: CallHandler
16 |
17 | init(testCase: XCTestCase) {
18 | self.callHandler = CallHandlerImpl(withTestCase: testCase)
19 | }
20 |
21 | func instanceType() -> MockClientTransport {
22 | return self
23 | }
24 |
25 | var name: String? {
26 | return self.callHandler.accept("", ofFunction: #function, atFile: #file, inLine: #line, withArgs: self.name) as! String?
27 | }
28 |
29 | var supportsKeepAlive: Bool {
30 | return self.callHandler.accept(true, ofFunction: #function, atFile: #file, inLine: #line, withArgs: self.supportsKeepAlive) as! Bool
31 | }
32 |
33 | func negotiate(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((_ response: NegotiationResponse?, _ error: Error?) -> ())?) {
34 | self.callHandler.accept(nil, ofFunction: #function, atFile: #file, inLine: #line, withArgs: connection, connectionData, completionHandler)
35 | }
36 |
37 | func start(connection: ConnectionProtocol, connectionData: String?, completionHandler: ((_ response: Any?, _ error: Error?) -> ())?) {
38 | self.callHandler.accept(nil, ofFunction: #function, atFile: #file, inLine: #line, withArgs: connection, connectionData, completionHandler)
39 | }
40 |
41 | func send(connection: ConnectionProtocol, data: Any, connectionData: String?, completionHandler: ((_ response: Any?, _ error: Error?) -> ())?) {
42 | self.callHandler.accept(nil, ofFunction: #function, atFile: #file, inLine: #line, withArgs: connection, connectionData, completionHandler)
43 | }
44 |
45 | func abort(connection: ConnectionProtocol, timeout: Double, connectionData: String?) {
46 | self.callHandler.accept(nil, ofFunction: #function, atFile: #file, inLine: #line, withArgs: connection, timeout, connectionData)
47 | }
48 |
49 | func lostConnection(connection: ConnectionProtocol) {
50 | self.callHandler.accept(nil, ofFunction: #function, atFile: #file, inLine: #line, withArgs: connection)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/SignalRSwift.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint SignalR-Swift.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | #
13 | # These will help people to find your library, and whilst it
14 | # can feel like a chore to fill in it's definitely to your advantage. The
15 | # summary should be tweet-length, and the description more in depth.
16 | #
17 |
18 | s.name = "SignalRSwift"
19 | s.version = "2.0.3"
20 | s.summary = "A SignalR client library for iOS written in Swift"
21 |
22 | # This description is used to generate tags and improve search results.
23 | # * Think: What does it do? Why did you write it? What is the focus?
24 | # * Try to keep it short, snappy and to the point.
25 | # * Write the description between the DESC delimiters below.
26 | # * Finally, don't worry about the indent, CocoaPods strips it!
27 | s.description = "This is a signalR client written purely in swift using Alamofire, SwiftWebSockets and ObjectMapper"
28 |
29 | s.homepage = "https://github.com/AutosoftDMS/SignalR-Swift"
30 |
31 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
32 | #
33 | # Licensing your code is important. See http://choosealicense.com for more info.
34 | # CocoaPods will detect a license file if there is a named LICENSE*
35 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
36 | #
37 |
38 | s.license = "MIT"
39 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
40 |
41 |
42 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
43 | #
44 | # Specify the authors of the library, with email addresses. Email addresses
45 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
46 | # accepts just a name if you'd rather not provide an email address.
47 | #
48 | # Specify a social_media_url where others can refer to, for example a twitter
49 | # profile URL.
50 | #
51 |
52 | s.author = { "Jordan Camara" => "jcamara@autosoftdms.com" }
53 |
54 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
55 | #
56 | # If this Pod runs only on iOS or OS X, then specify the platform and
57 | # the deployment target. You can optionally include the target after the platform.
58 | #
59 |
60 | s.platform = :ios, "8.0"
61 |
62 | s.source = { :git => "https://github.com/AutosoftDMS/SignalR-Swift.git", :tag => "#{s.version}" }
63 |
64 | s.source_files = "SignalR-Swift/**/*.swift"
65 | s.exclude_files = "Classes/Exclude"
66 |
67 | s.dependency "Alamofire", "~> 4.2"
68 | s.dependency "Starscream", "~> 3.0"
69 |
70 | end
71 |
--------------------------------------------------------------------------------