Skip to content

Commit

Permalink
Add FirebaseStorage module
Browse files Browse the repository at this point in the history
  • Loading branch information
darinf committed May 14, 2024
1 parent 0a709cd commit 5726508
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 1 deletion.
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,24 @@ target_link_libraries(FirebaseFunctions PRIVATE
ssl
zlibstatic)

add_library(FirebaseStorage SHARED
Sources/FirebaseStorage/StorageErrorCode.swift
Sources/FirebaseStorage/Storage+Swift.swift
Sources/FirebaseStorage/StorageReference+Swift.swift)
target_compile_options(FirebaseStorage PRIVATE
-cxx-interoperability-mode=default)
target_link_libraries(FirebaseStorage PUBLIC
firebase
firebase_storage
FirebaseCore)
target_link_libraries(FirebaseStorage PRIVATE
crypto
firebase_rest_lib
flatbuffers
libcurl
ssl
zlibstatic)

if(SWIFT_FIREBASE_BUILD_EXAMPLES)
FetchContent_Declare(SwiftWin32
GIT_REPOSITORY https://github.com/compnerd/swift-win32
Expand Down
13 changes: 13 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ let SwiftFirebase =
.library(name: "FirebaseAuth", targets: ["FirebaseAuth"]),
.library(name: "FirebaseFirestore", targets: ["FirebaseFirestore"]),
.library(name: "FirebaseFunctions", targets: ["FirebaseFunctions"]),
.library(name: "FirebaseStorage", targets: ["FirebaseStorage"]),
.executable(name: "FireBaseUI", targets: ["FireBaseUI"]),
],
dependencies: [
Expand Down Expand Up @@ -193,6 +194,18 @@ let SwiftFirebase =
.interoperabilityMode(.Cxx),
.unsafeFlags(["-Xcc", "-I\(include)"]),
]),
.target(name: "FirebaseStorage",
dependencies: ["firebase", "FirebaseCore"],
cxxSettings: [
.define("INTERNAL_EXPERIMENTAL"),
.define("_CRT_SECURE_NO_WARNINGS",
.when(platforms: [.windows])),
.headerSearchPath("../../third_party/firebase-development/usr/include"),
],
swiftSettings: [
.interoperabilityMode(.Cxx),
.unsafeFlags(["-Xcc", "-I\(include)"]),
]),
.executableTarget(name: "FireBaseUI",
dependencies: [
"FirebaseCore",
Expand Down
2 changes: 1 addition & 1 deletion Sources/FirebaseFunctions/HTTPSCallable+Swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class HTTPSCallable {
callImpl(data: data) { result, error in
if let error {
continuation.resume(throwing: error)
} else{
} else {
continuation.resume(returning: result ?? .init())
}
}
Expand Down
28 changes: 28 additions & 0 deletions Sources/FirebaseStorage/Storage+Swift.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: BSD-3-Clause

@_exported
import firebase
@_spi(FirebaseInternal)
import FirebaseCore

import CxxShim

public class Storage {
let impl: swift_firebase.swift_cxx_shims.firebase.storage.StorageRef

init(_ impl: swift_firebase.swift_cxx_shims.firebase.storage.StorageRef) {
self.impl = impl
}

public static func storage(app: FirebaseApp) -> Storage {
let instance = swift_firebase.swift_cxx_shims.firebase.storage.storage_get_instance(app)
guard swift_firebase.swift_cxx_shims.firebase.storage.storage_is_valid(instance) else {
fatalError("Invalid Storage Instance")
}
return .init(instance)
}

public func reference(withPath path: String) -> StorageReference {
.init(swift_firebase.swift_cxx_shims.firebase.storage.storage_get_reference(impl, path))
}
}
77 changes: 77 additions & 0 deletions Sources/FirebaseStorage/StorageErrorCode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: BSD-3-Clause

@_exported
import firebase
@_spi(FirebaseInternal)
import FirebaseCore

public struct StorageErrorCode: Error {
public let rawValue: Int
public let localizedDescription: String

internal init(_ params: (code: Int32, message: String)) {
self.rawValue = Int(params.code)
localizedDescription = params.message
}

private init(_ error: firebase.storage.Error) {
self.init(rawValue: Int(error.rawValue))
}
}

extension StorageErrorCode: RawRepresentable {
public typealias RawValue = Int

public init(rawValue: Int) {
self.rawValue = rawValue
localizedDescription = "\(rawValue)"
}
}

extension StorageErrorCode {
init(_ error: firebase.storage.Error, errorMessage: String?) {
self.init((code: error.rawValue, message: errorMessage ?? "\(error.rawValue)"))
}

init?(_ error: firebase.storage.Error?, errorMessage: UnsafePointer<CChar>?) {
guard let actualError = error, actualError.rawValue != 0 else { return nil }
var errorMessageString: String?
if let errorMessage {
errorMessageString = .init(cString: errorMessage)
}
self.init(actualError, errorMessage: errorMessageString)
}
}

extension StorageErrorCode {
public static var none: Self { .init(firebase.storage.kErrorNone) }
public static var unknown: Self { .init(firebase.storage.kErrorUnknown) }
public static var objectNotFound: Self { .init(firebase.storage.kErrorObjectNotFound) }
public static var bucketNotFound: Self { .init(firebase.storage.kErrorBucketNotFound) }
public static var projectNotFound: Self { .init(firebase.storage.kErrorProjectNotFound) }
public static var quotaExceeded: Self { .init(firebase.storage.kErrorQuotaExceeded) }
public static var unauthenticated: Self { .init(firebase.storage.kErrorUnauthenticated) }
public static var unauthorized: Self { .init(firebase.storage.kErrorUnauthorized) }
public static var retryLimitExceeded: Self { .init(firebase.storage.kErrorRetryLimitExceeded) }
public static var nonMatchingChecksum: Self { .init(firebase.storage.kErrorNonMatchingChecksum) }
public static var downloadSizeExceeded: Self { .init(firebase.storage.kErrorDownloadSizeExceeded) }
public static var cancelled: Self { .init(firebase.storage.kErrorCancelled) }
}

extension StorageErrorCode: Equatable {}

extension StorageErrorCode {
// The Obj C API provides this type as well, so provide it here for consistency.
public typealias Code = StorageErrorCode

// This allows us to re-expose self as a code similarly
// to what the Firebase SDK does when it creates the
// underlying NSErrors on iOS/macOS.
public var code: Code {
return self
}

public init(_ code: Code) {
self.init(rawValue: code.rawValue)
}
}
49 changes: 49 additions & 0 deletions Sources/FirebaseStorage/StorageReference+Swift.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: BSD-3-Clause

@_exported
import firebase
@_spi(FirebaseInternal)
import FirebaseCore

import CxxShim
import Foundation

public class StorageReference {
let impl: firebase.storage.StorageReference

init(_ impl: firebase.storage.StorageReference) {
self.impl = impl
}

public func child(_ path: String) -> StorageReference {
.init(impl.Child(path))
}

public func downloadURL(completion: @escaping (URL?, Error?) -> Void) {
downloadURLImpl() { result, error in
DispatchQueue.main.async {
completion(result, error)
}
}
}

public func downloadURL() async throws -> URL {
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<URL, any Error>) in
downloadURLImpl() { result, error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: result!)
}
}
}
}

private func downloadURLImpl(completion: @escaping (URL?, Error?) -> Void) {
let future = swift_firebase.swift_cxx_shims.firebase.storage.storage_reference_get_download_url(impl)
future.setCompletion({
let (result, error) = future.resultAndError { StorageErrorCode($0) }
completion(result.flatMap { .init(string: String($0)) }, error)
})
}
}
5 changes: 5 additions & 0 deletions Sources/firebase/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ module firebase [system] {
header "FirebaseFunctions.hh"
export *
}

module storage {
header "FirebaseStorage.hh"
export *
}
}

0 comments on commit 5726508

Please sign in to comment.