use std::time::Duration;
use js_sys::{Array, Uint8Array};
use k256::ecdsa::VerifyingKey;
use wasm_bindgen::convert::TryFromJsValue;
use wasm_bindgen::prelude::*;
use crate::GrpcClientBuilderError;
use crate::signer::{JsSigner, JsSignerFn};
mod grpc_client;
use grpc_client::GrpcClient;
#[wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &str = r#"
export type UrlOrEndpoint = string | Endpoint;
export type UrlsOrEndpoints = UrlOrEndpoint | UrlOrEndpoint[];
"#;
#[wasm_bindgen]
pub struct Endpoint {
pub(crate) inner: crate::Endpoint,
}
#[wasm_bindgen]
impl Endpoint {
#[wasm_bindgen(constructor)]
pub fn new(url: String) -> Self {
let endpoint = crate::Endpoint::from(url);
Self { inner: endpoint }
}
#[wasm_bindgen(js_name = "withMetadata")]
pub fn with_metadata(self, key: String, value: String) -> Self {
Self {
inner: self.inner.metadata(key, value),
}
}
#[wasm_bindgen(js_name = "withMetadataBin")]
pub fn with_metadata_bin(self, key: String, value: Uint8Array) -> Self {
Self {
inner: self.inner.metadata_bin(key, value.to_vec()),
}
}
#[wasm_bindgen(js_name = "withTimeout")]
pub fn with_timeout(self, timeout_ms: u64) -> Self {
Self {
inner: self.inner.timeout(Duration::from_millis(timeout_ms)),
}
}
}
#[wasm_bindgen]
pub struct GrpcClientBuilder {
inner: crate::GrpcClientBuilder,
}
#[wasm_bindgen]
impl GrpcClientBuilder {
#[wasm_bindgen(js_name = "withUrl")]
pub fn with_url(
self,
#[wasm_bindgen(unchecked_param_type = "UrlsOrEndpoints")] url: JsValue,
) -> Result<Self, JsValue> {
let endpoints = endpoints_from_js(url)?;
let ret = Self {
inner: self.inner.endpoints(endpoints),
};
Ok(ret)
}
#[wasm_bindgen(js_name = "withUrls")]
pub fn with_urls(
self,
#[wasm_bindgen(unchecked_param_type = "UrlsOrEndpoints")] urls: JsValue,
) -> Result<Self, JsValue> {
let endpoints = endpoints_from_js(urls)?;
let ret = Self {
inner: self.inner.endpoints(endpoints),
};
Ok(ret)
}
#[wasm_bindgen(js_name = withPubkeyAndSigner)]
pub fn with_pubkey_and_signer(
self,
account_pubkey: Uint8Array,
signer_fn: JsSignerFn,
) -> Result<Self, GrpcClientBuilderError> {
let signer = JsSigner::new(signer_fn);
let account_pubkey = VerifyingKey::try_from(account_pubkey.to_vec().as_slice())
.map_err(|_| GrpcClientBuilderError::InvalidPublicKey)?;
Ok(Self {
inner: self.inner.pubkey_and_signer(account_pubkey, signer),
})
}
pub fn build(self) -> Result<GrpcClient, GrpcClientBuilderError> {
Ok(self.inner.build()?.into())
}
}
pub(crate) fn endpoint_from_js(value: JsValue) -> Result<crate::Endpoint, JsValue> {
if let Some(url) = value.as_string() {
return Ok(crate::Endpoint::from(url));
}
if let Ok(endpoint) = Endpoint::try_from_js_value(value) {
return Ok(endpoint.inner);
}
Err(JsValue::from_str(
"Expected a string or Endpoint for endpoint values",
))
}
pub(crate) fn endpoints_from_js(value: JsValue) -> Result<Vec<crate::Endpoint>, JsValue> {
if Array::is_array(&value) {
let array = Array::from(&value);
return array
.iter()
.map(endpoint_from_js)
.collect::<Result<Vec<_>, _>>();
}
Ok(vec![endpoint_from_js(value)?])
}
impl From<crate::GrpcClientBuilder> for GrpcClientBuilder {
fn from(inner: crate::GrpcClientBuilder) -> Self {
Self { inner }
}
}