Skip to content

Commit d5ee8b7

Browse files
authored
Merge pull request #13 from reloni/develop
Single NSURLSession
2 parents b2b174c + 38252b8 commit d5ee8b7

13 files changed

+295
-211
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ script:
2525
- set -o pipefail && xcodebuild -scheme "$FRAMEWORK_SCHEME" -project "$PROJECT" -sdk "$SDK" -configuration Debug ONLY_ACTIVE_ARCH=YES -destination "$DESTINATION_PLATFORM" -enableCodeCoverage YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES clean test | xcpretty -c
2626

2727
after_success:
28-
- bash <(curl -s https://codecov.io/bash)
28+
- bash <(curl -s https://codecov.io/bash) -J '^RxHttpClient$'

RxHttpClient.xcodeproj/project.pbxproj

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@
111111
isa = PBXGroup;
112112
children = (
113113
6EFB9EE71D2A575A00E30A5D /* Result.swift */,
114+
6EFB9ED81D2A53FD00E30A5D /* StreamDataTask.swift */,
114115
6EFB9ED21D2A53FD00E30A5D /* CacheProvider.swift */,
115116
6EFB9ED31D2A53FD00E30A5D /* HttpClient.swift */,
116117
6EFB9ED41D2A53FD00E30A5D /* HttpExtensions.swift */,
117118
6EFB9ED51D2A53FD00E30A5D /* HttpUtilities.swift */,
118119
6EFB9ED71D2A53FD00E30A5D /* NSURLSessionDataEventsObserver.swift */,
119-
6EFB9ED81D2A53FD00E30A5D /* StreamDataTask.swift */,
120120
6EFB9EE51D2A563000E30A5D /* MimeTypeConverter.swift */,
121121
6EFB9EBD1D2A4E2600E30A5D /* Info.plist */,
122122
6EFB9EBB1D2A4E2600E30A5D /* RxHttpClient.h */,
@@ -163,7 +163,6 @@
163163
6EFB9EB41D2A4E2600E30A5D /* Frameworks */,
164164
6EFB9EB51D2A4E2600E30A5D /* Headers */,
165165
6EFB9EB61D2A4E2600E30A5D /* Resources */,
166-
6EFB9EE41D2A544B00E30A5D /* Copy carthage frameworks */,
167166
);
168167
buildRules = (
169168
);
@@ -263,22 +262,6 @@
263262
shellPath = /bin/sh;
264263
shellScript = "/usr/local/bin/carthage copy-frameworks";
265264
};
266-
6EFB9EE41D2A544B00E30A5D /* Copy carthage frameworks */ = {
267-
isa = PBXShellScriptBuildPhase;
268-
buildActionMask = 2147483647;
269-
files = (
270-
);
271-
inputPaths = (
272-
"$(SRCROOT)/Dependencies/iOS/RxSwift.framework",
273-
"$(SRCROOT)/Dependencies/iOS/RxCocoa.framework",
274-
);
275-
name = "Copy carthage frameworks";
276-
outputPaths = (
277-
);
278-
runOnlyForDeploymentPostprocessing = 0;
279-
shellPath = /bin/sh;
280-
shellScript = "/usr/local/bin/carthage copy-frameworks";
281-
};
282265
/* End PBXShellScriptBuildPhase section */
283266

284267
/* Begin PBXSourcesBuildPhase section */

RxHttpClient/HttpClient.swift

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,69 +8,83 @@ public enum HttpRequestResult {
88
}
99

1010
public protocol HttpClientType {
11-
var httpUtilities: HttpUtilitiesType { get }
12-
func loadData(request: NSMutableURLRequestType) -> Observable<HttpRequestResult>
13-
func loadStreamData(request: NSMutableURLRequestType, cacheProvider: CacheProviderType?) -> Observable<StreamTaskResult>
11+
func createUrlRequest(url: NSURL) -> NSMutableURLRequestType
12+
func createUrlRequest(url: NSURL, headers: [String: String]?) -> NSMutableURLRequestType
13+
func loadData(request: NSURLRequestType) -> Observable<HttpRequestResult>
14+
func loadStreamData(request: NSURLRequestType, cacheProvider: CacheProviderType?) -> Observable<StreamTaskResult>
15+
func createStreamDataTask(request: NSURLRequestType, cacheProvider: CacheProviderType?) -> StreamDataTaskType
1416
}
1517

1618
public class HttpClient {
17-
public let httpUtilities: HttpUtilitiesType
19+
internal let httpUtilities: HttpUtilitiesType
1820
internal let scheduler = SerialDispatchQueueScheduler(globalConcurrentQueueQOS: DispatchQueueSchedulerQOS.Utility)
21+
internal let sessionConfiguration: NSURLSessionConfiguration
22+
internal let shouldInvalidateSession: Bool
1923

20-
public init(httpUtilities: HttpUtilitiesType = HttpUtilities()) {
21-
24+
internal lazy var urlSession: NSURLSessionType = {
25+
return self.httpUtilities.createUrlSession(self.sessionConfiguration, delegate: self.sessionObserver as? NSURLSessionDataDelegate, queue: nil)
26+
}()
27+
28+
internal lazy var sessionObserver: NSURLSessionDataEventsObserverType = {
29+
return self.httpUtilities.createUrlSessionStreamObserver()
30+
}()
31+
32+
internal init(sessionConfiguration: NSURLSessionConfiguration, httpUtilities: HttpUtilitiesType) {
33+
self.httpUtilities = httpUtilities
34+
self.sessionConfiguration = sessionConfiguration
35+
shouldInvalidateSession = true
36+
}
37+
38+
internal init(urlSession: NSURLSessionType, httpUtilities: HttpUtilitiesType) {
2239
self.httpUtilities = httpUtilities
40+
shouldInvalidateSession = false
41+
self.sessionConfiguration = urlSession.configuration
42+
self.urlSession = urlSession
43+
}
44+
45+
public convenience init(urlSession: NSURLSessionType) {
46+
self.init(urlSession: urlSession, httpUtilities: HttpUtilities())
47+
}
48+
49+
public convenience init(sessionConfiguration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()) {
50+
self.init(sessionConfiguration: sessionConfiguration, httpUtilities: HttpUtilities())
51+
}
52+
53+
deinit {
54+
guard shouldInvalidateSession else { return }
55+
urlSession.invalidateAndCancel()
2356
}
2457
}
2558

2659
extension HttpClient : HttpClientType {
27-
public func loadData(request: NSMutableURLRequestType)
28-
-> Observable<HttpRequestResult> {
29-
return Observable.create { [weak self] observer in
30-
guard let object = self else { observer.onCompleted(); return NopDisposable.instance }
31-
32-
let task = object.httpUtilities.createStreamDataTask(NSUUID().UUIDString,
33-
request: request, sessionConfiguration: NSURLSession.defaultConfig, cacheProvider: nil)
34-
35-
let receivedData = NSMutableData()
36-
37-
let disposable = task.taskProgress.catchError { error in
38-
observer.onNext(.error(error))
39-
observer.onCompleted()
40-
return Observable.empty()
41-
}.doOnCompleted { observer.onCompleted() }.bindNext { result in
42-
if case Result.success(let box) = result {
43-
if case StreamTaskEvents.ReceiveData(let data) = box.value {
44-
receivedData.appendData(data)
45-
} else if case StreamTaskEvents.Success = box.value {
46-
if receivedData.length > 0 {
47-
observer.onNext(.successData(receivedData))
48-
} else {
49-
observer.onNext(.success)
50-
}
51-
}
52-
} else if case Result.error(let error) = result {
53-
observer.onNext(.error(error))
54-
}
55-
}
56-
57-
task.resume()
60+
public func createUrlRequest(url: NSURL, headers: [String: String]?) -> NSMutableURLRequestType {
61+
return httpUtilities.createUrlRequest(url, headers: headers)
62+
}
63+
64+
public func createUrlRequest(url: NSURL) -> NSMutableURLRequestType {
65+
return createUrlRequest(url, headers: nil)
66+
}
67+
68+
public func loadData(request: NSURLRequestType) -> Observable<HttpRequestResult> {
69+
return loadStreamData(request, cacheProvider: MemoryCacheProvider(uid: NSUUID().UUIDString)).flatMapLatest { result -> Observable<HttpRequestResult> in
70+
switch result {
71+
case Result.error(let error): return Observable.just(.error(error))
72+
case Result.success(let box):
73+
guard case StreamTaskEvents.Success(let cache) = box.value else { return Observable.empty() }
5874

59-
return AnonymousDisposable {
60-
task.cancel()
61-
disposable.dispose()
62-
}
63-
}.observeOn(scheduler).shareReplay(0)
75+
guard let cacheProvider = cache where cacheProvider.currentDataLength > 0 else { return Observable.just(.success) }
76+
77+
return Observable.just(.successData(cacheProvider.getCurrentData()))
78+
}
79+
}.observeOn(scheduler).shareReplay(0)
6480
}
6581

66-
public func loadStreamData(request: NSMutableURLRequestType, cacheProvider: CacheProviderType?)
67-
-> Observable<StreamTaskResult> {
82+
public func loadStreamData(request: NSURLRequestType, cacheProvider: CacheProviderType?) -> Observable<StreamTaskResult> {
6883
return Observable.create { [weak self] observer in
6984
guard let object = self else { observer.onCompleted(); return NopDisposable.instance }
7085

71-
let task = object.httpUtilities.createStreamDataTask(NSUUID().UUIDString, request: request, sessionConfiguration: NSURLSession.defaultConfig,
72-
cacheProvider: cacheProvider)
73-
86+
let task = object.createStreamDataTask(request, cacheProvider: cacheProvider)
87+
7488
let disposable = task.taskProgress.catchError { error in
7589
observer.onNext(Result.error(error))
7690
observer.onCompleted()
@@ -91,4 +105,13 @@ extension HttpClient : HttpClientType {
91105
}
92106
}.observeOn(scheduler).shareReplay(0)
93107
}
108+
109+
public func createStreamDataTask(request: NSURLRequestType, cacheProvider: CacheProviderType?) -> StreamDataTaskType {
110+
let dataTask = urlSession.dataTaskWithRequest(request)
111+
return httpUtilities.createStreamDataTask(NSUUID().UUIDString,
112+
dataTask: dataTask,
113+
httpClient: self,
114+
sessionEvents: sessionObserver.sessionEvents,
115+
cacheProvider: cacheProvider)
116+
}
94117
}

RxHttpClient/HttpExtensions.swift

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ extension NSURLResponse : NSURLResponseType { }
2121

2222
// NSURLRequestProtocol
2323
public protocol NSURLRequestType {
24+
var URL: NSURL? { get }
2425
var HTTPMethod: String? { get }
26+
var allHTTPHeaderFields: [String: String]? { get }
2527
}
2628
extension NSURLRequest : NSURLRequestType { }
2729

2830

2931
// NSMutableURLRequestProtocol
3032
public protocol NSMutableURLRequestType : NSURLRequestType {
3133
func addValue(value: String, forHTTPHeaderField: String)
32-
var URL: NSURL? { get }
33-
var allHTTPHeaderFields: [String: String]? { get }
3434
func setHttpMethod(method: String)
3535
}
3636
extension NSMutableURLRequest : NSMutableURLRequestType {
@@ -40,19 +40,21 @@ extension NSMutableURLRequest : NSMutableURLRequestType {
4040
}
4141

4242

43-
public protocol NSURLSessionTaskType { }
43+
public protocol NSURLSessionTaskType {
44+
func isEqual(object: AnyObject?) -> Bool
45+
}
4446
extension NSURLSessionTask : NSURLSessionTaskType { }
4547

4648
// NSURLSessionDataTaskProtocol
4749
public protocol NSURLSessionDataTaskType : NSURLSessionTaskType {
4850
func resume()
4951
func suspend()
5052
func cancel()
51-
func getOriginalMutableUrlRequest() -> NSMutableURLRequestType?
53+
func getOriginalUrlRequest() -> NSURLRequestType?
5254
}
5355
extension NSURLSessionDataTask : NSURLSessionDataTaskType {
54-
public func getOriginalMutableUrlRequest() -> NSMutableURLRequestType? {
55-
return originalRequest as? NSMutableURLRequestType
56+
public func getOriginalUrlRequest() -> NSURLRequestType? {
57+
return originalRequest as? NSURLRequestType
5658
}
5759
}
5860

@@ -63,19 +65,19 @@ public protocol NSURLSessionType {
6365
var configuration: NSURLSessionConfiguration { get }
6466
func invalidateAndCancel()
6567
func dataTaskWithURL(url: NSURL, completionHandler: DataTaskResult) -> NSURLSessionDataTaskType
66-
func dataTaskWithRequest(request: NSMutableURLRequestType, completionHandler: DataTaskResult) -> NSURLSessionDataTaskType
67-
func dataTaskWithRequest(request: NSMutableURLRequestType) -> NSURLSessionDataTaskType
68+
func dataTaskWithRequest(request: NSURLRequestType, completionHandler: DataTaskResult) -> NSURLSessionDataTaskType
69+
func dataTaskWithRequest(request: NSURLRequestType) -> NSURLSessionDataTaskType
6870
}
6971
extension NSURLSession : NSURLSessionType {
7072
public func dataTaskWithURL(url: NSURL, completionHandler: DataTaskResult) -> NSURLSessionDataTaskType {
7173
return dataTaskWithURL(url, completionHandler: completionHandler) as NSURLSessionDataTask
7274
}
7375

74-
public func dataTaskWithRequest(request: NSMutableURLRequestType, completionHandler: DataTaskResult) -> NSURLSessionDataTaskType {
75-
return dataTaskWithRequest(request as! NSMutableURLRequest, completionHandler: completionHandler) as NSURLSessionDataTask
76+
public func dataTaskWithRequest(request: NSURLRequestType, completionHandler: DataTaskResult) -> NSURLSessionDataTaskType {
77+
return dataTaskWithRequest(request as! NSURLRequest, completionHandler: completionHandler) as NSURLSessionDataTask
7678
}
7779

78-
public func dataTaskWithRequest(request: NSMutableURLRequestType) -> NSURLSessionDataTaskType {
80+
public func dataTaskWithRequest(request: NSURLRequestType) -> NSURLSessionDataTaskType {
7981
return dataTaskWithRequest(request as! NSURLRequest) as NSURLSessionDataTask
8082
}
8183
}

RxHttpClient/HttpUtilities.swift

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,53 @@
11
import Foundation
2+
import RxSwift
23

3-
public protocol HttpUtilitiesType {
4+
protocol HttpUtilitiesType {
45
func createUrlRequest(baseUrl: String, parameters: [String: String]?) -> NSMutableURLRequestType?
56
func createUrlRequest(baseUrl: String, parameters: [String: String]?, headers: [String: String]?) -> NSMutableURLRequestType?
67
func createUrlRequest(url: NSURL, headers: [String: String]?) -> NSMutableURLRequestType
78
func createUrlSession(configuration: NSURLSessionConfiguration, delegate: NSURLSessionDelegate?, queue: NSOperationQueue?) -> NSURLSessionType
89
func createUrlSessionStreamObserver() -> NSURLSessionDataEventsObserverType
9-
func createStreamDataTask(taskUid: String, request: NSMutableURLRequestType, sessionConfiguration: NSURLSessionConfiguration, cacheProvider: CacheProviderType?)
10-
-> StreamDataTaskType
10+
func createStreamDataTask(taskUid: String, dataTask: NSURLSessionDataTaskType, httpClient: HttpClientType, sessionEvents: Observable<SessionDataEvents>,
11+
cacheProvider: CacheProviderType?) -> StreamDataTaskType
1112
}
1213

13-
public class HttpUtilities {
14-
public init() { }
15-
}
14+
struct HttpUtilities { }
1615

1716
extension HttpUtilities : HttpUtilitiesType {
18-
public func createUrlRequest(baseUrl: String, parameters: [String : String]?) -> NSMutableURLRequestType? {
17+
func createUrlRequest(baseUrl: String, parameters: [String : String]?) -> NSMutableURLRequestType? {
1918
guard let url = NSURL(baseUrl: baseUrl, parameters: parameters) else {
2019
return nil
2120
}
2221
return createUrlRequest(url)
2322
}
2423

25-
public func createUrlRequest(baseUrl: String, parameters: [String: String]?, headers: [String: String]?) -> NSMutableURLRequestType? {
24+
func createUrlRequest(baseUrl: String, parameters: [String: String]?, headers: [String: String]?) -> NSMutableURLRequestType? {
2625
guard let url = NSURL(baseUrl: baseUrl, parameters: parameters) else {
2726
return nil
2827
}
2928

3029
return createUrlRequest(url, headers: headers)
3130
}
3231

33-
public func createUrlRequest(url: NSURL, headers: [String : String]? = nil) -> NSMutableURLRequestType {
32+
func createUrlRequest(url: NSURL, headers: [String : String]? = nil) -> NSMutableURLRequestType {
3433
let request = NSMutableURLRequest(URL: url)
3534
headers?.forEach { request.addValue($1, forHTTPHeaderField: $0) }
3635
return request
3736
}
3837

39-
public func createUrlSession(configuration: NSURLSessionConfiguration, delegate: NSURLSessionDelegate? = nil, queue: NSOperationQueue? = nil)
38+
func createUrlSession(configuration: NSURLSessionConfiguration, delegate: NSURLSessionDelegate? = nil, queue: NSOperationQueue? = nil)
4039
-> NSURLSessionType {
4140
return NSURLSession(configuration: configuration,
4241
delegate: delegate,
4342
delegateQueue: queue)
4443
}
4544

46-
public func createUrlSessionStreamObserver() -> NSURLSessionDataEventsObserverType {
45+
func createUrlSessionStreamObserver() -> NSURLSessionDataEventsObserverType {
4746
return NSURLSessionDataEventsObserver()
4847
}
4948

50-
public func createStreamDataTask(taskUid: String, request: NSMutableURLRequestType,
51-
sessionConfiguration: NSURLSessionConfiguration = .defaultSessionConfiguration(), cacheProvider: CacheProviderType?) -> StreamDataTaskType {
52-
return StreamDataTask(taskUid: taskUid, request: request, httpUtilities: self, sessionConfiguration: sessionConfiguration, cacheProvider: cacheProvider)
49+
func createStreamDataTask(taskUid: String, dataTask: NSURLSessionDataTaskType, httpClient: HttpClientType, sessionEvents: Observable<SessionDataEvents>,
50+
cacheProvider: CacheProviderType?) -> StreamDataTaskType {
51+
return StreamDataTask(taskUid: taskUid, dataTask: dataTask, httpClient: httpClient, sessionEvents: sessionEvents, cacheProvider: cacheProvider)
5352
}
5453
}

RxHttpClient/NSURLSessionDataEventsObserver.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,31 @@ public enum SessionDataEvents {
88
case didCompleteWithError(session: NSURLSessionType, dataTask: NSURLSessionTaskType, error: NSError?)
99
}
1010

11-
public protocol NSURLSessionDataEventsObserverType {
11+
protocol NSURLSessionDataEventsObserverType {
1212
var sessionEvents: Observable<SessionDataEvents> { get }
1313
}
1414

1515
extension NSURLSessionDataEventsObserver : NSURLSessionDataEventsObserverType {
16-
public var sessionEvents: Observable<SessionDataEvents> {
16+
var sessionEvents: Observable<SessionDataEvents> {
1717
return sessionEventsSubject
1818
}
1919
}
2020

21-
public class NSURLSessionDataEventsObserver : NSObject, NSURLSessionDataDelegate {
21+
class NSURLSessionDataEventsObserver : NSObject, NSURLSessionDataDelegate {
2222
internal let sessionEventsSubject = PublishSubject<SessionDataEvents>()
2323
}
2424

2525
extension NSURLSessionDataEventsObserver {
26-
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse,
26+
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse,
2727
completionHandler: (NSURLSessionResponseDisposition) -> Void) {
2828
sessionEventsSubject.onNext(.didReceiveResponse(session: session, dataTask: dataTask, response: response, completion: completionHandler))
2929
}
3030

31-
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
31+
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
3232
sessionEventsSubject.onNext(.didReceiveData(session: session, dataTask: dataTask, data: data))
3333
}
3434

35-
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
35+
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
3636
sessionEventsSubject.onNext(.didCompleteWithError(session: session, dataTask: task, error: error))
3737
}
3838
}

0 commit comments

Comments
 (0)