Skip to content

Commit

Permalink
Add Alamofire support
Browse files Browse the repository at this point in the history
  • Loading branch information
ProVir committed Jun 1, 2018
1 parent f07a65f commit 36a7acb
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 38 deletions.
1 change: 1 addition & 0 deletions Cartfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github "Alamofire/Alamofire" ~> 4.7
4 changes: 4 additions & 0 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ target 'WebServiceExample' do
pod 'Alamofire'
end

target 'WebServiceSwift' do
pod 'Alamofire'
end

8 changes: 6 additions & 2 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ PODS:
DEPENDENCIES:
- Alamofire

SPEC REPOS:
https://github.com/cocoapods/specs.git:
- Alamofire

SPEC CHECKSUMS:
Alamofire: e4fa87002c137ba2d8d634d2c51fabcda0d5c223

PODFILE CHECKSUM: e272eb5ac7ed6c653efe6688b042a0992b735290
PODFILE CHECKSUM: 8c5d5d4f811ce36fa921b4d5cad56c9fda10835d

COCOAPODS: 1.4.0
COCOAPODS: 1.5.2
157 changes: 157 additions & 0 deletions Source/Alamofire/WebServiceAlamofireBaseEngine.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
//
// WebServiceAlamofireBaseEngine.swift
// WebServiceSwift 2.3.0
//
// Created by ViR (Короткий Виталий) on 31.05.2018.
// Copyright © 2018 ProVir. All rights reserved.
//

import Foundation
import Alamofire


open class WebServiceAlamofireBaseEngine: WebServiceEngining {
public let queueForRequest: DispatchQueue?
public let queueForDataHandler: DispatchQueue? = nil
public let queueForDataHandlerFromStorage: DispatchQueue? = DispatchQueue.global(qos: .default)

public let useNetworkActivityIndicator: Bool

public init(queueForRequest: DispatchQueue?, useNetworkActivityIndicator: Bool) {
self.queueForRequest = queueForRequest
self.useNetworkActivityIndicator = useNetworkActivityIndicator
}


private struct TaskData {
var requestId: UInt64
var requestData: RequestData
var request: Alamofire.DataRequest
}

public struct RequestData {
public var request: WebServiceBaseRequesting

public var completionWithData: (Any) -> Void
public var completionWithError: (Error) -> Void
public var canceled: () -> Void

public var innerData: Any?

public init(request: WebServiceBaseRequesting,
completionWithData: @escaping (Any) -> Void,
completionWithError: @escaping (Error) -> Void,
canceled: @escaping () -> Void,
innerData: Any? = nil) {
self.request = request
self.completionWithData = completionWithData
self.completionWithError = completionWithError
self.canceled = canceled
self.innerData = innerData
}
}


private let lock = PThreadMutexLock()
private var tasks = [UInt64: TaskData]()


public func performRequest(requestId: UInt64, request: WebServiceBaseRequesting, completionWithData: @escaping (Any) -> Void, completionWithError: @escaping (Error) -> Void, canceled: @escaping () -> Void) {
do {
let data = RequestData(request: request, completionWithData: completionWithData, completionWithError: completionWithError, canceled: canceled)
if let af_request = try self.performRequest(requestId: requestId, data: data) {
startAlamofireRequest(af_request, requestId: requestId, data: data)
}
} catch {
completionWithError(error)
}
}

open func cancelRequest(requestId: UInt64) {
if let task:TaskData = lock.synchronized({ self.tasks.removeValue(forKey: requestId) }) {
task.request.cancel()
task.requestData.canceled()

canceledAlamofireRequest(task.request, requestId: requestId)
}
}



//MARK: - Need Override
open func isSupportedRequest(_ request: WebServiceBaseRequesting, rawDataTypeForRestoreFromStorage: Any.Type?) -> Bool {
fatalError("WebServiceAlamofireBaseEngine: require override isSupportedRequest(request:rawDataForRestoreFromStorage:) function. ")
}

open func performRequest(requestId: UInt64, data: RequestData) throws -> Alamofire.DataRequest? {
fatalError("WebServiceAlamofireBaseEngine: require override request(data:) function. You need use function startAlamofireRequest(:data:)")
}

open func dataHandler(request: WebServiceBaseRequesting, data: Any, isRawFromStorage: Bool) throws -> Any? {
fatalError("WebServiceAlamofireBaseEngine: require override dataHandler(request:data:isRawFromStorage:) function. ")
}


//MARK: Can override
open func canceledAlamofireRequest(_ request: Alamofire.DataRequest, requestId: UInt64) {

}

open func responseAlamofire(_ response: Alamofire.DataResponse<Data>, requestId: UInt64, requestData: RequestData) throws -> Any {
//Default implementation
switch response.result {
case .success(let data):
return data

case .failure(let error):
throw error
}
}



//MARK: - Helper
public func startAlamofireRequest(_ request: Alamofire.DataRequest, requestId: UInt64, data: RequestData) {
let task = TaskData(requestId: requestId, requestData: data, request: request)

lock.synchronized {
self.tasks[requestId] = task
}

task.request.responseData(queue: queueForDataHandlerFromStorage) { [weak self] response in
if let sSelf = self {
sSelf.lock.synchronized {
sSelf.tasks.removeValue(forKey: requestId)
}

do {
let result = try sSelf.responseAlamofire(response, requestId: requestId, requestData: data)
data.completionWithData(result)
} catch {
data.completionWithError(error)
}
} else {
data.canceled()
}
}
}

public func requestData(forSessionTask sessionTask: URLSessionTask) -> (requestId: UInt64, data: RequestData)? {
return lock.synchronized {
for (requestId, taskData) in tasks {
if taskData.request.task == sessionTask {
return (requestId, taskData.requestData)
}
}

return nil
}
}

public func updateRequestData(requestId: UInt64, data: RequestData) {
lock.synchronized {
tasks[requestId]?.requestData = data
}
}

}
121 changes: 121 additions & 0 deletions Source/Alamofire/WebServiceAlamofireSimpleEngine.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//
// WebServiceAlamofireSimpleEngine.swift
// WebServiceSwift 2.3.0
//
// Created by ViR (Короткий Виталий) on 01.06.2018.
// Copyright © 2018 ProVir. All rights reserved.
//

