Skip to content

Commit

Permalink
Merge pull request #235 from mattdonnelly/swifter-2.2
Browse files Browse the repository at this point in the history
Swifter 2.2
  • Loading branch information
meteochu authored Jun 23, 2018
2 parents 4c5d257 + 55add11 commit f13f71e
Show file tree
Hide file tree
Showing 29 changed files with 1,156 additions and 493 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@

If you're using Xcode 6 and above, Swifter can be installed by simply dragging the Swifter Xcode project into your own project and adding either the SwifteriOS or SwifterMac framework as an embedded framework.

### Swifter 2.0

With the introduction of Swift 3, the naming convention of the language was changed. As a result, Swifter was updated to match the updated naming conventions of Swift. Additionally, we've slimmed down the framework and simplified a lot of the processes with the introduction of the `ListTag`, `UserTag`, and `UsersTag` enums for methods that allow for either id/slug for Lists, or id/screenName for Users.

### Usage

Swifter can be used with the 3 different kinds of authentication protocols Twitter allows. You can specify which protocol to use as shown below. For more information on each of the authentication protocols, please check [Twitter OAuth Help](https://dev.twitter.com/oauth).
Expand Down Expand Up @@ -81,6 +77,8 @@ Additionally, there is also `.screenName(arrayOfUserNames)` and `.id(arrayOfIds)

#### Streaming API:

**Important Note**: Twitter has deprecated the Streaming API in favour of their new [Accounts Activity API](https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-enterprise). You can find out more about migrating to the new API [here](https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/migration/us-ss-migration-guide). Twitter plans to remove the old streaming API on August 16, 2018, Swifter will remove the endpoints for it shortly after that.

```swift
swifter.streamRandomSampleTweets(progress: { status in
// ...
Expand Down
91 changes: 71 additions & 20 deletions Sources/Swifter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ import Accounts
#endif

extension Notification.Name {
static let SwifterCallbackNotification: Notification.Name = Notification.Name(rawValue: "SwifterCallbackNotificationName")
static let swifterCallback = Notification.Name(rawValue: "Swifter.CallbackNotificationName")
}

// MARK: - Twitter URL
public enum TwitterURL {

case api
case upload
case stream
case publish
case userStream
case siteStream
case oauth
Expand All @@ -51,13 +53,15 @@ public enum TwitterURL {
case .userStream: return URL(string: "https://userstream.twitter.com/1.1/")!
case .siteStream: return URL(string: "https://sitestream.twitter.com/1.1/")!
case .oauth: return URL(string: "https://api.twitter.com/")!
case .publish: return URL(string: "https://publish.twitter.com/")!
}
}

}

// MARK: - Tweet Mode
public enum TweetMode {

case `default`
case extended
case compat
Expand All @@ -84,7 +88,9 @@ public class Swifter {
public typealias SuccessHandler = (JSON) -> Void
public typealias CursorSuccessHandler = (JSON, _ previousCursor: String?, _ nextCursor: String?) -> Void
public typealias JSONSuccessHandler = (JSON, _ response: HTTPURLResponse) -> Void
public typealias FailureHandler = (_ error: Error) -> Void
public typealias SearchResultHandler = (JSON, _ searchMetadata: JSON) -> Void
public typealias FailureHandler = (_ error: Error) -> Void


internal struct CallbackNotification {
static let optionsURLKey = "SwifterCallbackNotificationOptionsURLKey"
Expand All @@ -93,6 +99,7 @@ public class Swifter {
internal struct DataParameters {
static let dataKey = "SwifterDataParameterKey"
static let fileNameKey = "SwifterDataParameterFilename"
static let jsonDataKey = "SwifterDataJSONDataParameterKey"
}

// MARK: - Properties
Expand All @@ -109,7 +116,8 @@ public class Swifter {
}

public init(consumerKey: String, consumerSecret: String, oauthToken: String, oauthTokenSecret: String) {
self.client = OAuthClient(consumerKey: consumerKey, consumerSecret: consumerSecret , accessToken: oauthToken, accessTokenSecret: oauthTokenSecret)
self.client = OAuthClient(consumerKey: consumerKey, consumerSecret: consumerSecret,
accessToken: oauthToken, accessTokenSecret: oauthTokenSecret)
}

#if os(macOS) || os(iOS)
Expand All @@ -125,15 +133,22 @@ public class Swifter {
// MARK: - JSON Requests

@discardableResult
internal func jsonRequest(path: String, baseURL: TwitterURL, method: HTTPMethodType, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler? = nil, downloadProgress: JSONSuccessHandler? = nil, success: JSONSuccessHandler? = nil, failure: HTTPRequest.FailureHandler? = nil) -> HTTPRequest {
internal func jsonRequest(path: String,
baseURL: TwitterURL,
method: HTTPMethodType,
parameters: [String: Any],
uploadProgress: HTTPRequest.UploadProgressHandler? = nil,
downloadProgress: JSONSuccessHandler? = nil,
success: JSONSuccessHandler? = nil,
failure: HTTPRequest.FailureHandler? = nil) -> HTTPRequest {

let jsonDownloadProgressHandler: HTTPRequest.DownloadProgressHandler = { [weak self] data, _, _, response in
guard let `self` = self else { return }
guard let _ = downloadProgress else { return }
self.handleStreamProgress(data: data, response: response, handler: downloadProgress)
if let progress = downloadProgress {
self?.handleStreamProgress(data: data, response: response, handler: progress)
}
}

let jsonSuccessHandler: HTTPRequest.SuccessHandler = { data, response in

DispatchQueue.global(qos: .utility).async {
do {
let jsonResult = try JSON.parse(jsonData: data)
Expand All @@ -142,7 +157,7 @@ public class Swifter {
}
} catch {
DispatchQueue.main.async {
if case 200 ... 299 = response.statusCode, data.count == 0 {
if case 200...299 = response.statusCode, data.isEmpty {
success?(JSON("{}"), response)
} else {
failure?(error)
Expand All @@ -151,12 +166,22 @@ public class Swifter {
}
}
}

if method == .GET {
return self.client.get(path, baseURL: baseURL, parameters: parameters, uploadProgress: uploadProgress, downloadProgress: jsonDownloadProgressHandler, success: jsonSuccessHandler, failure: failure)
} else {
return self.client.post(path, baseURL: baseURL, parameters: parameters, uploadProgress: uploadProgress, downloadProgress: jsonDownloadProgressHandler, success: jsonSuccessHandler, failure: failure)
}

switch method {
case .GET:
return self.client.get(path, baseURL: baseURL, parameters: parameters,
uploadProgress: uploadProgress, downloadProgress: jsonDownloadProgressHandler,
success: jsonSuccessHandler, failure: failure)
case .POST:
return self.client.post(path, baseURL: baseURL, parameters: parameters,
uploadProgress: uploadProgress, downloadProgress: jsonDownloadProgressHandler,
success: jsonSuccessHandler, failure: failure)
case .DELETE:
return self.client.delete(path, baseURL: baseURL, parameters: parameters,
success: jsonSuccessHandler, failure: failure)
default:
fatalError("This HTTP Method is not supported")
}
}

private func handleStreamProgress(data: Data, response: HTTPURLResponse, handler: JSONSuccessHandler? = nil) {
Expand All @@ -180,13 +205,39 @@ public class Swifter {
}

@discardableResult
internal func getJSON(path: String, baseURL: TwitterURL, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler? = nil, downloadProgress: JSONSuccessHandler? = nil, success: JSONSuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
return self.jsonRequest(path: path, baseURL: baseURL, method: .GET, parameters: parameters, uploadProgress: uploadProgress, downloadProgress: downloadProgress, success: success, failure: failure)
internal func getJSON(path: String,
baseURL: TwitterURL,
parameters: [String: Any],
uploadProgress: HTTPRequest.UploadProgressHandler? = nil,
downloadProgress: JSONSuccessHandler? = nil,
success: JSONSuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
return self.jsonRequest(path: path, baseURL: baseURL, method: .GET, parameters: parameters,
uploadProgress: uploadProgress, downloadProgress: downloadProgress,
success: success, failure: failure)
}

@discardableResult
internal func postJSON(path: String, baseURL: TwitterURL, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler? = nil, downloadProgress: JSONSuccessHandler? = nil, success: JSONSuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
return self.jsonRequest(path: path, baseURL: baseURL, method: .POST, parameters: parameters, uploadProgress: uploadProgress, downloadProgress: downloadProgress, success: success, failure: failure)
internal func postJSON(path: String,
baseURL: TwitterURL,
parameters: [String: Any],
uploadProgress: HTTPRequest.UploadProgressHandler? = nil,
downloadProgress: JSONSuccessHandler? = nil,
success: JSONSuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
return self.jsonRequest(path: path, baseURL: baseURL, method: .POST, parameters: parameters,
uploadProgress: uploadProgress, downloadProgress: downloadProgress,
success: success, failure: failure)
}

@discardableResult
internal func deleteJSON(path: String,
baseURL: TwitterURL,
parameters: [String: Any],
success: JSONSuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
return self.jsonRequest(path: path, baseURL: baseURL, method: .DELETE, parameters: parameters,
success: success, failure: failure)
}

}
25 changes: 23 additions & 2 deletions Sources/SwifterAccountsClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal class AccountsClient: SwifterClientProtocol {
self.credential = Credential(account: account)
}

func get(_ path: String, baseURL: TwitterURL, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler?, downloadProgress: HTTPRequest.DownloadProgressHandler?, success: HTTPRequest.SuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
func get(_ path: String, baseURL: TwitterURL, parameters: [String: Any], uploadProgress: HTTPRequest.UploadProgressHandler?, downloadProgress: HTTPRequest.DownloadProgressHandler?, success: HTTPRequest.SuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
let url = URL(string: path, relativeTo: baseURL.url)

let stringifiedParameters = parameters.stringifiedDictionary()
Expand All @@ -55,7 +55,7 @@ internal class AccountsClient: SwifterClientProtocol {
return request
}

func post(_ path: String, baseURL: TwitterURL, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler?, downloadProgress: HTTPRequest.DownloadProgressHandler?, success: HTTPRequest.SuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
func post(_ path: String, baseURL: TwitterURL, parameters: [String: Any], uploadProgress: HTTPRequest.UploadProgressHandler?, downloadProgress: HTTPRequest.DownloadProgressHandler?, success: HTTPRequest.SuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
let url = URL(string: path, relativeTo: baseURL.url)

var params = parameters
Expand Down Expand Up @@ -96,6 +96,27 @@ internal class AccountsClient: SwifterClientProtocol {
request.start()
return request
}

func delete(_ path: String,
baseURL: TwitterURL,
parameters: [String: Any],
success: HTTPRequest.SuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
let url = URL(string: path, relativeTo: baseURL.url)

let stringifiedParameters = parameters.stringifiedDictionary()

let socialRequest = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .DELETE, url: url, parameters: stringifiedParameters)!
socialRequest.account = self.credential!.account!

let request = HTTPRequest(request: socialRequest.preparedURLRequest())
request.parameters = parameters
request.successHandler = success
request.failureHandler = failure

request.start()
return request
}

}
#endif
36 changes: 34 additions & 2 deletions Sources/SwifterAppOnlyClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ internal class AppOnlyClient: SwifterClientProtocol {
self.consumerSecret = consumerSecret
}

func get(_ path: String, baseURL: TwitterURL, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler?, downloadProgress: HTTPRequest.DownloadProgressHandler?, success: HTTPRequest.SuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
func get(_ path: String,
baseURL: TwitterURL,
parameters: [String: Any],
uploadProgress: HTTPRequest.UploadProgressHandler?,
downloadProgress: HTTPRequest.DownloadProgressHandler?,
success: HTTPRequest.SuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
let url = URL(string: path, relativeTo: baseURL.url)

let request = HTTPRequest(url: url!, method: .GET, parameters: parameters)
Expand All @@ -56,7 +62,13 @@ internal class AppOnlyClient: SwifterClientProtocol {
return request
}

func post(_ path: String, baseURL: TwitterURL, parameters: Dictionary<String, Any>, uploadProgress: HTTPRequest.UploadProgressHandler?, downloadProgress: HTTPRequest.DownloadProgressHandler?, success: HTTPRequest.SuccessHandler?, failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
func post(_ path: String,
baseURL: TwitterURL,
parameters: [String: Any],
uploadProgress: HTTPRequest.UploadProgressHandler?,
downloadProgress: HTTPRequest.DownloadProgressHandler?,
success: HTTPRequest.SuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
let url = URL(string: path, relativeTo: baseURL.url)

let request = HTTPRequest(url: url!, method: .POST, parameters: parameters)
Expand All @@ -76,6 +88,26 @@ internal class AppOnlyClient: SwifterClientProtocol {
request.start()
return request
}

func delete(_ path: String,
baseURL: TwitterURL,
parameters: [String: Any],
success: HTTPRequest.SuccessHandler?,
failure: HTTPRequest.FailureHandler?) -> HTTPRequest {
let url = URL(string: path, relativeTo: baseURL.url)

let request = HTTPRequest(url: url!, method: .DELETE, parameters: parameters)
request.successHandler = success
request.failureHandler = failure
request.dataEncoding = self.dataEncoding

if let bearerToken = self.credential?.accessToken?.key {
request.headers = ["Authorization": "Bearer \(bearerToken)"];
}

request.start()
return request
}

class func base64EncodedCredentials(withKey key: String, secret: String) -> String {
let encodedKey = key.urlEncodedString()
Expand Down
Loading

0 comments on commit f13f71e

Please sign in to comment.