Skip to content

Commit

Permalink
[Swift3] Download file fix
Browse files Browse the repository at this point in the history
  • Loading branch information
dwbiid committed Aug 9, 2017
1 parent 5d263e1 commit beb89bc
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,62 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
nil
)
})
case is URL.Type:
validatedRequest.responseData(completionHandler: { (dataResponse) in
cleanupRequest()
do {
guard !dataResponse.result.isFailure else {
throw DownloadException.responseFailed
}

guard let data = dataResponse.data else {
throw DownloadException.responseDataMissing
}

guard let request = request.request else {
throw DownloadException.requestMissing
}

let fileManager = FileManager.default
let urlRequest = try request.asURLRequest()
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let requestURL = try self.getURL(from: urlRequest)

var requestPath = try self.getPath(from: requestURL)

if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) {
requestPath = requestPath.appending("/\(headerFileName)")
}

let filePath = documentsDirectory.appendingPathComponent(requestPath)
let directoryPath = filePath.deletingLastPathComponent().path

try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
try data.write(to: filePath, options: .atomic)

completion(
Response(
response: dataResponse.response!,
body: (filePath as! T)
),
nil
)

} catch let requestParserError as DownloadException {
completion(
nil,
ErrorResponse.Error(400, dataResponse.data, requestParserError)
)
} catch let error {
completion(
nil,
ErrorResponse.Error(400, dataResponse.data, error)
)
}
return
})
default:
validatedRequest.responseJSON(options: .allowFragments) { response in
cleanupRequest()
Expand Down Expand Up @@ -253,4 +309,63 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
return httpHeaders
}
}
fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? {
guard let contentDisposition = contentDisposition else {
return nil
}
let items = contentDisposition.components(separatedBy: ";")
var filename : String? = nil
for contentItem in items {
let filenameKey = "filename="
guard let range = contentItem.range(of: filenameKey) else {
break
}
filename = contentItem
return filename?
.replacingCharacters(in: range, with:"")
.replacingOccurrences(of: "\"", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
}
return filename
}
fileprivate func getPath(from url : URL) throws -> String {
guard var path = NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.path else {
throw DownloadException.requestMissingPath
}
if path.hasPrefix("/") {
path.remove(at: path.startIndex)
}
return path
}
fileprivate func getURL(from urlRequest : URLRequest) throws -> URL {
guard let url = urlRequest.url else {
throw DownloadException.requestMissingURL
}
return url
}
fileprivate enum DownloadException : Error {
case responseDataMissing
case responseFailed
case requestMissing
case requestMissingPath
case requestMissingURL
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.3.0-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ Pod::Spec.new do |s|
s.license = 'Proprietary'
s.homepage = 'https://github.com/swagger-api/swagger-codegen'
s.summary = 'SwaggerClient Swift SDK'
s.source_files = 'SwaggerClient/Classes/Swaggers/**/*.swift'
s.dependency 'Alamofire', '~> 3.4.1'
s.source_files = 'SwaggerClient/Classes/**/*.swift'
s.dependency 'Alamofire', '~> 3.5.1'
end
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,97 @@ extension NSUUID: JSONEncodable {
}
}

/// Represents an ISO-8601 full-date (RFC-3339).
/// ex: 12-31-1999
/// https://xml2rfc.tools.ietf.org/public/rfc/html/rfc3339.html#anchor14
public final class ISOFullDate: CustomStringConvertible {

public let year: Int
public let month: Int
public let day: Int

public init(year year: Int, month: Int, day: Int) {
self.year = year
self.month = month
self.day = day
}

/**
Converts an NSDate to an ISOFullDate. Only interested in the year, month, day components.

- parameter date: The date to convert.

- returns: An ISOFullDate constructed from the year, month, day of the date.
*/
public static func from(date date: NSDate) -> ISOFullDate? {
guard let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian) else {
return nil
}

let components = calendar.components(
[
.Year,
.Month,
.Day,
],
fromDate: date
)
return ISOFullDate(
year: components.year,
month: components.month,
day: components.day
)
}

/**
Converts a ISO-8601 full-date string to an ISOFullDate.

- parameter string: The ISO-8601 full-date format string to convert.

- returns: An ISOFullDate constructed from the string.
*/
public static func from(string string: String) -> ISOFullDate? {
let components = string
.characters
.split("-")
.map(String.init)
.flatMap { Int($0) }
guard components.count == 3 else { return nil }

return ISOFullDate(
year: components[0],
month: components[1],
day: components[2]
)
}

/**
Converts the receiver to an NSDate, in the default time zone.

- returns: An NSDate from the components of the receiver, in the default time zone.
*/
public func toDate() -> NSDate? {
let components = NSDateComponents()
components.year = year
components.month = month
components.day = day
components.timeZone = NSTimeZone.defaultTimeZone()
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
return calendar?.dateFromComponents(components)
}

// MARK: CustomStringConvertible

public var description: String {
return "\(year)-\(month)-\(day)"
}

}

