Skip to content

Commit

Permalink
listing objects works
Browse files Browse the repository at this point in the history
  • Loading branch information
rafiki270 committed May 12, 2018
1 parent d6b3a3b commit 83686e3
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 4 deletions.
26 changes: 26 additions & 0 deletions Sources/S3/Extensions/S3+List.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ import Foundation
// Helper S3 extension for getting file indexes
extension S3 {

/// Get list of objects
public func list(bucket: String, region: Region? = nil, headers: [String: String], on container: Container) throws -> Future<BucketResults> {
let signer = try container.makeS3Signer()
let region = region ?? signer.config.region
guard let baseUrl = URL(string: "https://\(bucket).s3.\(region.rawValue).amazonaws.com/"), let host = baseUrl.host,
var components = URLComponents(string: baseUrl.absoluteString) else {
throw S3.Error.invalidUrl
}
components.queryItems = [
URLQueryItem(name: "list-type", value: "2")
]
guard let url = components.url else {
throw S3.Error.invalidUrl
}
var headers = headers
headers["Host"] = host
let awsHeaders = try signer.headers(for: .GET, urlString: url.absoluteString, region: region, headers: headers, payload: .none)
return try make(request: url, method: .GET, headers: awsHeaders, data: "".convertToData(), on: container).map(to: BucketResults.self) { response in
try self.check(response)
return try response.decode(to: BucketResults.self)
}
}

/// Get list of objects
public func list(bucket: String, region: Region? = nil, on container: Container) throws -> Future<BucketResults> {
return try list(bucket: bucket, region: region, headers: [:], on: container)
}

}
68 changes: 67 additions & 1 deletion Sources/S3/Models/BucketResults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,72 @@ import Foundation
import Vapor