import Foundation
import Alamofire


//MARK: Request
public protocol WebServiceAlamofireBaseRequesting {
func afRequest(sessionManager: Alamofire.SessionManager) throws -> Alamofire.DataRequest

var afResponseType: WebServiceAlamofireResponseType { get }
func afBaseDecodeResponse(_ data: WebServiceAlamofireResponseData) throws -> Any?
}

public protocol WebServiceAlamofireRequesting: WebServiceAlamofireBaseRequesting, WebServiceRequesting {
func afDecodeResponse(_ data: WebServiceAlamofireResponseData) throws -> ResultType
}

public extension WebServiceAlamofireRequesting {
func afBaseDecodeResponse(_ data: WebServiceAlamofireResponseData) throws -> Any? {
return try afDecodeResponse(data)
}
}

//MARK: Response
public enum WebServiceAlamofireResponseType {
case binary
case json
}

public struct WebServiceAlamofireResponseData {
//Only one is not null
public let binary: Data!
public let json: Any!

public init(binary: Data) {
self.binary = binary
self.json = nil
}

public init(json: Any) {
self.json = json
self.binary = nil
}
}

//MARK: Auto decoders
protocol WebServiceAlamofireAutoDecoder: WebServiceRequesting { }

extension WebServiceAlamofireAutoDecoder where ResultType == Void {
var afResponseType: WebServiceAlamofireResponseType { return .binary }
func afDecodeResponse(_ data: WebServiceAlamofireResponseData) throws -> Void {
return Void()
}
}

