use super::{Endpoint, RemoteResource};
use crate::error::ApiResult;
use crate::param;
use crate::prelude::*;
use crate::schema::pid::{Handle, PersistentIdentifier};
use crate::util::constants::HTTP_URL;
use alloc::collections::BTreeSet;
use color_eyre::eyre::eyre;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Record {
pub response_code: u16,
pub handle: String,
#[serde(default)]
pub values: Vec<Value>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Value {
pub index: u32,
#[serde(rename = "type")]
pub kind: String,
pub data: ValueData,
pub permissions: Option<String>,
pub ttl: Option<u64>,
pub timestamp: Option<String>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct ValueData {
pub format: String,
pub value: serde_json::Value,
}
impl Record {
pub fn public_urls(&self) -> Vec<String> {
self.values
.iter()
.filter(|value| value.kind.eq_ignore_ascii_case("URL") && value.data.format.eq_ignore_ascii_case("string"))
.filter_map(|value| value.data.value.as_str())
.filter(|value| HTTP_URL.is_match(value).unwrap_or(false))
.map(str::to_string)
.collect::<BTreeSet<_>>()
.into_iter()
.collect()
}
pub(crate) fn validate(self) -> ApiResult<Self> {
match self.response_code {
| 1 => Ok(self),
| code => Err(eyre!("Handle proxy could not resolve the Handle — response code {code}")),
}
}
}
pub async fn resolve(identifier: &Handle) -> ApiResult<Record> {
match Endpoint::from_template("handle") {
| Ok(endpoint) => resolve_with(&endpoint, identifier).await,
| Err(why) => Err(eyre!("Handle API endpoint is unavailable — {why}")),
}
}
pub(crate) async fn resolve_with(endpoint: &Endpoint, identifier: &Handle) -> ApiResult<Record> {
let value = identifier.identifier();
match value.is_empty() {
| true => Err(eyre!("Handle resolver requires a valid Handle")),
| false => {
let encoded = value.split('/').map(urlencoding::encode).collect::<Vec<_>>().join("/");
let data = Some(vec![param!(TemplateValue, "identifier", encoded.as_str())]);
let response = endpoint.invoke("record", data).await;
endpoint
.handle::<Record>(response)
.map_err(|why| eyre!("Handle proxy returned invalid resolver metadata — {why}"))
.and_then(Record::validate)
}
}
}