public class BucketResults {
public struct BucketResults: Content {

/// Name of the bucket
public let name: String

/// Keys that begin with the indicated prefix
public let prefix: String?

/**
All of the keys rolled up into a common prefix count as a single return when calculating the number of returns. See MaxKeys.

A response can contain CommonPrefixes only if you specify a delimiter.
CommonPrefixes contains all (if there are any) keys between Prefix and the next occurrence of the string specified by a delimiter.
CommonPrefixes lists keys that act like subdirectories in the directory specified by Prefix.
For example, if the prefix is notes/ and the delimiter is a slash (/) as in notes/summer/july, the common prefix is notes/summer/. All of the keys that roll up into a common prefix count as a single return when calculating the number of returns. See MaxKeys
*/
public let commonPrefixes: [CommonPrefix]?

/// Returns the number of keys included in the response. The value is always less than or equal to the MaxKeys value
public let keyCount: Int

/// The maximum number of keys returned in the response body
public let maxKeys: Int

/// Causes keys that contain the same string between the prefix and the first occurrence of the delimiter to be rolled up into a single result element in the CommonPrefixes collection. These rolled-up keys are not returned elsewhere in the response. Each rolled-up result counts as only one return against the MaxKeys value
public let delimiter: String?

/// Encoding type used by Amazon S3 to encode object key names in the XML response
public let encodingType: String?

/// Pagination; If StartAfter was sent with the request, it is included in the response
public let startAfter: String?

/// If the response is truncated, Amazon S3 returns this parameter with a continuation token. You can specify the token as the continuation-token in your next request to retrieve the next set of keys
public let nextContinuationToken: String?

/// Set to false if all of the results were returned. Set to true if more keys are available to return. If the number of results exceeds that specified by MaxKeys, all of the results might not be returned
public let isTruncated: Bool

/// Objects
public let objects: [Object]

enum CodingKeys: String, CodingKey {
case name = "Name"
case prefix = "Prefix"
case commonPrefixes = "CommonPrefixes"
case keyCount = "KeyCount"
case maxKeys = "MaxKeys"
case delimiter = "Delimiter"
case encodingType = "Encoding-Type"
case startAfter = "StartAfter"
case nextContinuationToken = "NextContinuationToken"
case isTruncated = "IsTruncated"
case objects = "Contents"
}

}


public struct CommonPrefix: Codable {

/// Common prefix name
let path: String

enum CodingKeys: String, CodingKey {
case path = "Prefix"
}

}
42 changes: 42 additions & 0 deletions Sources/S3/Models/Object.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Object.swift
// S3
//
// Created by Ondrej Rafaj on 12/05/2018.
//

import Foundation
import Vapor


/// S3 object
public struct Object: Content {

/// The object's key / file name
let fileName: String

/// STANDARD | STANDARD_IA | ONEZONE_IA | REDUCED_REDUNDANCY | GLACIER
public let storageClass: String?

/// The entity tag is an MD5 hash of the object. ETag reflects only changes to the contents of an object, not its metadata
public let etag: String

/// Owner
public let owner: Owner?

/// Size in bytes of the object
public let size: Int?

/// Date and time the object was last modified
public let lastModified: Date

enum CodingKeys: String, CodingKey {
case fileName = "Key"
case storageClass = "StorageClass"
case etag = "ETag"
case owner = "Owner"
case size = "Size"
case lastModified = "LastModified"
}

}
7 changes: 7 additions & 0 deletions Sources/S3/Models/Owner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ import Vapor
/// Owner object
public struct Owner: Content {

/// Owner's ID
public let id: String

/**
Owner's name
- *This value is only included in the response in the US East (N. Virginia), US West (N. California), US West (Oregon), Asia Pacific (Singapore), Asia Pacific (Sydney), Asia Pacific (Tokyo), EU (Ireland), and South America (São Paulo) regions.*
- *For a list of all the Amazon S3 supported regions and endpoints, see Regions and Endpoints in the AWS General Reference.*
*/
public let name: String?

enum CodingKeys: String, CodingKey {
Expand Down
43 changes: 43 additions & 0 deletions Sources/S3/Protocols/S3Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,75 @@ import Foundation
import Vapor


/// S3 client Protocol
public protocol S3Client: Service {

/// Get list of objects
func buckets(on: Container) throws -> Future<BucketsInfo>

/// Create a bucket
func create(bucket: String, region: Region?, on container: Container) throws -> Future<Void>

/// Delete a bucket wherever it is
// func delete(bucket: String, on container: Container) throws -> Future<Void>

/// Delete a bucket
func delete(bucket: String, region: Region?, on container: Container) throws -> Future<Void>

/// Get bucket location
// func location(bucket: String, on container: Container) throws -> Future<Bucket.Location>

/// Get list of objects
func list(bucket: String, region: Region?, on container: Container) throws -> Future<BucketResults>

/// Get list of objects
func list(bucket: String, region: Region?, headers: [String: String], on container: Container) throws -> Future<BucketResults>

/// Upload file to S3
func put(file: File.Upload, headers: [String: String], on: Container) throws -> EventLoopFuture<File.Response>

/// Upload file to S3
func put(file url: URL, destination: String, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(file url: URL, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(file path: String, destination: String, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(file path: String, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(string: String, destination: String, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(string: String, destination: String, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(string: String, mime: MediaType, destination: String, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(string: String, mime: MediaType, destination: String, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Upload file to S3
func put(string: String, mime: MediaType, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future<File.Response>

/// Retrieve file data from S3
func get(fileInfo file: LocationConvertible, on container: Container) throws -> Future<File.Info>

/// Retrieve file data from S3
func get(fileInfo file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future<File.Info>

/// Retrieve file data from S3
func get(file: LocationConvertible, on: Container) throws -> Future<File.Response>

/// Retrieve file data from S3
func get(file: LocationConvertible, headers: [String: String], on: Container) throws -> Future<File.Response>

/// Delete file from S3
func delete(file: LocationConvertible, on: Container) throws -> Future<Void>

/// Delete file from S3
func delete(file: LocationConvertible, headers: [String: String], on: Container) throws -> Future<Void>
}
17 changes: 14 additions & 3 deletions Sources/S3DemoApp/S3DemoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,26 @@ public func routes(_ router: Router) throws {
let s3 = try req.makeS3Client()
return try s3.delete(bucket: "api-created-bucket", region: .euCentral1, on: req).map(to: String.self) {
return ":)"
}.catchMap({ (error) -> (String) in
}.catchMap({ (error) -> (String) in
if let error = error.s3ErroMessage() {
return error.message
}
return ":("
}
}
)
}

// Delete bucket
router.get("files") { req -> Future<BucketResults> in
let s3 = try req.makeS3Client()
return try s3.list(bucket: "booststore", region: .usEast1, headers: [:], on: req).catchMap({ (error) -> (BucketResults) in
if let error = error.s3ErroMessage() {
print(error.message)
}
throw error
})
}

// // Bucket location
// router.get("bucket/location") { req -> Future<String> in
// let s3 = try req.makeS3Client()
Expand All @@ -58,7 +69,7 @@ public func routes(_ router: Router) throws {
// }

// Demonstrate work with files
router.get("files") { req -> Future<String> in
router.get("files/test") { req -> Future<String> in
let string = "Content of my example file"

let fileName = "file-hu.txt"
Expand Down

0 comments on commit 83686e3

Please sign in to comment.