Skip to content

Commit

Permalink
Merge pull request #21 from AppcentMobile/feature/download-support
Browse files Browse the repository at this point in the history
Feature/download support
  • Loading branch information
burakcolakappcent authored Dec 28, 2023
2 parents 3537b49 + 2957996 commit f398484
Show file tree
Hide file tree
Showing 15 changed files with 351 additions and 131 deletions.
79 changes: 38 additions & 41 deletions Sources/ACMNetworking/ACMNetworking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,54 @@ import Foundation

/// ACMNetworking, make requests easily
public class ACMNetworking: NSObject {
private var task: URLSessionDataTask?
var mainEndpoint: ACMBaseEndpoint?
var session: URLSession?
var requestTask: URLSessionDataTask?
var downloadTask: URLSessionDownloadTask?
var taskProgress: NSKeyValueObservation?

/// Predefined variables
var logger: ACMBaseLogger? {
mainEndpoint?.logger
}

var stringUtils: ACMStringUtils? {
mainEndpoint?.stringUtils
}

/// Public Init function
/// For creating object with SDK
override public init() {
super.init()
}

/// Main request function
///
/// - Parameters:
/// - endpoint: base endpoint that keeps all endpoint information
/// - currentRetryCount(Optional): retry request count
/// - onSuccess: Callback for success scenario
/// - onError: Callback for error scenario
///
/// - Returns:
/// - Void
public func request<T: Decodable>(to endpoint: ACMBaseEndpoint,
currentRetryCount: Int? = 0,
onSuccess: ACMGenericCallbacks.ResponseCallback<T>,
onError: ACMGenericCallbacks.ErrorCallback)
{
guard let urlRequest = generateURLRequest(endpoint: endpoint) else { return }

task = endpoint.session(delegate: self).dataTask(with: urlRequest) { [weak self] data, response, error in
guard let self else { return }

self.handleNilErrorResponse(with: endpoint, error: error, onError: onError)
self.handleNilResponse(with: endpoint, response: response, onError: onError)
self.handleConnectivityError(with: endpoint, error: error, onError: onError)

guard let data = self.handleData(with: endpoint, data: data, onError: onError) else { return }
guard let httpResponse = self.handleHttpResponse(with: endpoint, response: response, onError: onError) else { return }

// Check if response is in valid http range
guard self.validateResponse(with: httpResponse) else {
self.executeRetry(with: endpoint, httpResponse: httpResponse, data: data, currentRetryCount: currentRetryCount, onSuccess: onSuccess, onError: onError)
return
}

self.cancel()

self.handleResult(with: endpoint, data: data, onSuccess: onSuccess, onError: onError)
}
task?.resume()
/// Public destroy function
deinit {
print("ACMNetworking deinited")
}

/// Cancels the current network request
public func cancel() {
task?.cancel()
task = nil
cancelRequestTask()
cancelDownloadTask()
session?.invalidateAndCancel()
session = nil
taskProgress?.invalidate()
taskProgress = nil
mainEndpoint = nil
}

private func cancelRequestTask() {
if requestTask?.state == .running {
requestTask?.cancel()
}
requestTask = nil
}

private func cancelDownloadTask() {
if downloadTask?.state == .running {
downloadTask?.cancel()
}
downloadTask = nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ public enum ACMGenericCallbacks {
public typealias InfoCallback = ((Bool?, Error?) -> Void)?
/// Success callback with generic response for closures
public typealias ResponseCallback<T> = ((T) -> Void)?
/// Success callback with generic response for closures
public typealias DownloadCallback = ((ACMDownloadModel) -> Void)?
/// Progress callback with generic response for closures
public typealias ProgressCallback = ((ACMProgressModel) -> Void)?
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
//

enum ACMNetworkingConstants {
static var configOverride: Bool = false
static var configOverride: Bool? = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public enum ACMNetworkConstants {
public static var httpBodyMultipart = "Multipart data, length: %@"
/// Info message for retry mechanism
public static var httpRetryCount = "Current retry count is %d, total retry count is %d"
/// Error message if data is invalid and could not be parsed
public static var genericErrorMessage = "Generic error : %@"
}

public extension ACMNetworkConstants {
Expand All @@ -52,12 +54,12 @@ public extension ACMNetworkConstants {
}

/// Header for holding multipart header with content type
static func multipartHeader(model: ACMMultipartContentTypeModel) -> ACMHeaderModel {
ACMHeaderModel(field: "Content-Type", value: ACMStringUtils.shared.merge(list: [
static func multipartHeader(model: ACMMultipartContentTypeModel, utils: ACMStringUtils?) -> ACMHeaderModel {
ACMHeaderModel(field: "Content-Type", value: utils?.merge(list: [
model.type,
" ",
model.boundary,
]))
]) ?? "")
}

/// Header for holding multipart accept type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,65 @@ import Foundation
extension ACMNetworking {
func baseRequest(to endpoint: ACMBaseEndpoint) -> URLRequest? {
guard let urlRequest = endpoint.urlRequest else {
ACMBaseLogger.error(ACMNetworkConstants.urlRequestErrorMessage)
endpoint.logger?.error(ACMNetworkConstants.urlRequestErrorMessage)
return nil
}

let info = ACMStringUtils.shared.merge(list: [
var infoList = [
ACMNetworkConstants.httpRequestType,
endpoint.method.rawValue,
])
ACMBaseLogger.info(info)
]

if let methodRaw = endpoint.method?.rawValue {
infoList.append(methodRaw)
}

let info = endpoint.stringUtils?.merge(list: infoList)
endpoint.logger?.info(info)

if let url = endpoint.url {
let info = ACMStringUtils.shared.merge(list: [
let info = endpoint.stringUtils?.merge(list: [
ACMNetworkConstants.httpURLMessage,
"\(url)",
])
ACMBaseLogger.info(info)
endpoint.logger?.info(info)
}

if let authHeader = endpoint.authHeader {
let info = ACMStringUtils.shared.merge(list: [
let info = endpoint.stringUtils?.merge(list: [
ACMNetworkConstants.httpAuthHeadersMessage,
"\(authHeader)",
])
ACMBaseLogger.info(info)
endpoint.logger?.info(info)
}

if let headers = endpoint.headers, headers.count > 0 {
let info = ACMStringUtils.shared.merge(list: [
let info = endpoint.stringUtils?.merge(list: [
ACMNetworkConstants.httpHeadersMessage,
"\(headers)",
])
ACMBaseLogger.info(info)
endpoint.logger?.info(info)
}

if let queryItems = endpoint.queryItems, queryItems.count > 0 {
let info = ACMStringUtils.shared.merge(list: [
let info = endpoint.stringUtils?.merge(list: [
ACMNetworkConstants.httpQueryItemsMessage,
"\(queryItems)",
])
ACMBaseLogger.info(info)
endpoint.logger?.info(info)
}

if let params = endpoint.params {
let info = ACMStringUtils.shared.merge(list: [
let info = endpoint.stringUtils?.merge(list: [
ACMNetworkConstants.httpBodyMessage,
params.paramsRaw,
])
ACMBaseLogger.info(info)
endpoint.logger?.info(info)
} else if let data = endpoint.mediaData {
let info = ACMStringUtils.shared.merge(list: [
let info = endpoint.stringUtils?.merge(list: [
ACMNetworkConstants.httpBodyMessage,
String(format: ACMNetworkConstants.httpBodyMultipart, "\(data.length)"),
])
ACMBaseLogger.info(info)
endpoint.logger?.info(info)
}

return urlRequest
Expand All @@ -75,13 +80,13 @@ extension ACMNetworking: URLSessionTaskDelegate {
/// - task: URL session task
/// - didFinishCollecting: Metrics that gathered
public func urlSession(_: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
let message = ACMStringUtils.shared.merge(list: [
let message = mainEndpoint?.stringUtils?.merge(list: [
"didFinishCollecting",
task.description,
"metrics",
"\(metrics.taskInterval)",
])
ACMBaseLogger.info(message)
logger?.info(message)
}

/// URL Session taskIsWaitingForConnectivity
Expand All @@ -90,11 +95,11 @@ extension ACMNetworking: URLSessionTaskDelegate {
/// - session: URL Session
/// - task: URL session task
public func urlSession(_: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {
let message = ACMStringUtils.shared.merge(list: [
let message = mainEndpoint?.stringUtils?.merge(list: [
"taskIsWaitingForConnectivity",
task.description,
])
ACMBaseLogger.info(message)
logger?.info(message)
}

/// URL Session didSendBodyData
Expand All @@ -106,7 +111,7 @@ extension ACMNetworking: URLSessionTaskDelegate {
/// - totalBytesSent
/// - totalBytesExpectedToSend
public func urlSession(_: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
let message = ACMStringUtils.shared.merge(list: [
let message = mainEndpoint?.stringUtils?.merge(list: [
"task",
task.description,
"didSendBodyData",
Expand All @@ -116,6 +121,6 @@ extension ACMNetworking: URLSessionTaskDelegate {
"totalBytesExpectedToSend",
"\(totalBytesExpectedToSend)",
])
ACMBaseLogger.info(message)
logger?.info(message)
}
}
Loading

0 comments on commit f398484

Please sign in to comment.