use crate::err::LDError;
use nostr::{
event::EventId, nips::nip21::FromNostrUri, nips::nip21::ToNostrUri,
PublicKey,
};
use oxigraph::model::*;
use oxiri::Iri as OxIri;
use rand_09::{distr::Alphanumeric, Rng};
use serde_json::Value;
use sha256::digest;
use sophia_iri::resolve::BaseIri;
use sophia_jsonld::vocabulary::ArcIri;
use url::Url;
use urn::UrnBuilder;
pub const NOSTRA_BASE_IRI: &str = "http://nostralink.org/";
const NSS_NOSTR_CONTENT: &str = "nostr-content";
const NSS_NOSTR_EVENT: &str = "nostr-event";
pub trait ToNamedNode {
fn named_node(&self) -> Result<NamedNode, LDError>;
fn named_node_with_f(&self, _f_comp: &str) -> Result<NamedNode, LDError> {
Err(LDError::NamedNodeConvertError)
}
}
pub trait FromNamedNode {
fn from_named_node(&self) -> Result<PublicKey, LDError>;
}
impl ToNamedNode for EventId {
fn named_node(&self) -> Result<NamedNode, LDError> {
let urn = UrnBuilder::new(NSS_NOSTR_EVENT, &self.to_hex())
.build()
.unwrap();
Ok(NamedNode::new_unchecked(urn.as_str()))
}
fn named_node_with_f(&self, f_comp: &str) -> Result<NamedNode, LDError> {
let mut urn = UrnBuilder::new(NSS_NOSTR_EVENT, &self.to_hex())
.build()
.unwrap();
let _ = urn.set_f_component(Some(f_comp));
Ok(NamedNode::new(urn.as_str()).unwrap())
}
}
impl ToNamedNode for PublicKey {
fn named_node(&self) -> Result<NamedNode, LDError> {
match self.to_nostr_uri() {
Ok(uri) => Ok(NamedNode::new_unchecked(uri)),
Err(_err) => Err(LDError::NamedNodeConvertError),
}
}
fn named_node_with_f(&self, f_comp: &str) -> Result<NamedNode, LDError> {
match self.to_nostr_uri() {
Ok(uri) => Ok(NamedNode::new_unchecked(format!("{uri}#{f_comp}"))),
Err(_err) => Err(LDError::NamedNodeConvertError),
}
}
}
impl FromNamedNode for NamedNode {
fn from_named_node(&self) -> Result<PublicKey, LDError> {
match PublicKey::from_nostr_uri(&self.clone().into_string()) {
Ok(pk) => Ok(pk),
Err(_err) => Err(LDError::NamedNodeConvertError),
}
}
}
pub fn content_iri_for_value(value: Value) -> Result<String, LDError> {
let content_digest = digest(value.to_string());
let urn = UrnBuilder::new(NSS_NOSTR_CONTENT, &content_digest)
.build()
.map_err(|_| LDError::URNError)?;
Ok(urn.as_str().into())
}
pub fn random_urn_nn() -> NamedNode {
let nid: String = rand_09::rng()
.sample_iter(&Alphanumeric)
.take(128)
.map(char::from)
.collect();
NamedNode::new_unchecked(format!("urn:rand:{nid}"))
}
pub fn nostr_vocab_nn(fragment: &str) -> NamedNode {
let mut url = Url::parse("https://w3id.org/nostr#").unwrap();
url.set_fragment(Some(fragment));
NamedNode::new_unchecked(url.to_string())
}
pub fn nl_base_iri() -> BaseIri<&'static str> {
BaseIri::new(NOSTRA_BASE_IRI).unwrap()
}
pub fn nl_iri(path: &str) -> OxIri<String> {
BaseIri::new(NOSTRA_BASE_IRI)
.unwrap()
.resolve_unchecked(path)
}
pub fn nl_arc_iri(path: &str) -> ArcIri {
ArcIri::new_unchecked(nl_iri(path).to_string().into())
}
#[test]
fn test_iris() {
assert_eq!(
nl_iri("EventReaction").to_string(),
"http://nostralink.org/EventReaction"
);
assert_eq!(nl_iri("Action").to_string(), "http://nostralink.org/Action");
assert_eq!(
nl_iri("Note#frag").to_string(),
"http://nostralink.org/Note#frag"
);
}