use std::env::VarError;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "expose-jsvalue")]
use wasm_bindgen::prelude::*;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
pub struct FirebaseConfig {
#[cfg_attr(feature = "serde", serde(rename = "projectId"))]
pub project_id: String,
#[cfg_attr(feature = "serde", serde(rename = "apiKey"))]
pub api_key: Option<String>,
#[cfg_attr(feature = "serde", serde(rename = "authDomain"))]
pub auth_domain: Option<String>,
#[cfg_attr(feature = "serde", serde(rename = "storageBucket"))]
pub storage_bucket: Option<String>,
#[cfg_attr(feature = "serde", serde(rename = "messagingSenderId"))]
pub messaging_sender_id: Option<String>,
#[cfg_attr(feature = "serde", serde(rename = "appId"))]
pub app_id: Option<String>,
#[cfg_attr(feature = "serde", serde(rename = "measurementId"))]
pub measurement_id: Option<String>,
#[cfg_attr(feature = "serde", serde(rename = "databaseURL"))]
pub database_url: Option<String>,
}
impl FirebaseConfig {
pub fn new(project_id: impl ToString) -> Self {
Self {
project_id: project_id.to_string(),
..Default::default()
}
}
pub fn new_from_env() -> Result<Self, VarError> {
let project_id: String = std::env::var("FIREBASE_PROJECT_ID")?;
let api_key = std::env::var("FIREBASE_API_KEY").ok();
let auth_domain = std::env::var("FIREBASE_AUTH_DOMAIN").ok();
let storage_bucket = std::env::var("FIREBASE_STORAGE_BUCKET").ok();
let messaging_sender_id = std::env::var("FIREBASE_MESSAGING_SENDER_ID").ok();
let app_id = std::env::var("FIREBASE_APP_ID").ok();
let measurement_id = std::env::var("FIREBASE_MEASUREMENT_ID").ok();
let database_url = std::env::var("FIREBASE_DATABASE_URL").ok();
Ok(Self {
project_id,
api_key,
auth_domain,
storage_bucket,
messaging_sender_id,
app_id,
measurement_id,
database_url,
})
}
}
#[cfg(feature = "expose-jsvalue")]
impl TryFrom<FirebaseConfig> for JsValue {
type Error = JsValue;
fn try_from(value: FirebaseConfig) -> Result<Self, Self::Error> {
serde_wasm_bindgen::to_value(&value).map_err(|e| e.into())
}
}
#[allow(non_snake_case)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FirebaseConfigConstructor<'a> {
pub projectId: &'a str,
pub apiKey: &'a str,
pub authDomain: &'a str,
pub storageBucket: &'a str,
pub messagingSenderId: &'a str,
pub appId: &'a str,
pub measurementId: &'a str,
pub databaseURL: &'a str,
}
impl<'a> FirebaseConfigConstructor<'a> {
pub fn into_config(&self) -> Option<FirebaseConfig> {
if self.projectId == "" {
return None
}
fn if_empty_none(s: &str) -> Option<String> {
if s == "" {
None
} else {
Some(s.to_owned())
}
}
Some(FirebaseConfig {
project_id: self.projectId.to_owned(),
api_key: if_empty_none(self.apiKey),
auth_domain: if_empty_none(self.authDomain),
storage_bucket: if_empty_none(self.storageBucket),
messaging_sender_id: if_empty_none(self.messagingSenderId),
app_id: if_empty_none(self.appId),
measurement_id: if_empty_none(self.measurementId),
database_url: if_empty_none(self.databaseURL),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn random_string() -> String {
use rand::Rng;
let mut rng = rand::thread_rng();
let n: u8 = rng.gen();
n.to_string()
}
#[test]
pub fn config_constructor_using_default() {
let rand_item = random_string();
let config_constructor = FirebaseConfigConstructor {
projectId: "my-project-id",
appId: &rand_item,
..Default::default()
};
assert_eq!(config_constructor.projectId, "my-project-id");
assert_eq!(config_constructor.apiKey, "");
assert_eq!(config_constructor.authDomain, "");
assert_eq!(config_constructor.storageBucket, "");
assert_eq!(config_constructor.messagingSenderId, "");
assert_eq!(config_constructor.appId, rand_item);
assert_eq!(config_constructor.measurementId, "");
assert_eq!(config_constructor.databaseURL, "");
}
#[test]
pub fn config_constructor_minimal_using_default_into_config() {
let config_constructor = FirebaseConfigConstructor {
projectId: "my-project-id",
..Default::default()
};
assert_eq!(config_constructor.projectId, "my-project-id");
assert_eq!(config_constructor.apiKey, "");
assert_eq!(config_constructor.authDomain, "");
assert_eq!(config_constructor.storageBucket, "");
assert_eq!(config_constructor.messagingSenderId, "");
assert_eq!(config_constructor.appId, "");
assert_eq!(config_constructor.measurementId, "");
assert_eq!(config_constructor.databaseURL, "");
let config = config_constructor.into_config();
let expected_config = FirebaseConfig {
project_id: "my-project-id".to_owned(),
api_key: None,
auth_domain: None,
storage_bucket: None,
messaging_sender_id: None,
app_id: None,
measurement_id: None,
database_url: None,
};
assert_eq!(config, Some(expected_config));
}
#[test]
pub fn config_constructor_minimal_using_default_into_config_fails() {
let config_constructor = FirebaseConfigConstructor {
..Default::default()
};
assert_eq!(config_constructor.projectId, "");
assert_eq!(config_constructor.apiKey, "");
assert_eq!(config_constructor.authDomain, "");
assert_eq!(config_constructor.storageBucket, "");
assert_eq!(config_constructor.messagingSenderId, "");
assert_eq!(config_constructor.appId, "");
assert_eq!(config_constructor.measurementId, "");
assert_eq!(config_constructor.databaseURL, "");
let config = config_constructor.into_config();
assert_eq!(config, None);
}
}