This repository was archived by the owner on Sep 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 52
/
Copy pathBackgroundFetch.swift
95 lines (84 loc) · 3.88 KB
/
BackgroundFetch.swift
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//
// BackgroundFetch.swift
// reddift
//
// Created by sonson on 2016/06/03.
// Copyright © 2016年 sonson. All rights reserved.
//
#if os(iOS)
import UIKit
import Foundation
/// Session class to communicate with reddit.com using OAuth.
public class BackgroundFetch: NSObject, URLSessionDelegate {
let session: Session
var taskURLSession: URLSession?
var tokenURLSession: URLSession?
var firstTry = true
let taskHandler: ((_ response: HTTPURLResponse?, _ dataURL: URL?, _ error: NSError?) -> Void)
var request: URLRequest
public init(current currentSession: Session, request aRequest: URLRequest, taskHandler aTaskHandler: @escaping (_ response: HTTPURLResponse?, _ dataURL: URL?, _ error: NSError?) -> Void) {
session = currentSession
taskHandler = aTaskHandler
request = aRequest
super.init()
taskURLSession = URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "com.sonson.reddift.profile"), delegate: self, delegateQueue: nil)
tokenURLSession = URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "com.sonson.reddift.token"), delegate: self, delegateQueue: nil)
}
public func resume() {
guard let taskURLSession = self.taskURLSession else { return }
taskURLSession.downloadTask(with: request).resume()
}
func handleTask(with response: HTTPURLResponse, didFinishDownloadingToURL: URL, requestForRefreshToken: URLRequest) {
if response.statusCode == HttpStatus.unauthorized.rawValue {
if firstTry {
if let tokenURLSession = self.tokenURLSession {
firstTry = false
tokenURLSession.downloadTask(with: requestForRefreshToken).resume()
}
} else {
taskHandler(nil, nil, HttpStatus(response.statusCode) as NSError)
}
} else {
taskHandler(response, didFinishDownloadingToURL, nil)
}
}
func handleTokenRefresh(with response: HTTPURLResponse, didFinishDownloadingToURL: URL, token: OAuth2Token) {
if response.statusCode == HttpStatus.ok.rawValue {
let data = try? Data(contentsOf: didFinishDownloadingToURL)
let result: Result<JSONDictionary> = Result(from: Response(data: data, urlResponse: response), optional: nil)
.flatMap(response2Data)
.flatMap(data2Json)
.flatMap(redditAny2Object)
let result2 = refreshTokenWithJSON(result, token: token)
switch result2 {
case .success(let token):
session.token = token
request.setOAuth2Token(token)
resume()
case .failure(let error):
taskHandler(nil, nil, error)
}
} else {
taskHandler(nil, nil, HttpStatus(response.statusCode) as NSError)
}
}
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
guard let response = downloadTask.response as? HTTPURLResponse
else { return }
guard let token = self.session.token as? OAuth2Token
else { return }
guard let requestForRefreshToken = token.requestForRefreshing()
else { return }
if session == tokenURLSession {
handleTokenRefresh(with: response, didFinishDownloadingToURL: location, token: token)
} else if session == taskURLSession {
handleTask(with: response, didFinishDownloadingToURL: location, requestForRefreshToken: requestForRefreshToken)
} else {
taskHandler(nil, nil, ReddiftError.unknown as NSError)
}
}
public func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
taskHandler(nil, nil, error as NSError?)
}
}
#endif