use std::sync::Arc;
use reqwest::Client;
use alloy_primitives::hex::decode;
use serde::{Deserialize, Serialize};
use graphql_client::{GraphQLQuery, Response, QueryBody};
use super::{
RainMetaDocumentV1Item, KnownMagic, types::authoring::v1::AuthoringMeta, super::error::Error,
};
type Bytes = String;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "src/meta/query/schema.json",
query_path = "src/meta/query/meta.graphql",
response_derives = "Debug, Serialize, Deserialize"
)]
pub(super) struct MetaQuery;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "src/meta/query/schema.json",
query_path = "src/meta/query/deployer.graphql",
response_derives = "Debug, Serialize, Deserialize"
)]
pub(super) struct DeployerQuery;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct MetaResponse {
#[serde(with = "serde_bytes")]
pub bytes: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DeployerResponse {
#[serde(with = "serde_bytes")]
pub tx_hash: Vec<u8>,
#[serde(with = "serde_bytes")]
pub bytecode_meta_hash: Vec<u8>,
#[serde(with = "serde_bytes")]
pub meta_hash: Vec<u8>,
#[serde(with = "serde_bytes")]
pub meta_bytes: Vec<u8>,
#[serde(with = "serde_bytes")]
pub bytecode: Vec<u8>,
#[serde(with = "serde_bytes")]
pub parser: Vec<u8>,
#[serde(with = "serde_bytes")]
pub store: Vec<u8>,
#[serde(with = "serde_bytes")]
pub interpreter: Vec<u8>,
}
impl DeployerResponse {
pub fn get_authoring_meta(&self) -> Option<AuthoringMeta> {
if let Ok(meta_maps) = RainMetaDocumentV1Item::cbor_decode(&self.meta_bytes) {
for meta_map in &meta_maps {
if meta_map.magic == KnownMagic::AuthoringMetaV1 {
if let Ok(v) = meta_map.unpack() {
match AuthoringMeta::abi_decode_validate(&v) {
Ok(am) => return Some(am),
Err(_) => return None,
}
}
}
}
None
} else {
None
}
}
}
pub(super) async fn process_meta_query(
client: Arc<Client>,
request_body: &QueryBody<meta_query::Variables>,
url: &str,
) -> Result<MetaResponse, Error> {
Ok(MetaResponse {
bytes: decode(
client
.post(url)
.json(request_body)
.send()
.await
.map_err(Error::ReqwestError)?
.json::<Response<meta_query::ResponseData>>()
.await
.map_err(Error::ReqwestError)?
.data
.ok_or(Error::NoRecordFound)?
.meta
.ok_or(Error::NoRecordFound)?
.raw_bytes,
)
.or(Err(Error::NoRecordFound))?,
})
}
pub(super) async fn process_deployer_query(
client: Arc<Client>,
request_body: &QueryBody<deployer_query::Variables>,
url: &str,
) -> Result<DeployerResponse, Error> {
let res = client
.post(url)
.json(request_body)
.send()
.await
.map_err(Error::ReqwestError)?
.json::<Response<deployer_query::ResponseData>>()
.await
.map_err(Error::ReqwestError)?
.data
.ok_or(Error::NoRecordFound)?
.expression_deployers;
if !res.is_empty() {
let bytecode = if let Some(v) = &res[0].bytecode {
decode(v).or(Err(Error::NoRecordFound))?
} else {
return Err(Error::NoRecordFound);
};
let parser = if let Some(v) = &res[0].parser {
decode(&v.parser.deployed_bytecode).or(Err(Error::NoRecordFound))?
} else {
return Err(Error::NoRecordFound);
};
let store = if let Some(v) = &res[0].store {
decode(&v.store.deployed_bytecode).or(Err(Error::NoRecordFound))?
} else {
return Err(Error::NoRecordFound);
};
let interpreter = if let Some(v) = &res[0].interpreter {
decode(&v.interpreter.deployed_bytecode).or(Err(Error::NoRecordFound))?
} else {
return Err(Error::NoRecordFound);
};
let bytecode_meta_hash = if res[0].meta.len() == 1 {
decode(&res[0].meta[0].id).or(Err(Error::NoRecordFound))?
} else {
return Err(Error::NoRecordFound);
};
let tx_hash = if let Some(v) = &res[0].deploy_transaction {
decode(&v.id).or(Err(Error::NoRecordFound))?
} else {
return Err(Error::NoRecordFound);
};
let meta_hash = decode(&res[0].constructor_meta_hash).or(Err(Error::NoRecordFound))?;
let meta_bytes = decode(&res[0].constructor_meta).or(Err(Error::NoRecordFound))?;
Ok(DeployerResponse {
meta_hash,
meta_bytes,
bytecode,
parser,
store,
interpreter,
bytecode_meta_hash,
tx_hash,
})
} else {
Err(Error::NoRecordFound)
}
}