Sources/XCMetricsBackendLib/UploadMetrics/Repository/LogFileS3Repository.swift (56 lines of code) (raw):

// Copyright (c) 2020 Spotify AB. // // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. import Foundation import Vapor import S3 /// `LogFileRepository` that uses Amazon S3 to store and fetch logs struct LogFileS3Repository: LogFileRepository { let bucketName: String let s3: S3 init(accessKey: String, bucketName: String, regionName: String, secretAccessKey: String) { self.bucketName = bucketName guard let region = Region(rawValue: regionName) else { preconditionFailure("Invalid S3 Region \(regionName)") } self.s3 = S3(accessKeyId: accessKey, secretAccessKey: secretAccessKey, region: region) } init?(config: Configuration) { guard let bucketName = config.s3Bucket, let accessKey = config.awsAccessKeyId, let secretAccessKey = config.awsSecretAccessKey, let regionName = config.s3Region else { return nil } self.init(accessKey: accessKey, bucketName: bucketName, regionName: regionName, secretAccessKey: secretAccessKey) } func put(logFile: File) throws -> URL { let data = Data(logFile.data.xcm_onlyFileData().readableBytesView) let putObjectRequest = S3.PutObjectRequest(acl: .private, body: data, bucket: bucketName, contentLength: Int64(data.count), key: logFile.filename) let fileURL = try s3.putObject(putObjectRequest) .map { _ -> URL? in return URL(string: "s3://\(bucketName)/\(logFile.filename)") }.wait() guard let url = fileURL else { throw RepositoryError.unexpected(message: "Invalid url of \(logFile.filename)") } return url } func get(logURL: URL) throws -> LogFile { guard let bucket = logURL.host else { throw RepositoryError.unexpected(message: "URL is not an S3 url \(logURL)") } let fileName = logURL.lastPathComponent let request = S3.GetObjectRequest(bucket: bucket, key: fileName) let fileData = try s3.getObject(request) .map { response -> Data? in return response.body }.wait() guard let data = fileData else { throw RepositoryError.unexpected(message: "There was an error downloading file \(logURL)") } let tmp = try TemporaryFile(creatingTempDirectoryForFilename: "\(UUID().uuidString).xcactivitylog") try data.write(to: tmp.fileURL) return LogFile(remoteURL: logURL, localURL: tmp.fileURL) } }