extension ISOFullDate: JSONEncodable {
public func encodeToJSON() -> AnyObject {
return "\(year)-\(month)-\(day)"
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,16 @@ class Decoders {
return NSDate(timeIntervalSince1970: Double(sourceInt / 1000) )
}
fatalError("formatter failed to parse \(source)")
}
}

// Decoder for ISOFullDate
Decoders.addDecoder(clazz: ISOFullDate.self, decoder: { (source: AnyObject) -> ISOFullDate in
if let string = source as? String,
let isoDate = ISOFullDate.from(string: string) {
return isoDate
}
fatalError("formatter failed to parse \(source)")
})

// Decoder for [Return]
Decoders.addDecoder(clazz: [Return].self) { (source: AnyObject) -> [Return] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,62 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
nil
)
})
case is URL.Type:
validatedRequest.responseData(completionHandler: { (dataResponse) in
cleanupRequest()

do {

guard !dataResponse.result.isFailure else {
throw DownloadException.responseFailed
}

guard let data = dataResponse.data else {
throw DownloadException.responseDataMissing
}

guard let request = request.request else {
throw DownloadException.requestMissing
}

let fileManager = FileManager.default
let urlRequest = try request.asURLRequest()
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let requestURL = try self.getURL(from: urlRequest)

var requestPath = try self.getPath(from: requestURL)

if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) {
requestPath = requestPath.appending("/\(headerFileName)")
}

let filePath = documentsDirectory.appendingPathComponent(requestPath)
let directoryPath = filePath.deletingLastPathComponent().path

try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
try data.write(to: filePath, options: .atomic)

completion(
Response(
response: dataResponse.response!,
body: (filePath as! T)
),
nil
)

} catch let requestParserError as DownloadException {
completion(
nil,
ErrorResponse.Error(400, dataResponse.data, requestParserError)
)
} catch let error {
completion(
nil,
ErrorResponse.Error(400, dataResponse.data, error)
)
}
return
})
default:
validatedRequest.responseJSON(options: .allowFragments) { response in
cleanupRequest()
Expand Down Expand Up @@ -253,4 +309,63 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
return httpHeaders
}
}

fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? {

guard let contentDisposition = contentDisposition else {
return nil
}

let items = contentDisposition.components(separatedBy: ";")

var filename : String? = nil

for contentItem in items {

let filenameKey = "filename="
guard let range = contentItem.range(of: filenameKey) else {
break
}

filename = contentItem
return filename?
.replacingCharacters(in: range, with:"")
.replacingOccurrences(of: "\"", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
}

return filename

}

fileprivate func getPath(from url : URL) throws -> String {

guard var path = NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.path else {
throw DownloadException.requestMissingPath
}

if path.hasPrefix("/") {
path.remove(at: path.startIndex)
}

return path

}

fileprivate func getURL(from urlRequest : URLRequest) throws -> URL {

guard let url = urlRequest.url else {
throw DownloadException.requestMissingURL
}

return url
}

fileprivate enum DownloadException : Error {
case responseDataMissing
case responseFailed
case requestMissing
case requestMissingPath
case requestMissingURL
}
}

0 comments on commit beb89bc

Please sign in to comment.