use std::sync::Arc;
use crate::public::auth::Auth;
use crate::public::generated::app_client::{
AgentClient, AppClient, AuthorizationClient, ExternalCredentialsClient, IdentityClient,
IndexedDBClient, WorkflowClient,
};
use crate::public::generated::rpc_support::GestaltError;
use crate::public::grpc_transport::{GrpcTransport, dial_public_grpc};
use crate::public::rest_transport::RestTransport;
use crate::rpc_support::gestalt_error_code;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Transport {
Rest,
Grpc,
}
pub fn rest() -> Transport {
Transport::Rest
}
pub fn grpc() -> Transport {
Transport::Grpc
}
pub enum GestaltClient {
Rest(AppClient<RestTransport>),
Grpc(Box<AppClient<GrpcTransport>>),
}
pub struct RestGestaltClient {
pub app: AppClient<RestTransport>,
pub agent: AgentClient<RestTransport>,
pub workflow: WorkflowClient<RestTransport>,
pub identity: IdentityClient<RestTransport>,
pub authorization: AuthorizationClient<RestTransport>,
}
impl RestGestaltClient {
pub fn close(self) {}
}
pub struct GrpcGestaltClient {
pub app: AppClient<GrpcTransport>,
pub agent: AgentClient<GrpcTransport>,
pub workflow: WorkflowClient<GrpcTransport>,
pub identity: IdentityClient<GrpcTransport>,
pub authorization: AuthorizationClient<GrpcTransport>,
pub indexed_db: IndexedDBClient<GrpcTransport>,
pub external_credentials: ExternalCredentialsClient<GrpcTransport>,
}
impl GrpcGestaltClient {
pub fn close(self) {}
}
pub async fn create_gestalt_client<A: Auth + 'static>(
address: impl Into<String>,
auth: A,
transport: Transport,
) -> Result<GestaltClient, GestaltError> {
let address = normalize_address(address.into())?;
let auth: Arc<dyn Auth> = Arc::new(auth);
match transport {
Transport::Rest => Ok(GestaltClient::Rest(AppClient::new(RestTransport::new(
address,
Arc::clone(&auth),
)))),
Transport::Grpc => {
let channel = dial_public_grpc(&address)?.connect_lazy();
Ok(GestaltClient::Grpc(Box::new(AppClient::new(
GrpcTransport::new(channel, auth),
))))
}
}
}
pub async fn create_rest_gestalt_client<A: Auth + 'static>(
address: impl Into<String>,
auth: A,
) -> Result<RestGestaltClient, GestaltError> {
let address = normalize_address(address.into())?;
let auth: Arc<dyn Auth> = Arc::new(auth);
Ok(bind_rest(RestTransport::new(address, auth)))
}
pub async fn create_grpc_gestalt_client<A: Auth + 'static>(
address: impl Into<String>,
auth: A,
) -> Result<GrpcGestaltClient, GestaltError> {
let address = normalize_address(address.into())?;
let auth: Arc<dyn Auth> = Arc::new(auth);
let channel = dial_public_grpc(&address)?.connect_lazy();
Ok(bind_grpc(GrpcTransport::new(channel, auth)))
}
fn bind_rest(transport: RestTransport) -> RestGestaltClient {
RestGestaltClient {
app: AppClient::new(transport.clone()),
agent: AgentClient::new(transport.clone()),
workflow: WorkflowClient::new(transport.clone()),
identity: IdentityClient::new(transport.clone()),
authorization: AuthorizationClient::new(transport.clone()),
}
}
fn bind_grpc(transport: GrpcTransport) -> GrpcGestaltClient {
GrpcGestaltClient {
app: AppClient::new(transport.clone()),
agent: AgentClient::new(transport.clone()),
workflow: WorkflowClient::new(transport.clone()),
identity: IdentityClient::new(transport.clone()),
authorization: AuthorizationClient::new(transport.clone()),
indexed_db: IndexedDBClient::new(transport.clone()),
external_credentials: ExternalCredentialsClient::new(transport),
}
}
fn normalize_address(address: String) -> Result<String, GestaltError> {
let address = address.trim();
if address.is_empty() {
return Err(GestaltError::new(
gestalt_error_code::INVALID_ARGUMENT,
"address is required for external clients (use gestalt_from_context for bound provider access)",
));
}
Ok(address.trim_end_matches('/').to_string())
}