extension WebServiceAlamofireAutoDecoder where ResultType == Data {
var afResponseType: WebServiceAlamofireResponseType { return .binary }
func afDecodeResponse(_ data: WebServiceAlamofireResponseData) throws -> Data {
return data.binary
}
}


//MARK: Engine
public class WebServiceAlamofireSimpleEngine: WebServiceAlamofireBaseEngine {
private let sessionManager: Alamofire.SessionManager

public init(sessionManager: Alamofire.SessionManager = Alamofire.SessionManager.default, queueForRequest: DispatchQueue? = nil, useNetworkActivityIndicator: Bool = true) {
self.sessionManager = sessionManager
super.init(queueForRequest: queueForRequest, useNetworkActivityIndicator: useNetworkActivityIndicator)
}

public override func isSupportedRequest(_ request: WebServiceBaseRequesting, rawDataTypeForRestoreFromStorage: Any.Type?) -> Bool {
return request is WebServiceAlamofireBaseRequesting
}

public override func performRequest(requestId: UInt64, data: WebServiceAlamofireBaseEngine.RequestData) throws -> DataRequest? {
guard let request = data.request as? WebServiceAlamofireBaseRequesting else {
throw WebServiceRequestError.notSupportRequest
}

return try request.afRequest(sessionManager: sessionManager)
}

public override func responseAlamofire(_ response: DataResponse<Data>, requestId: UInt64, requestData: WebServiceAlamofireBaseEngine.RequestData) throws -> Any {
switch response.result {
case .success(let data):
if let statusCode = response.response?.statusCode, statusCode >= 300 {
throw WebServiceResponseError.httpStatusCode(statusCode)
}

return data

case .failure(let error):
throw error
}
}

public override func dataHandler(request: WebServiceBaseRequesting, data: Any, isRawFromStorage: Bool) throws -> Any? {
guard let binary = data as? Data, let request = request as? WebServiceAlamofireBaseRequesting else {
throw WebServiceRequestError.notSupportDataHandler
}

switch request.afResponseType {
case .binary:
return try request.afBaseDecodeResponse(WebServiceAlamofireResponseData(binary: binary))

case .json:
let jsonData = try JSONSerialization.jsonObject(with: binary, options: [])
return try request.afBaseDecodeResponse(WebServiceAlamofireResponseData(json: jsonData))
}
}

}
38 changes: 38 additions & 0 deletions Source/PThreadMutexLock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// PThreadMutexLock.swift
// WebServiceExample
//
// Created by Короткий Виталий on 01.06.2018.
// Copyright © 2018 ProVir. All rights reserved.
//

import Foundation

internal class PThreadMutexLock: NSObject, NSLocking {
private var mutex = pthread_mutex_t()

override init() {
super.init()

pthread_mutex_init(&mutex, nil)
}

deinit {
pthread_mutex_destroy(&mutex)
}

func lock() {
pthread_mutex_lock(&mutex)
}

func unlock() {
pthread_mutex_unlock(&mutex)
}

@discardableResult
func synchronized<T>(_ handler: () throws -> T) rethrows -> T {
pthread_mutex_lock(&mutex)
defer { pthread_mutex_unlock(&mutex) }
return try handler()
}
}
29 changes: 0 additions & 29 deletions Source/WebService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -733,32 +733,3 @@ public class WebService {
}
}

//MARK: Helpers
private class PThreadMutexLock: NSObject, NSLocking {
private var mutex = pthread_mutex_t()

override init() {
super.init()

pthread_mutex_init(&mutex, nil)
}

deinit {
pthread_mutex_destroy(&mutex)
}

func lock() {
pthread_mutex_lock(&mutex)
}

func unlock() {
pthread_mutex_unlock(&mutex)
}

@discardableResult
func synchronized<T>(_ handler: () throws -> T) rethrows -> T {
pthread_mutex_lock(&mutex)
defer { pthread_mutex_unlock(&mutex) }
return try handler()
}
}
Loading

0 comments on commit 36a7acb

Please sign in to comment.