forked from mironal/TwitterAPIKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTwitterAPIClient.swift
More file actions
150 lines (130 loc) · 5.04 KB
/
TwitterAPIClient.swift
File metadata and controls
150 lines (130 loc) · 5.04 KB
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
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import Foundation
open class TwitterAPIClient {
public static var defaultJSONDecoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
// for v1
let dateFormatterV1 = DateFormatter()
dateFormatterV1.locale = Locale(identifier: "en_US_POSIX")
dateFormatterV1.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
// for v2
let dateFormatterV2 = DateFormatter()
dateFormatterV2.locale = Locale(identifier: "en_US_POSIX")
dateFormatterV2.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
decoder.dateDecodingStrategy = .custom { decoder -> Date in
let container = try decoder.singleValueContainer()
let dateStr = try container.decode(String.self)
if let date = dateFormatterV1.date(from: dateStr) {
return date
}
if let date = dateFormatterV2.date(from: dateStr) {
return date
}
throw DecodingError.dataCorrupted(
.init(codingPath: decoder.codingPath, debugDescription: "Unexpected date format: \(dateStr)"))
}
return decoder
}()
public let auth: TwitterAuthAPI
public let v1: TwitterAPIv1
public let v2: TwitterAPIv2
public let session: TwitterAPISession
public var apiAuth: TwitterAuthenticationMethod {
return session.auth
}
/// for refresh token
private var refreshOAuth20TokenClient: TwitterAPIClient?
public init(
_ auth: TwitterAuthenticationMethod,
configuration: URLSessionConfiguration = .default,
environment: TwitterAPIEnvironment = .init()
) {
session = TwitterAPISession(
auth: auth,
configuration: configuration,
environment: environment
)
self.auth = TwitterAuthAPI(session: session)
v1 = TwitterAPIv1(session: session)
v2 = TwitterAPIv2(session: session)
}
/// for OAuth1.0a
convenience public init(
consumerKey: String,
consumerSecret: String,
oauthToken: String,
oauthTokenSecret: String
) {
self.init(
.oauth10a(
.init(
consumerKey: consumerKey,
consumerSecret: consumerSecret,
oauthToken: oauthToken,
oauthTokenSecret: oauthTokenSecret
)),
environment: .init()
)
}
}
// MARK: - Refresh OAuth2.0 token
extension TwitterAPIClient {
public typealias RefreshOAuth20TokenResultValue = (token: TwitterAuthenticationMethod.OAuth20, refreshed: Bool)
/// Refresh OAuth2.0 token
public func refreshOAuth20Token(
type: TwitterAuthenticationMethod.OAuth20WithPKCEClientType,
forceRefresh: Bool = false,
_ block: @escaping (Result<RefreshOAuth20TokenResultValue, TwitterAPIKitError>) -> Void
) {
guard case .oauth20(let token) = apiAuth else {
block(.failure(.refreshOAuth20TokenFailed(reason: .invalidAuthenticationMethod(apiAuth))))
return
}
guard let refreshToken = token.refreshToken else {
block(.failure(.refreshOAuth20TokenFailed(reason: .refreshTokenIsMissing)))
return
}
if !forceRefresh, !token.expired {
block(.success((token: token, refreshed: false)))
return
}
let refreshOAuth20TokenClient = TwitterAPIClient(
.requestOAuth20WithPKCE(type),
configuration: session.session.configuration,
environment: session.environment
)
self.refreshOAuth20TokenClient = refreshOAuth20TokenClient
refreshOAuth20TokenClient.auth.oauth20.postOAuth2RefreshToken(
.init(refreshToken: refreshToken, clientID: token.clientID)
)
.responseObject { [weak self] response in
guard let self = self else { return }
switch response.result {
case .success(let refreshedToken):
var token = token
token.refresh(token: refreshedToken)
self.session.refreshOAuth20Token(token)
block(.success((token: token, refreshed: true)))
NotificationCenter.default.post(
name: TwitterAPIClient.didRefreshOAuth20Token,
object: self,
userInfo: [TwitterAPIClient.tokenUserInfoKey: token]
)
case .failure(let error):
block(.failure(error))
}
self.refreshOAuth20TokenClient = nil
}
}
}
open class TwitterAPIBase {
public let session: TwitterAPISession
public init(session: TwitterAPISession) {
self.session = session
}
}
extension TwitterAPIClient {
// swift-format-ignore
public static let didRefreshOAuth20Token = Notification.Name(rawValue: "TwitterAPIKit.TwitterAPIClient.Notification.didRefreshOAuth20Token")
public static let tokenUserInfoKey = "TwitterAPIKit.TwitterAPIClient.UserInfoKey.tokenUser"
}