Newer
Older
use graphql_client::{reqwest::post_graphql, GraphQLQuery};
use crate::*;
// type used in parameters query
#[allow(non_camel_case_types)]
type jsonb = serde_json::Value;
schema_path = "res/indexer-schema.graphql",
pub struct IdentityByIndex;
// // name → identity
// #[derive(GraphQLQuery)]
// #[graphql(
// schema_path = "res/indexer-schema.graphql",
// query_path = "res/indexer-queries.graphql"
// )]
// pub struct IdentityByName;
// pubkey → identity
schema_path = "res/indexer-schema.graphql",
pub struct IdentityByPubkey;
schema_path = "res/indexer-schema.graphql",
query_path = "res/indexer-queries.graphql"
)]
pub struct LatestBlock;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "res/indexer-schema.graphql",
query_path = "res/indexer-queries.graphql"
)]
pub struct GenesisHash;
pub async fn username_by_index(&self, index: u32) -> anyhow::Result<Option<String>> {
Ok(post_graphql::<IdentityByIndex, _>(
identity_by_index::Variables {
index: index.into(),
.and_then(|data| data.identity_by_pk.map(|idty| idty.name))
.unwrap())
pub async fn username_by_pubkey(&self, pubkey: &str) -> anyhow::Result<Option<String>> {
Ok(post_graphql::<IdentityByPubkey, _>(
&self.gql_url,
identity_by_pubkey::Variables {
pubkey: pubkey.to_string(),
.and_then(|data| data.identity.into_iter().next().map(|idty| idty.name))
.unwrap())
// // not used anymore because available with Duniter
// pub async fn pubkey_by_username(&self, username: &str) -> anyhow::Result<Option<String>> {
// Ok(post_graphql::<IdentityByName, _>(
// &self.gql_client,
// self.gql_url.clone(),
// identity_by_name::Variables {
// name: username.to_string(),
// },
// )
// .await?
// .data
// .and_then(|data| data.identity.into_iter().next().map(|idty| idty.pubkey)))
// }
/// fetch latest block number
pub async fn fetch_latest_block(&self) -> Result<u64, anyhow::Error> {
Ok(post_graphql::<LatestBlock, _>(
&self.gql_client,
self.gql_url.clone(),
latest_block::Variables {},
)
.await?
.data
.unwrap() // must have a data field
.parameters
.first()
.unwrap() // must have one and only one parameter matching request
.value
.clone()
.unwrap() // must have a value field
.as_u64()
.unwrap()) // must be a Number of blocks
}
/// fetch genesis hash
pub async fn fetch_genesis_hash(&self) -> Result<Hash, anyhow::Error> {
Ok(post_graphql::<GenesisHash, _>(
&self.gql_client,
self.gql_url.clone(),
genesis_hash::Variables {},
)
.await?
.data
.ok_or(GcliError::Indexer("could not reach indexer".to_string()))?
.block
.first()
.unwrap() // must have one and only one block matching request
.hash
.clone()
.parse::<Hash>()
.unwrap())
}
#[derive(Clone, Default, Debug, clap::Parser)]
/// Check that indexer and node are on the same network (same genesis hash)
Check,
/// Fetch latest indexed block
LatestBlock,
pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
// build indexer because it is needed for all subcommands
let mut data = data.build_indexer().await?;
Subcommand::Check => {
data = data.build_client().await?;
if data.genesis_hash == data.indexer_genesis_hash {
println!(
"{} and {} have the same genesis hash: {}",
data.cfg.duniter_endpoint,
data.indexer().gql_url,
data.genesis_hash
);
} else {
println!(
"⚠️ {} ({}) and {} ({}) do not share same genesis",
data.cfg.duniter_endpoint,
data.genesis_hash,
data.indexer().gql_url,
data.indexer_genesis_hash
);
}
Subcommand::LatestBlock => {
println!(
"latest block indexed by {} is: {}",
data.cfg.indexer_endpoint,
data.indexer().fetch_latest_block().await?
);
}