use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CredentialsSource {
#[default]
ApplicationDefault,
ServiceAccountFile(String),
ServiceAccountJson(String),
MetadataServer,
AccessToken(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GcpConfig {
pub project_id: Option<String>,
#[serde(default)]
pub credentials: CredentialsSource,
#[serde(default)]
pub enabled_services: HashSet<String>,
#[serde(default)]
pub service_configs: std::collections::HashMap<String, serde_json::Value>,
pub emulator_host: Option<String>,
}
impl Default for GcpConfig {
fn default() -> Self {
Self {
project_id: None,
credentials: CredentialsSource::ApplicationDefault,
enabled_services: HashSet::new(),
service_configs: std::collections::HashMap::new(),
emulator_host: None,
}
}
}
impl GcpConfig {
pub fn new() -> Self {
Self::default()
}
pub fn builder() -> GcpConfigBuilder {
GcpConfigBuilder::new()
}
pub fn from_env() -> GcpConfigBuilder {
let mut builder = GcpConfigBuilder::new();
if let Ok(project) = std::env::var("GOOGLE_CLOUD_PROJECT") {
builder = builder.project_id(project);
} else if let Ok(project) = std::env::var("GCP_PROJECT") {
builder = builder.project_id(project);
} else if let Ok(project) = std::env::var("GCLOUD_PROJECT") {
builder = builder.project_id(project);
}
if let Ok(creds_file) = std::env::var("GOOGLE_APPLICATION_CREDENTIALS") {
builder = builder.service_account_file(creds_file);
}
if let Ok(host) = std::env::var("PUBSUB_EMULATOR_HOST") {
builder = builder.emulator_host(host);
}
if let Ok(host) = std::env::var("FIRESTORE_EMULATOR_HOST") {
builder = builder.emulator_host(host);
}
if let Ok(host) = std::env::var("STORAGE_EMULATOR_HOST") {
builder = builder.emulator_host(host);
}
builder
}
pub fn is_enabled(&self, service: &str) -> bool {
self.enabled_services.contains(service)
}
pub fn service_config<T: serde::de::DeserializeOwned>(&self, service: &str) -> Option<T> {
self.service_configs
.get(service)
.and_then(|v| serde_json::from_value(v.clone()).ok())
}
}
#[derive(Default)]
pub struct GcpConfigBuilder {
config: GcpConfig,
}
impl GcpConfigBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn project_id(mut self, project_id: impl Into<String>) -> Self {
self.config.project_id = Some(project_id.into());
self
}
pub fn credentials(mut self, credentials: CredentialsSource) -> Self {
self.config.credentials = credentials;
self
}
pub fn service_account_file(mut self, path: impl Into<String>) -> Self {
self.config.credentials = CredentialsSource::ServiceAccountFile(path.into());
self
}
pub fn service_account_json(mut self, json: impl Into<String>) -> Self {
self.config.credentials = CredentialsSource::ServiceAccountJson(json.into());
self
}
pub fn emulator_host(mut self, host: impl Into<String>) -> Self {
self.config.emulator_host = Some(host.into());
self
}
pub fn enable(mut self, service: impl Into<String>) -> Self {
self.config.enabled_services.insert(service.into());
self
}
pub fn enable_storage(self) -> Self {
self.enable("storage")
}
pub fn enable_pubsub(self) -> Self {
self.enable("pubsub")
}
pub fn enable_firestore(self) -> Self {
self.enable("firestore")
}
pub fn enable_spanner(self) -> Self {
self.enable("spanner")
}
pub fn enable_bigquery(self) -> Self {
self.enable("bigquery")
}
pub fn enable_secret_manager(self) -> Self {
self.enable("secret-manager")
}
pub fn enable_cloud_run(self) -> Self {
self.enable("cloud-run")
}
pub fn enable_cloud_functions(self) -> Self {
self.enable("cloud-functions")
}
pub fn enable_data(self) -> Self {
self.enable_storage()
.enable_firestore()
.enable_spanner()
.enable_bigquery()
}
pub fn service_config(mut self, service: &str, config: serde_json::Value) -> Self {
self.config
.service_configs
.insert(service.to_string(), config);
self
}
pub fn build(self) -> GcpConfig {
self.config
}
}