#[allow(unused_imports)]
use parking_lot::RwLock;
#[allow(unused_imports)]
use std::sync::Arc;
use tracing::info;
use crate::{GcpConfig, GcpError, Result};
pub struct GcpServices {
config: GcpConfig,
#[cfg(feature = "storage")]
storage: RwLock<Option<google_cloud_storage::client::Client>>,
#[cfg(feature = "pubsub")]
pubsub: RwLock<Option<google_cloud_pubsub::client::Client>>,
#[cfg(feature = "spanner")]
spanner: RwLock<Option<google_cloud_spanner::client::Client>>,
#[cfg(feature = "bigquery")]
bigquery: RwLock<Option<google_cloud_bigquery::client::Client>>,
}
impl GcpServices {
pub async fn new(config: GcpConfig) -> Result<Arc<Self>> {
info!(
project = ?config.project_id,
services = ?config.enabled_services,
"GCP services initialized"
);
let services = Self {
config,
#[cfg(feature = "storage")]
storage: RwLock::new(None),
#[cfg(feature = "pubsub")]
pubsub: RwLock::new(None),
#[cfg(feature = "spanner")]
spanner: RwLock::new(None),
#[cfg(feature = "bigquery")]
bigquery: RwLock::new(None),
};
let services = Arc::new(services);
services.initialize_enabled_services().await?;
Ok(services)
}
async fn initialize_enabled_services(&self) -> Result<()> {
for service in &self.config.enabled_services {
match service.as_str() {
#[cfg(feature = "storage")]
"storage" => {
self.init_storage().await?;
}
#[cfg(feature = "pubsub")]
"pubsub" => {
self.init_pubsub().await?;
}
#[cfg(feature = "spanner")]
"spanner" => {
self.init_spanner().await?;
}
#[cfg(feature = "bigquery")]
"bigquery" => {
self.init_bigquery().await?;
}
_ => {}
}
}
Ok(())
}
pub fn config(&self) -> &GcpConfig {
&self.config
}
pub fn project_id(&self) -> Option<&str> {
self.config.project_id.as_deref()
}
#[cfg(feature = "storage")]
async fn init_storage(&self) -> Result<()> {
use google_cloud_storage::client::{Client, ClientConfig};
let mut client = self.storage.write();
if client.is_none() {
let config = ClientConfig::default()
.with_auth()
.await
.map_err(|e| GcpError::Auth(e.to_string()))?;
*client = Some(Client::new(config));
info!("Cloud Storage client initialized");
}
Ok(())
}
#[cfg(feature = "pubsub")]
async fn init_pubsub(&self) -> Result<()> {
use google_cloud_pubsub::client::{Client, ClientConfig};
let mut client = self.pubsub.write();
if client.is_none() {
let project_id = self
.config
.project_id
.as_ref()
.ok_or(GcpError::ProjectNotSpecified)?;
let config = ClientConfig::default()
.with_auth()
.await
.map_err(|e| GcpError::Auth(e.to_string()))?;
*client = Some(
Client::new(config)
.await
.map_err(|e| GcpError::Service(e.to_string()))?,
);
info!(project = %project_id, "Pub/Sub client initialized");
}
Ok(())
}
#[cfg(feature = "spanner")]
async fn init_spanner(&self) -> Result<()> {
use google_cloud_spanner::client::{Client, ClientConfig};
let mut client = self.spanner.write();
if client.is_none() {
let project_id = self
.config
.project_id
.as_ref()
.ok_or(GcpError::ProjectNotSpecified)?;
let config = ClientConfig::default()
.with_auth()
.await
.map_err(|e| GcpError::Auth(e.to_string()))?;
*client = Some(
Client::new(project_id, config)
.await
.map_err(|e| GcpError::Service(e.to_string()))?,
);
info!(project = %project_id, "Spanner client initialized");
}
Ok(())
}
#[cfg(feature = "bigquery")]
async fn init_bigquery(&self) -> Result<()> {
use google_cloud_bigquery::client::{Client, ClientConfig};
let mut client = self.bigquery.write();
if client.is_none() {
let project_id = self
.config
.project_id
.as_ref()
.ok_or(GcpError::ProjectNotSpecified)?;
let config = ClientConfig::default()
.with_auth()
.await
.map_err(|e| GcpError::Auth(e.to_string()))?;
*client = Some(
Client::new(config)
.await
.map_err(|e| GcpError::Service(e.to_string()))?,
);
info!(project = %project_id, "BigQuery client initialized");
}
Ok(())
}
#[cfg(feature = "storage")]
pub fn storage(&self) -> Result<google_cloud_storage::client::Client> {
if !self.config.is_enabled("storage") {
return Err(GcpError::not_configured("storage"));
}
self.storage
.read()
.clone()
.ok_or_else(|| GcpError::Service("Storage client not initialized".to_string()))
}
#[cfg(not(feature = "storage"))]
pub fn storage(&self) -> Result<()> {
Err(GcpError::not_enabled("storage"))
}
#[cfg(feature = "pubsub")]
pub fn pubsub(&self) -> Result<google_cloud_pubsub::client::Client> {
if !self.config.is_enabled("pubsub") {
return Err(GcpError::not_configured("pubsub"));
}
self.pubsub
.read()
.clone()
.ok_or_else(|| GcpError::Service("Pub/Sub client not initialized".to_string()))
}
#[cfg(not(feature = "pubsub"))]
pub fn pubsub(&self) -> Result<()> {
Err(GcpError::not_enabled("pubsub"))
}
#[cfg(feature = "spanner")]
pub fn spanner(&self) -> Result<google_cloud_spanner::client::Client> {
if !self.config.is_enabled("spanner") {
return Err(GcpError::not_configured("spanner"));
}
self.spanner
.read()
.clone()
.ok_or_else(|| GcpError::Service("Spanner client not initialized".to_string()))
}
#[cfg(not(feature = "spanner"))]
pub fn spanner(&self) -> Result<()> {
Err(GcpError::not_enabled("spanner"))
}
#[cfg(feature = "bigquery")]
pub fn bigquery(&self) -> Result<google_cloud_bigquery::client::Client> {
if !self.config.is_enabled("bigquery") {
return Err(GcpError::not_configured("bigquery"));
}
self.bigquery
.read()
.clone()
.ok_or_else(|| GcpError::Service("BigQuery client not initialized".to_string()))
}
#[cfg(not(feature = "bigquery"))]
pub fn bigquery(&self) -> Result<()> {
Err(GcpError::not_enabled("bigquery"))
}
}