From 8b32be48b513fcf29414873fe475347e4b775b6d Mon Sep 17 00:00:00 2001 From: Srdan Rasic Date: Sun, 27 Dec 2015 16:41:49 +0100 Subject: [PATCH 1/3] Add gitignore --- .gitignore | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..624ccbf --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +.DS_Store + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control +# +# Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build From ba1c1f773b187dfefa9f96f25895d4deb24522d4 Mon Sep 17 00:00:00 2001 From: Srdan Rasic Date: Sun, 27 Dec 2015 18:05:09 +0100 Subject: [PATCH 2/3] Add session delegate support --- DVR.xcodeproj/project.pbxproj | 2 ++ DVR/Session.swift | 23 +++++++++++++--- DVR/SessionDataTask.swift | 51 ++++++++++++++++++++++++++++++++++- DVR/SessionDownloadTask.swift | 37 +++++++++++++++++++++++-- 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/DVR.xcodeproj/project.pbxproj b/DVR.xcodeproj/project.pbxproj index 46db810..9d1d082 100644 --- a/DVR.xcodeproj/project.pbxproj +++ b/DVR.xcodeproj/project.pbxproj @@ -119,7 +119,9 @@ 3647AF9D1B335D5500EF10D4 /* DVR */, 3647AF9C1B335D5500EF10D4 /* Products */, ); + indentWidth = 4; sourceTree = ""; + tabWidth = 4; }; 3647AF9C1B335D5500EF10D4 /* Products */ = { isa = PBXGroup; diff --git a/DVR/Session.swift b/DVR/Session.swift index 4d95076..a376226 100644 --- a/DVR/Session.swift +++ b/DVR/Session.swift @@ -17,14 +17,22 @@ public class Session: NSURLSession { private var completedInteractions = [Interaction]() private var completionBlock: (Void -> Void)? + private var nextTaskID: Int = 0 + private let idGenerationQueue = dispatch_queue_create("com.venmo.DVR.idGenerationQueue", nil) + + private let _delegate: NSURLSessionDelegate? + override public var delegate: NSURLSessionDelegate? { + return _delegate + } // MARK: - Initializers - public init(outputDirectory: String = "~/Desktop/DVR/", cassetteName: String, testBundle: NSBundle = NSBundle.allBundles().filter() { $0.bundlePath.hasSuffix(".xctest") }.first!, backingSession: NSURLSession = NSURLSession.sharedSession()) { + public init(outputDirectory: String = "~/Desktop/DVR/", cassetteName: String, testBundle: NSBundle = NSBundle.allBundles().filter() { $0.bundlePath.hasSuffix(".xctest") }.first!, backingSession: NSURLSession = NSURLSession.sharedSession(), delegate: NSURLSessionDelegate? = nil) { self.outputDirectory = outputDirectory self.cassetteName = cassetteName self.testBundle = testBundle self.backingSession = backingSession + _delegate = delegate super.init() } @@ -115,16 +123,25 @@ public class Session: NSURLSession { // MARK: - Private + private func generateNextTaskID() -> Int { + var id: Int! + dispatch_sync(idGenerationQueue) { + id = self.nextTaskID + self.nextTaskID += 1 + } + return id + } + private func addDataTask(request: NSURLRequest, completionHandler: ((NSData?, NSURLResponse?, NSError?) -> Void)? = nil) -> NSURLSessionDataTask { let modifiedRequest = backingSession.configuration.HTTPAdditionalHeaders.map(request.requestByAppendingHeaders) ?? request - let task = SessionDataTask(session: self, request: modifiedRequest, completion: completionHandler) + let task = SessionDataTask(taskIdentifier: generateNextTaskID(), session: self, request: modifiedRequest, completion: completionHandler) addTask(task) return task } private func addDownloadTask(request: NSURLRequest, completionHandler: SessionDownloadTask.Completion? = nil) -> NSURLSessionDownloadTask { let modifiedRequest = backingSession.configuration.HTTPAdditionalHeaders.map(request.requestByAppendingHeaders) ?? request - let task = SessionDownloadTask(session: self, request: modifiedRequest, completion: completionHandler) + let task = SessionDownloadTask(taskIdentifier: generateNextTaskID(), session: self, request: modifiedRequest, completion: completionHandler) addTask(task) return task } diff --git a/DVR/SessionDataTask.swift b/DVR/SessionDataTask.swift index 679d9ea..3b4b062 100644 --- a/DVR/SessionDataTask.swift +++ b/DVR/SessionDataTask.swift @@ -14,13 +14,38 @@ class SessionDataTask: NSURLSessionDataTask { let completion: Completion? private let queue = dispatch_queue_create("com.venmo.DVR.sessionDataTaskQueue", nil) + // MARK: - Overridden Properties + + let _taskIdentifier: Int + override var taskIdentifier: Int { + return _taskIdentifier + } + + override var originalRequest: NSURLRequest? { + return request + } + + override var currentRequest: NSURLRequest? { + return request + } + + var _response: NSURLResponse? = nil + override var response: NSURLResponse? { + return _response + } + + var _state: NSURLSessionTaskState = .Suspended + override var state: NSURLSessionTaskState { + return _state + } // MARK: - Initializers - init(session: Session, request: NSURLRequest, completion: (Completion)? = nil) { + init(taskIdentifier: Int, session: Session, request: NSURLRequest, completion: (Completion)? = nil) { self.session = session self.request = request self.completion = completion + _taskIdentifier = taskIdentifier } @@ -31,16 +56,39 @@ class SessionDataTask: NSURLSessionDataTask { } override func resume() { + _state = .Running + let cassette = session.cassette // Find interaction if let interaction = session.cassette?.interactionForRequest(request) { + + _response = interaction.response + + if let delegate = session.delegate as? NSURLSessionDataDelegate { + + // Delegate message #1 + delegate.URLSession?(session, dataTask: self, didReceiveResponse: interaction.response, completionHandler: { (disposition) -> Void in + // TODO + }) + + // Delegate message #2 + if let responseData = interaction.responseData { + delegate.URLSession?(session, dataTask: self, didReceiveData: responseData) + } + + // Delegate message #3 + delegate.URLSession?(session, task: self, didCompleteWithError: nil) + } + // Forward completion if let completion = completion { dispatch_async(queue) { completion(interaction.responseData, interaction.response, nil) } } + + _state = .Completed session.finishTask(self, interaction: interaction, playback: true) return } @@ -72,6 +120,7 @@ class SessionDataTask: NSURLSessionDataTask { // Still call the completion block so the user can chain requests while recording. dispatch_async(this.queue) { this.completion?(data, response, nil) + self?._state = .Completed } // Create interaction diff --git a/DVR/SessionDownloadTask.swift b/DVR/SessionDownloadTask.swift index c28bce6..b5f773f 100644 --- a/DVR/SessionDownloadTask.swift +++ b/DVR/SessionDownloadTask.swift @@ -10,13 +10,38 @@ class SessionDownloadTask: NSURLSessionDownloadTask { let request: NSURLRequest let completion: Completion? + // MARK: - Overridden Properties + + let _taskIdentifier: Int + override var taskIdentifier: Int { + return _taskIdentifier + } + + override var originalRequest: NSURLRequest? { + return request + } + + override var currentRequest: NSURLRequest? { + return request + } + + var _response: NSURLResponse? = nil + override var response: NSURLResponse? { + return _response + } + + var _state: NSURLSessionTaskState = .Suspended + override var state: NSURLSessionTaskState { + return _state + } // MARK: - Initializers - init(session: Session, request: NSURLRequest, completion: Completion? = nil) { + init(taskIdentifier: Int, session: Session, request: NSURLRequest, completion: Completion? = nil) { self.session = session self.request = request self.completion = completion + _taskIdentifier = taskIdentifier } // MARK: - NSURLSessionTask @@ -26,19 +51,27 @@ class SessionDownloadTask: NSURLSessionDownloadTask { } override func resume() { - let task = SessionDataTask(session: session, request: request) { data, response, error in + var task: SessionDataTask! = nil + task = SessionDataTask(taskIdentifier: taskIdentifier, session: session, request: request) { data, response, error in let location: NSURL? if let data = data { // Write data to temporary file let tempURL = NSURL(fileURLWithPath: (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent(NSUUID().UUIDString)) data.writeToURL(tempURL, atomically: true) location = tempURL + + // Notify the delegate + if let delegate = task.session.delegate as? NSURLSessionDownloadDelegate { + delegate.URLSession(task.session, downloadTask: self, didFinishDownloadingToURL: tempURL) + } } else { location = nil } self.completion?(location, response, error) + task._state = .Running } task.resume() + task._state = .Running } } From c2e3f6eb68e32c9af84125e22d1e967749646903 Mon Sep 17 00:00:00 2001 From: Srdan Rasic Date: Sun, 27 Dec 2015 22:39:30 +0100 Subject: [PATCH 3/3] Make nextTaskID static. --- DVR/Session.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DVR/Session.swift b/DVR/Session.swift index a376226..ece8bc3 100644 --- a/DVR/Session.swift +++ b/DVR/Session.swift @@ -17,7 +17,7 @@ public class Session: NSURLSession { private var completedInteractions = [Interaction]() private var completionBlock: (Void -> Void)? - private var nextTaskID: Int = 0 + private static var nextTaskID: Int = 0 private let idGenerationQueue = dispatch_queue_create("com.venmo.DVR.idGenerationQueue", nil) private let _delegate: NSURLSessionDelegate? @@ -126,8 +126,8 @@ public class Session: NSURLSession { private func generateNextTaskID() -> Int { var id: Int! dispatch_sync(idGenerationQueue) { - id = self.nextTaskID - self.nextTaskID += 1 + id = Session.nextTaskID + Session.nextTaskID += 1 } return id }