Skip to content

Commit

Permalink
fix(storage): cache control
Browse files Browse the repository at this point in the history
  • Loading branch information
grdsdev committed Oct 3, 2024
1 parent 8f61141 commit 30955b4
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 65 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"Supabase",
"whitespaces",
"xctest"
]
],
"makefile.configureOnOpen": false
}
137 changes: 73 additions & 64 deletions Sources/Storage/StorageFileApi.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import Foundation
import Helpers

import class MultipartFormData.MultipartFormData

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let DEFAULT_SEARCH_OPTIONS = SearchOptions(
let defaultSearchOptions = SearchOptions(
limit: 100,
offset: 0,
sortBy: SortBy(
Expand All @@ -21,6 +22,40 @@ private let defaultFileOptions = FileOptions(
upsert: false
)

enum FileUpload {
case data(Data)
case url(URL)

func encode(to formData: MultipartFormData, withPath path: String, options: FileOptions) {
formData.append(
options.cacheControl.data(using: .utf8)!,
withName: "cacheControl"
)

if let metadata = options.metadata {
formData.append(encodeMetadata(metadata), withName: "metadata")
}

switch self {
case let .data(data):
formData.append(
data,
withName: "",
fileName: path.fileName,
mimeType: options.contentType ?? mimeType(forPathExtension: path.pathExtension)
)

case let .url(url):
formData.append(url, withName: "")
}
}

private func encodeMetadata(_ metadata: JSONObject) -> Data {
let encoder = AnyJSON.encoder
return (try? encoder.encode(metadata)) ?? "{}".data(using: .utf8)!
}
}

/// Supabase Storage File API
public class StorageFileApi: StorageApi, @unchecked Sendable {
/// The bucket id to operate on.
Expand All @@ -39,36 +74,23 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
let signedURL: URL
}

private func encodeMetadata(_ metadata: JSONObject) -> Data {
let encoder = AnyJSON.encoder
return (try? encoder.encode(metadata)) ?? "{}".data(using: .utf8)!
}

private func _uploadOrUpdate(
method: HTTPMethod,
path: String,
formData: MultipartFormData,
file: FileUpload,
options: FileOptions?
) async throws -> FileUploadResponse {
let options = options ?? defaultFileOptions
var headers = options.headers.map { HTTPHeaders($0) } ?? HTTPHeaders()

let metadata = options.metadata

if method == .post {
headers.update(name: "x-upsert", value: "\(options.upsert)")
}

headers["duplex"] = options.duplex

if let metadata {
formData.append(encodeMetadata(metadata), withName: "metadata")
}

formData.append(
options.cacheControl.data(using: .utf8)!,
withName: "cacheControl"
)
let formData = MultipartFormData()
file.encode(to: formData, withPath: path, options: options)

struct UploadResponse: Decodable {
let Key: String
Expand Down Expand Up @@ -109,27 +131,26 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
data: Data,
options: FileOptions = FileOptions()
) async throws -> FileUploadResponse {
let fileName = path.fileName
let formData = MultipartFormData()
formData.append(
data,
withName: fileName,
fileName: fileName,
mimeType: options.contentType ?? mimeType(forPathExtension: path.pathExtension)
try await _uploadOrUpdate(
method: .post,
path: path,
file: .data(data),
options: options
)
return try await _uploadOrUpdate(method: .post, path: path, formData: formData, options: options)
}

@discardableResult
public func upload(
_ path: String,
fileURL: Data,
fileURL: URL,
options: FileOptions = FileOptions()
) async throws -> FileUploadResponse {
let fileName = path.fileName
let formData = MultipartFormData()
formData.append(fileURL, withName: fileName, fileName: fileName)
return try await _uploadOrUpdate(method: .post, path: path, formData: formData, options: options)
try await _uploadOrUpdate(
method: .post,
path: path,
file: .url(fileURL),
options: options
)
}

/// Replaces an existing file at the specified path with a new one.
Expand All @@ -144,15 +165,12 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
data: Data,
options: FileOptions = FileOptions()
) async throws -> FileUploadResponse {
let fileName = path.fileName
let formData = MultipartFormData()
formData.append(
data,
withName: fileName,
fileName: fileName,
mimeType: options.contentType ?? mimeType(forPathExtension: path.pathExtension)
try await _uploadOrUpdate(
method: .put,
path: path,
file: .data(data),
options: options
)
return try await _uploadOrUpdate(method: .put, path: path, formData: formData, options: options)
}

/// Replaces an existing file at the specified path with a new one.
Expand All @@ -167,9 +185,12 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
fileURL: URL,
options: FileOptions = FileOptions()
) async throws -> FileUploadResponse {
let formData = MultipartFormData()
formData.append(fileURL, withName: path.fileName)
return try await _uploadOrUpdate(method: .put, path: path, formData: formData, options: options)
try await _uploadOrUpdate(
method: .put,
path: path,
file: .url(fileURL),
options: options
)
}

/// Moves an existing file, optionally renaming it at the same time.
Expand Down Expand Up @@ -388,7 +409,7 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
) async throws -> [FileObject] {
let encoder = JSONEncoder()

var options = options ?? DEFAULT_SEARCH_OPTIONS
var options = options ?? defaultSearchOptions
options.prefix = path ?? ""

return try await execute(
Expand Down Expand Up @@ -579,18 +600,10 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
data: Data,
options: FileOptions? = nil
) async throws -> SignedURLUploadResponse {
let fileName = path.fileName
let formData = MultipartFormData()
formData.append(
data,
withName: fileName,
fileName: fileName,
mimeType: options?.contentType ?? mimeType(forPathExtension: path.pathExtension)
)
return try await _uploadToSignedURL(
try await _uploadToSignedURL(
path: path,
token: token,
formData: formData,
file: .data(data),
options: options
)
}
Expand All @@ -606,23 +619,21 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
public func uploadToSignedURL(
_ path: String,
token: String,
fileURL: Data,
fileURL: URL,
options: FileOptions? = nil
) async throws -> SignedURLUploadResponse {
let formData = MultipartFormData()
formData.append(fileURL, withName: path.fileName)
return try await _uploadToSignedURL(
try await _uploadToSignedURL(
path: path,
token: token,
formData: formData,
file: .url(fileURL),
options: options
)
}

private func _uploadToSignedURL(
path: String,
token: String,
formData: MultipartFormData,
file: FileUpload,
options: FileOptions?
) async throws -> SignedURLUploadResponse {
let options = options ?? defaultFileOptions
Expand All @@ -631,11 +642,8 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
headers["x-upsert"] = "\(options.upsert)"
headers["duplex"] = options.duplex

if let metadata = options.metadata {
formData.append(encodeMetadata(metadata), withName: "metadata")
}

formData.append(options.cacheControl.data(using: .utf8)!, withName: "cacheControl")
let formData = MultipartFormData()
file.encode(to: formData, withPath: path, options: options)

struct UploadResponse: Decodable {
let Key: String
Expand Down Expand Up @@ -664,7 +672,8 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {

private func _removeEmptyFolders(_ path: String) -> String {
let trimmedPath = path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
let cleanedPath = trimmedPath.replacingOccurrences(of: "/+", with: "/", options: .regularExpression)
let cleanedPath = trimmedPath.replacingOccurrences(
of: "/+", with: "/", options: .regularExpression)
return cleanedPath
}
}

0 comments on commit 30955b4

Please sign in to comment.