use crate::client::http::{
decode, json_headers, multipart_headers, send, ClientError, NamespaceConfig,
};
use crate::client::publish::{
publish_content, publish_merkle, publish_prehashed, publish_sealed, PublishHelperError,
};
use crate::client::transport::{MultipartField, RequestBody};
use crate::client::types::{
PublishBatchInput, PublishBatchResponse, PublishContentInput, PublishInput, PublishMerkleInput,
PublishMerkleResponse, PublishPrehashedInput, PublishResponse, PublishSealedInput, QuoteInput,
QuoteResponse, UploadsInput, UploadsResponse,
};
use crate::verifier::fetch::HttpMethod;
pub struct PoeNamespace<'t> {
config: NamespaceConfig<'t>,
}
impl<'t> PoeNamespace<'t> {
#[must_use]
pub fn new(config: NamespaceConfig<'t>) -> Self {
Self { config }
}
pub fn quote(&self, input: &QuoteInput) -> Result<QuoteResponse, ClientError> {
let body = serde_json::json!({
"record_bytes": input.record_bytes,
"recipient_count": input.recipient_count,
"file_bytes_total": input.file_bytes_total,
});
let url = format!("{}/api/v1/poe/quote", self.config.base_url);
let headers = json_headers(self.config.api_key.as_deref(), None);
let response = send(
self.config.transport,
&url,
HttpMethod::Post,
&headers,
&RequestBody::Json(serde_json::to_string(&body).expect("quote body serialises")),
)?;
decode(&response.body)
}
pub fn uploads(&self, input: &UploadsInput) -> Result<UploadsResponse, ClientError> {
let mut fields = vec![MultipartField {
name: "target".to_string(),
filename: None,
content_type: None,
value: input.target.as_bytes().to_vec(),
}];
for (idx, bytes) in input.data.iter().enumerate() {
fields.push(MultipartField {
name: format!("file_{idx}"),
filename: Some(format!("file_{idx}.bin")),
content_type: Some("application/octet-stream".to_string()),
value: bytes.clone(),
});
}
let url = format!("{}/api/v1/poe/uploads", self.config.base_url);
let headers = multipart_headers(
self.config.api_key.as_deref(),
input.idempotency_key.as_deref(),
);
let response = send(
self.config.transport,
&url,
HttpMethod::Post,
&headers,
&RequestBody::Multipart(fields),
)?;
decode(&response.body)
}
pub fn publish(&self, input: &PublishInput) -> Result<PublishResponse, ClientError> {
let mut body = serde_json::Map::new();
body.insert(
"record".to_string(),
serde_json::Value::String(hex::encode(&input.record)),
);
body.insert(
"quote_id".to_string(),
serde_json::Value::String(input.quote_id.clone()),
);
if let Some(sigs) = &input.signatures {
body.insert("signatures".to_string(), signatures_to_json(sigs));
}
let url = format!("{}/api/v1/poe/publish", self.config.base_url);
let headers = json_headers(
self.config.api_key.as_deref(),
input.idempotency_key.as_deref(),
);
let response = send(
self.config.transport,
&url,
HttpMethod::Post,
&headers,
&RequestBody::Json(
serde_json::to_string(&serde_json::Value::Object(body))
.expect("publish body serialises"),
),
)?;
let dedup_hit = response.status == 200;
let mut parsed: PublishResponse = decode(&response.body)?;
parsed.dedup_hit = dedup_hit;
Ok(parsed)
}
pub fn publish_batch(
&self,
input: &PublishBatchInput,
) -> Result<PublishBatchResponse, ClientError> {
let records: Vec<serde_json::Value> = input
.records
.iter()
.map(|r| {
let mut entry = serde_json::Map::new();
entry.insert(
"record".to_string(),
serde_json::Value::String(hex::encode(&r.record)),
);
entry.insert(
"quote_id".to_string(),
serde_json::Value::String(r.quote_id.clone()),
);
if let Some(sigs) = &r.signatures {
entry.insert("signatures".to_string(), signatures_to_json(sigs));
}
serde_json::Value::Object(entry)
})
.collect();
let body = serde_json::json!({ "records": records });
let url = format!("{}/api/v1/poe/publish-batch", self.config.base_url);
let headers = json_headers(
self.config.api_key.as_deref(),
input.idempotency_key.as_deref(),
);
let response = send(
self.config.transport,
&url,
HttpMethod::Post,
&headers,
&RequestBody::Json(serde_json::to_string(&body).expect("batch body serialises")),
)?;
decode(&response.body)
}
pub fn publish_content(
&self,
input: &PublishContentInput<'_>,
) -> Result<PublishResponse, PublishHelperError> {
publish_content(&self.config, input)
}
pub fn publish_prehashed(
&self,
input: &PublishPrehashedInput<'_>,
) -> Result<PublishResponse, PublishHelperError> {
publish_prehashed(&self.config, input)
}
pub fn publish_sealed(
&self,
input: &PublishSealedInput<'_>,
) -> Result<PublishResponse, PublishHelperError> {
publish_sealed(&self.config, input)
}
pub fn publish_merkle(
&self,
input: &PublishMerkleInput<'_>,
) -> Result<PublishMerkleResponse, PublishHelperError> {
publish_merkle(&self.config, input)
}
}
fn signatures_to_json(sigs: &[crate::client::types::RecordSignature]) -> serde_json::Value {
serde_json::Value::Array(
sigs.iter()
.map(|s| {
let mut map = serde_json::Map::new();
map.insert(
"cose_sign1".to_string(),
serde_json::Value::String(s.cose_sign1.clone()),
);
if let Some(key) = &s.cose_key {
map.insert(
"cose_key".to_string(),
serde_json::Value::String(key.clone()),
);
}
serde_json::Value::Object(map)
})
.collect(),
)
}