-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
378 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
github "Alamofire/Alamofire" ~> 4.7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,7 @@ target 'WebServiceExample' do | |
pod 'Alamofire' | ||
end | ||
|
||
target 'WebServiceSwift' do | ||
pod 'Alamofire' | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.