Skip to main content

firebase_admin_sdk/storage/
mod.rs

1//! Cloud Storage for Firebase module.
2//!
3//! This module provides functionality for interacting with Google Cloud Storage buckets
4//! associated with your Firebase project. It supports uploading, downloading, and deleting files,
5//! as well as managing file metadata.
6//!
7//! # Examples
8//!
9//! ```rust,no_run
10//! # use firebase_admin_sdk::FirebaseApp;
11//! # async fn run(app: FirebaseApp) {
12//! let storage = app.storage();
13//! let bucket = storage.bucket(None); // Use default bucket
14//!
15//! // Upload a file
16//! let file_content = b"Hello, World!".to_vec();
17//! let file = bucket.file("hello.txt");
18//! let _ = file.save(file_content, "text/plain").await;
19//! # }
20//! ```
21
22pub mod bucket;
23pub mod file;
24
25use crate::core::middleware::AuthMiddleware;
26use bucket::Bucket;
27use reqwest::Client;
28use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
29use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
30use thiserror::Error;
31
32const STORAGE_V1_API: &str = "https://storage.googleapis.com/storage/v1";
33
34/// Errors that can occur during Storage operations.
35#[derive(Error, Debug)]
36pub enum StorageError {
37    /// Wrapper for `reqwest::Error`.
38    #[error("HTTP Request failed: {0}")]
39    RequestError(#[from] reqwest::Error),
40    /// Wrapper for `reqwest_middleware::Error`.
41    #[error("Middleware error: {0}")]
42    MiddlewareError(#[from] reqwest_middleware::Error),
43    /// Errors returned by the Cloud Storage API.
44    #[error("API error: {0}")]
45    ApiError(String),
46    /// Wrapper for `serde_json::Error`.
47    #[error("Serialization error: {0}")]
48    SerializationError(#[from] serde_json::Error),
49    /// Missing project ID in service account key.
50    #[error("Project ID is missing in service account key")]
51    ProjectIdMissing,
52}
53
54/// Client for interacting with Cloud Storage for Firebase.
55#[derive(Clone)]
56pub struct FirebaseStorage {
57    client: ClientWithMiddleware,
58    pub base_url: String,
59    pub project_id: String,
60    middleware: AuthMiddleware,
61}
62
63impl FirebaseStorage {
64    /// Creates a new `FirebaseStorage` instance.
65    ///
66    /// This is typically called via `FirebaseApp::storage()`.
67    pub fn new(middleware: AuthMiddleware) -> Self {
68        let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3);
69
70        let client = ClientBuilder::new(Client::new())
71            .with(RetryTransientMiddleware::new_with_policy(retry_policy))
72            .with(middleware.clone())
73            .build();
74
75        let project_id = middleware.key.project_id.clone().unwrap_or_default();
76        let base_url = STORAGE_V1_API.to_string();
77
78        Self {
79            client,
80            base_url,
81            project_id,
82            middleware,
83        }
84    }
85
86    #[cfg(test)]
87    pub(crate) fn new_with_client(client: ClientWithMiddleware, base_url: String, middleware: AuthMiddleware) -> Self {
88        let project_id = middleware.key.project_id.clone().unwrap_or_default();
89        Self {
90            client,
91            base_url,
92            project_id,
93            middleware,
94        }
95    }
96
97    /// Gets a `Bucket` instance that refers to the specific bucket.
98    ///
99    /// # Arguments
100    ///
101    /// * `name` - The name of the bucket (e.g. "my-project.appspot.com").
102    ///            If not provided, it attempts to use the default bucket name derived from the project ID
103    ///            (e.g., "{project_id}.appspot.com").
104    pub fn bucket(&self, name: Option<&str>) -> Bucket {
105        let bucket_name = match name {
106            Some(n) => n.to_string(),
107            None => format!("{}.appspot.com", self.project_id),
108        };
109
110        Bucket::new(self.client.clone(), self.base_url.clone(), bucket_name, self.middleware.clone())
111    }
112}
113
114#[cfg(test)]
115mod tests;