Build Status

用于 Vapor 3 的 S3 客户端

功能

用法

更新 Package.swift 中的依赖项和目标

dependencies: [
    ...
    .package(url: "https://github.com/LiveUI/S3.git", from: "3.0.0-RC3.2"),
],
targets: [
        .target(name: "App", dependencies: ["Vapor", "S3"]),
        ...
]

运行 vapor update

在您的 configure 方法中将 S3Client 注册为服务

try services.register(s3: S3Signer.Config(...), defaultBucket: "my-bucket")

要使用自定义 Minio 服务器,请使用此 Config/Region

S3Signer.Config(accessKey: accessKey,
                secretKey: secretKey,
                region: Region(name: RegionName.usEast1,
                               hostName: "127.0.0.1:9000",
                               useTLS: false)

使用 S3Client

import S3

let s3 = try req.makeS3Client() // or req.make(S3Client.self) as? S3
s3.put(...)
s3.get(...)
s3.delete(...)

如果您只想使用签名器

import S3Signer

let s3 = try req.makeS3Signer() // or req.make(S3Signer.self)
s3.headers(...)

可用方法

/// S3 client Protocol
public protocol S3Client: Service {
    
    /// Get list of objects
    func buckets(on: Container) -> EventLoopFuture<BucketsInfo>
    
    /// Create a bucket
    func create(bucket: String, region: Region?, on container: Container) -> EventLoopFuture<Void>
    
    /// Delete a bucket
    func delete(bucket: String, region: Region?, on container: Container) -> EventLoopFuture<Void>
    
    /// Get bucket location
    func location(bucket: String, on container: Container) -> EventLoopFuture<Region>
    
    /// Get list of objects
    func list(bucket: String, region: Region?, on container: Container) -> EventLoopFuture<BucketResults>
    
    /// Get list of objects
    func list(bucket: String, region: Region?, headers: [String: String], on container: Container) -> EventLoopFuture<BucketResults>
    
    /// Upload file to S3
    func put(file: File.Upload, headers: [String: String], on: Container) throws -> EventLoopEventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(file url: URL, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(file url: URL, destination: String, bucket: String?, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(file path: String, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(file path: String, destination: String, bucket: String?, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(string: String, destination: String, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(string: String, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(string: String, mime: MediaType, destination: String, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(string: String, mime: MediaType, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Upload file to S3
    func put(string: String, mime: MediaType, destination: String, bucket: String?, access: AccessControlList, on: Container) -> EventLoopFuture<File.Response>
    
    /// Retrieve file data from S3
    func get(fileInfo file: LocationConvertible, on container: Container) -> EventLoopFuture<File.Info>
    
    /// Retrieve file data from S3
    func get(fileInfo file: LocationConvertible, headers: [String: String], on container: Container) -> EventLoopFuture<File.Info>
    
    /// Retrieve file data from S3
    func get(file: LocationConvertible, on: Container) -> EventLoopFuture<File.Response>
    
    /// Retrieve file data from S3
    func get(file: LocationConvertible, headers: [String: String], on: Container) -> EventLoopFuture<File.Response>
    
    /// Delete file from S3
    func delete(file: LocationConvertible, on: Container) -> EventLoopFuture<Void>
    
    /// Delete file from S3
    func delete(file: LocationConvertible, headers: [String: String], on: Container) -> EventLoopFuture<Void>
}

用法示例

public func routes(_ router: Router) throws {
    
    // Get all available buckets
    router.get("buckets")  { req -> EventLoopFuture<BucketsInfo> in
        let s3 = try req.makeS3Client()
        return try s3.buckets(on: req)
    }
    
    // Create new bucket
    router.put("bucket")  { req -> EventLoopFuture<String> in
        let s3 = try req.makeS3Client()
        return try s3.create(bucket: "api-created-bucket", region: .euCentral1, on: req).map(to: String.self) {
            return ":)"
            }.catchMap({ (error) -> (String) in
                if let error = error.s3ErrorMessage() {
                    return error.message
                }
                return ":("
            }
        )
    }
    
    // Locate bucket (get region)
    router.get("bucket/location")  { req -> EventLoopFuture<String> in
        let s3 = try req.makeS3Client()
        return try s3.location(bucket: "bucket-name", on: req).map(to: String.self) { region in
            return region.hostUrlString()
        }.catchMap({ (error) -> (String) in
                if let error = error as? S3.Error {
                    switch error {
                    case .errorResponse(_, let error):
                        return error.message
                    default:
                        return "S3 :("
                    }
                }
                return ":("
            }
        )
    }
    // Delete bucket
    router.delete("bucket")  { req -> EventLoopFuture<String> in
        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
                if let error = error.s3ErrorMessage() {
                    return error.message
                }
                return ":("
                }
        )
    }
    
    // Get list of objects
    router.get("files")  { req -> EventLoopFuture<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.s3ErrorMessage() {
                print(error.message)
            }
            throw error
        })
    }
    
    // Demonstrate work with files
    router.get("files/test") { req -> EventLoopFuture<String> in
        let string = "Content of my example file"
        
        let fileName = "file-hu.txt"
        
        let s3 = try req.makeS3Client()
        do {
            // Upload a file from string
            return try s3.put(string: string, destination: fileName, access: .publicRead, on: req).flatMap(to: String.self) { putResponse in
                print("PUT response:")
                print(putResponse)
                // Get the content of the newly uploaded file
                return try s3.get(file: fileName, on: req).flatMap(to: String.self) { getResponse in
                    print("GET response:")
                    print(getResponse)
                    print(String(data: getResponse.data, encoding: .utf8) ?? "Unknown content!")
                    // Get info about the file (HEAD)
                    return try s3.get(fileInfo: fileName, on: req).flatMap(to: String.self) { infoResponse in
                        print("HEAD/Info response:")
                        print(infoResponse)
                        // Delete the file
                        return try s3.delete(file: fileName, on: req).map() { response in
                            print("DELETE response:")
                            print(response)
                            let json = try JSONEncoder().encode(infoResponse)
                            return String(data: json, encoding: .utf8) ?? "Unknown content!"
                            }.catchMap({ error -> (String) in
                                if let error = error.s3ErrorMessage() {
                                    return error.message
                                }
                                return ":("
                            }
                        )
                    }
                }
            }
        } catch {
            print(error)
            fatalError()
        }
    }
}

支持

加入我们的 Slack,频道 #help-boost 来... 获得帮助 :)

Einstore 应用商店

Einstore 的核心包,一个完全开源的 Swift 企业应用商店!

其他核心包

代码贡献

我们喜欢 PR,我们对它们的需求永不满足...所以如果您有一个有趣的改进、错误修复或新功能,请随时与我们联系。如果您在开始开发之前对某些事情不确定,您可以随时通过我们的 Slack 联系我们的开发和产品团队。

致谢

作者

Ondrej Rafaj(在 Github 上 @rafiki270,在 Twitter 上 @rafiki270,在 LiveUI SlackVapor Slack

感谢

Anthoni Castelli(在 Github 上 @anthonycastelli,在 Vapor Slack 上 @anthony)感谢他在更新 Vapor3 的 S3Signer 方面的帮助

JustinM1(在 Github 上 @JustinM1)感谢他的精彩原创签名器包

许可

有关更多信息,请参见 LICENSE 文件。