Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Rep committed Aug 19, 2016
1 parent 71c041b commit d36eff4
Show file tree
Hide file tree
Showing 20 changed files with 170 additions and 200 deletions.
100 changes: 56 additions & 44 deletions TransparentDataAccess.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Binary file not shown.
8 changes: 7 additions & 1 deletion TransparentDataAccess/Model/GitHubTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public enum GitHub {
case UserProfile(String)
}

extension GitHub: ResourceType {
extension GitHub: TargetType, StorableType {
public var baseURL: NSURL { return NSURL(string: "https://api.github.com")! }
public var path: String {
switch self {
Expand All @@ -40,4 +40,10 @@ extension GitHub: ResourceType {
return "{\"login\": \"\(name)\", \"id\": 100}".dataUsingEncoding(NSUTF8StringEncoding)!
}
}
var key: String {
switch self {
case .UserProfile(let name):
return name
}
}
}
2 changes: 1 addition & 1 deletion TransparentDataAccess/Model/ResourceTypeExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum ResourceTypeExample{
case Token(key: String, secret: String)
}

extension ResourceTypeExample: ResourceType{
extension ResourceTypeExample: StorableType{
var key: String{
switch self {
case .EmptyTarget:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import RxSwift
import Moya

class TracksInFlightGetGateway<R, T: ResourceType>: GetGateway<R, T> {
class TracksInFlightGetGateway<R, T where T:TargetType, T:StorableType>: GetGateway<R, T> {

let gateway: GetGateway<R, T>

Expand Down
65 changes: 0 additions & 65 deletions TransparentDataAccess/TransparentDataAccess/Gateway.swift

This file was deleted.

41 changes: 41 additions & 0 deletions TransparentDataAccess/TransparentDataAccess/GatewayError.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
import RxSwift

enum GatewayError: ErrorType {
case HTTPError(code: Int)
case UnboxingError
case SystemError(code: Int, description: String)
case PermissionDenied
case NoDataReturned
case NoDataFor(key: String)
case CodingFailed

var description: String {
switch self {
case .HTTPError(let code):
return "HTTP error with status code \(code)"
case .UnboxingError:
return "Error while mapping response body"
case .SystemError(_, let description):
return description
case .PermissionDenied:
return "Permission was denied"
case .NoDataReturned:
return "Request returned no data"
case .NoDataFor(let key):
return "No data was found for key \(key)"
case .CodingFailed:
return "Resource coding failed"
}
}
}

extension GatewayError: Equatable {
Expand All @@ -9,5 +36,19 @@ func == (lhs: GatewayError, rhs: GatewayError) -> Bool {
switch (lhs, rhs) {
case (.NoDataFor(let x), .NoDataFor(let y)):
return x == y
case (.HTTPError(let x), .HTTPError(let y)):
return x == y
case (.UnboxingError, .UnboxingError):
return true
case (.SystemError(let x, _), .SystemError(let y, _)):
return x == y
case (.PermissionDenied, .PermissionDenied):
return true
case (.NoDataReturned, .NoDataReturned):
return true
case (.CodingFailed, .CodingFailed):
return true
default:
return false
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
import RxSwift

enum CodingGatewayError: ErrorType {
case NoDataForKey(key: String)
case CodingFailed
}

extension CodingGatewayError: Equatable {
}

func == (lhs: CodingGatewayError, rhs: CodingGatewayError) -> Bool {
switch (lhs, rhs) {
case (.NoDataForKey(let x), .NoDataForKey(let y)):
return x == y
case (.CodingFailed, .CodingFailed):
return true
default:
return false
}
}

class CodingGateway<R: NSCoding, T: StorableType>: GetSetGateway<R, T> {

override func getResource(resourceType: T, forceRefresh: Bool = false) -> Observable<R> {
Expand All @@ -28,14 +9,15 @@ class CodingGateway<R: NSCoding, T: StorableType>: GetSetGateway<R, T> {
observer.onNext(resource)
observer.onCompleted()
} else {
observer.onError(CodingGatewayError.CodingFailed)
observer.onError(GatewayError.CodingFailed)
}
} else {
observer.onError(CodingGatewayError.NoDataForKey(key: resourceType.key))
observer.onError(GatewayError.NoDataFor(key: resourceType.key))
}

return NopDisposable.instance
})
.observeOn(ConcurrentDispatchQueueScheduler(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)))
}

override func setResource(resourceType: T, resource: R) {
Expand Down
20 changes: 20 additions & 0 deletions TransparentDataAccess/TransparentDataAccess/Gateways/Gateway.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import RxSwift
import Moya

/// Target that can be stored using default gateways
protocol StorableType {
var key: String { get }
}

/// Get gateway interface
class GetGateway<R, T> {
func getResource(resourceType: T, forceRefresh: Bool = false) -> Observable<R> {
return Observable.empty()
}
}

/// GetSet gateway interface
class GetSetGateway<R, T: StorableType>: GetGateway<R, T> {
func setResource(resourceType: T, resource: R) {
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import KeychainAccess
import RxSwift

/// Set to wanted walue
let keychainServiceString = "undabot.TransparentDataAccess"

/// Resource that can be stored and fetched using keychain gateway
protocol Keychainable {
init(data: String)

func toString() -> String
}

let keychainServiceString = "undabot.TransparentDataAccess"
let keychain = Keychain(service: keychainServiceString)

class KeychainGateway<R: Keychainable, T: StorableType>: GetSetGateway<R, T> {
private let keychainKey = "TwitterAccessToken"

override func getResource(resourceType: T,
forceRefresh: Bool = false) -> Observable<R> {
override func getResource(resourceType: T, forceRefresh: Bool = false) -> Observable<R> {
let resourceString = keychain[resourceType.key]

if resourceString != nil && !forceRefresh {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,6 @@ import RxSwift
import Moya
import Unbox

enum WebRequestError: ErrorType {
case HTTPError(code: Int)
case UnboxingError
case SystemError(code: Int, description: String)
case PermissionDenied
case NoDataReturned

var description: String {
switch self {
case .HTTPError(let code):
return "HTTP error with status code \(code)"
case .UnboxingError:
return "Error while mapping response body"
case .SystemError(_, let description):
return description
case .PermissionDenied:
return "Permission was denied"
case .NoDataReturned:
return "Request returned no data"
}
}
}

extension WebRequestError: Equatable {
}

func == (lhs: WebRequestError, rhs: WebRequestError) -> Bool {
switch (lhs, rhs) {
case (.HTTPError(let x), .HTTPError(let y)):
return x == y
case (.UnboxingError, .UnboxingError):
return true
case (.PermissionDenied, .PermissionDenied):
return true
case (.NoDataReturned, .NoDataReturned):
return true
default:
return false
}
}

class WebGateway<R: Unboxable, T: TargetType>: GetGateway<R, T> {
var provider: RxMoyaProvider<T>!
let mapper: ResourceMapperProtocol
Expand All @@ -65,8 +24,8 @@ class WebGateway<R: Unboxable, T: TargetType>: GetGateway<R, T> {

// Catch 401 errors and automaticaly tries to refresh token
.catchError({ (error) -> Observable<R> in
if let tokenRefreshAction = self.tokenRefreshAction, error = error as? WebRequestError {
if error == WebRequestError.HTTPError(code: 401) {
if let tokenRefreshAction = self.tokenRefreshAction, error = error as? GatewayError {
if error == GatewayError.HTTPError(code: 401) {
return tokenRefreshAction(gateway: self, resourceType: resourceType)
}
}
Expand All @@ -81,15 +40,13 @@ class WebGateway<R: Unboxable, T: TargetType>: GetGateway<R, T> {
}

static func standartdTokenRefreshAction(gateway: WebGateway<R, T>, resourceType: T) -> Observable<R> {
return // TODO refresh token

return
// Allows subclass preform updates
gateway.createProvider()
.flatMap({ (newProvider) -> Observable<R> in

// Mapps Moya response to object with token refresh disabled
return gateway.mapper.mapResponse(newProvider.request(resourceType), refreshesToken: false)
})

}
}
15 changes: 15 additions & 0 deletions TransparentDataAccess/TransparentDataAccess/Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Moya

extension String {
var URLEscapedString: String {
return self.stringByAddingPercentEncodingWithAllowedCharacters(
NSCharacterSet.URLHostAllowedCharacterSet())!
}
var UTF8EncodedData: NSData {
return self.dataUsingEncoding(NSUTF8StringEncoding)!
}
}

public func url(route: TargetType) -> String {
return route.baseURL.URLByAppendingPathComponent(route.path).absoluteString
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ class ResourceMapper: ResourceMapperProtocol {
// If status code is 401 and refreshesToken is disabled
// return PermisionDenied error
if response.statusCode == 401 && !refreshesToken {
observer.onError(WebRequestError.PermissionDenied)
observer.onError(GatewayError.PermissionDenied)
}
// Else propagate error
else {
observer.onError(WebRequestError.HTTPError(code: response.statusCode))
observer.onError(GatewayError.HTTPError(code: response.statusCode))
}

} else {
Expand All @@ -36,7 +36,7 @@ class ResourceMapper: ResourceMapperProtocol {
observer.onNext(resource)
observer.onCompleted()
} catch {
observer.onError(WebRequestError.UnboxingError)
observer.onError(GatewayError.UnboxingError)
}
}

Expand All @@ -47,7 +47,7 @@ class ResourceMapper: ResourceMapperProtocol {

switch error {
case Moya.Error.Underlying(let error):
return .error(WebRequestError.SystemError(code: error.code,
return .error(GatewayError.SystemError(code: error.code,
description: error.userInfo["NSLocalizedDescription"] as? String ?? ""))
default:
return .error(error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,20 @@ class CompositeErrorsTest: XCTestCase{

let compositGateway = CompositGateway(gateways: [firstGateway, secondGateway])

var recievedError: WebRequestError?
var recievedError: GatewayError?

waitUntil(action: { done in
_ = compositGateway.getResource(type)
.subscribe(
onError: { (error) in
if let error = error as? WebRequestError{
if let error = error as? GatewayError{
recievedError = error
}
}, onDisposed: {
done()
})
})

expect(recievedError).to(equal(WebRequestError.HTTPError(code: 400)))
expect(recievedError).to(equal(GatewayError.HTTPError(code: 400)))
}
}
Loading

0 comments on commit d36eff4

Please sign in to comment.