use std::sync::{Arc, Mutex};
use k256::ecdsa::VerifyingKey;
use uniffi::Object;
mod grpc_client;
use crate::signer::{UniffiSigner, UniffiSignerBox};
use crate::GrpcClientBuilder as RustBuilder;
pub use grpc_client::GrpcClient;
#[derive(Debug, thiserror::Error, uniffi::Error)]
pub enum GrpcClientBuilderError {
#[error("error creating transport: {msg}")]
TonicTransportError {
msg: String,
},
#[error("invalid account public key")]
InvalidAccountPublicKey,
#[error("invalid account private key")]
InvalidAccountPrivateKey,
#[error("invalid metadata")]
Metadata(String),
}
#[derive(Object)]
pub struct GrpcClientBuilder(Mutex<Option<RustBuilder>>);
impl GrpcClientBuilder {
fn map_builder<F>(&self, map: F)
where
F: FnOnce(RustBuilder) -> RustBuilder,
{
let mut builder_lock = self.0.lock().expect("lock poisoned");
let builder = builder_lock.take().expect("builder must be set");
*builder_lock = Some(map(builder));
}
}
#[uniffi::export(async_runtime = "tokio")]
impl GrpcClientBuilder {
#[uniffi::constructor(name = "withUrl")]
pub fn with_url(url: String) -> Self {
let builder = RustBuilder::new().url(url);
GrpcClientBuilder(Mutex::new(Some(builder)))
}
#[uniffi::method(name = "withPubkeyAndSigner")]
pub fn pubkey_and_signer(
self: Arc<Self>,
account_pubkey: Vec<u8>,
signer: Arc<dyn UniffiSigner>,
) -> Result<Arc<Self>, GrpcClientBuilderError> {
let vk = VerifyingKey::from_sec1_bytes(&account_pubkey)
.map_err(|_| GrpcClientBuilderError::InvalidAccountPublicKey)?;
let signer = UniffiSignerBox(signer);
self.map_builder(move |builder| builder.pubkey_and_signer(vk, signer));
Ok(self)
}
#[uniffi::method(name = "withMetadata")]
pub fn metadata(self: Arc<Self>, key: &str, value: &str) -> Arc<Self> {
self.map_builder(move |builder| builder.metadata(key, value));
self
}
#[uniffi::method(name = "withMetadataBin")]
pub fn metadata_bin(self: Arc<Self>, key: &str, value: &[u8]) -> Arc<Self> {
self.map_builder(move |builder| builder.metadata_bin(key, value));
self
}
#[uniffi::method(name = "build")]
pub async fn build(self: Arc<Self>) -> Result<GrpcClient, GrpcClientBuilderError> {
let builder = self
.0
.lock()
.expect("lock poisoned")
.take()
.expect("builder must be set");
Ok(builder.build()?.into())
}
}
impl From<crate::GrpcClientBuilderError> for GrpcClientBuilderError {
fn from(error: crate::GrpcClientBuilderError) -> Self {
match error {
crate::GrpcClientBuilderError::TonicTransportError(error) => {
GrpcClientBuilderError::TonicTransportError {
msg: error.to_string(),
}
}
crate::GrpcClientBuilderError::InvalidPrivateKey => {
GrpcClientBuilderError::InvalidAccountPrivateKey
}
crate::GrpcClientBuilderError::InvalidPublicKey => {
GrpcClientBuilderError::InvalidAccountPublicKey
}
crate::GrpcClientBuilderError::TransportNotSet => {
unimplemented!("transport not set for builder, should not happen")
}
crate::GrpcClientBuilderError::Metadata(err) => {
GrpcClientBuilderError::Metadata(err.to_string())
}
}
}
}