nostralink 0.1.9

Linked data library for nostr
Documentation
use super::manager::{RdfEventsStore, RdfStoreError};
use super::util::*;
use crate::niri::ToNamedNode;
use crate::querydb::nrq_get;
use nostr::PublicKey;
use nostr_sdk::prelude::*;
use oxigraph::model::*;

pub trait RelaysPrefsManager {
    fn set_flags_for_relay(
        &self,
        pubk: &PublicKey,
        relay_node: NamedNode,
        flags: AtomicRelayServiceFlags,
    ) -> Result<(), RdfStoreError>;

    fn relay_flags_for_pubk(
        &self,
        pubk: &PublicKey,
        relay_node: &NamedNode,
    ) -> Result<AtomicRelayServiceFlags, RdfStoreError>;

    fn read_relays_for_pubk(
        &self,
        pubk: &PublicKey,
    ) -> Result<Vec<RelayUrl>, RdfStoreError>;

    fn write_relays_for_pubk(
        &self,
        pubk: &PublicKey,
    ) -> Result<Vec<RelayUrl>, RdfStoreError>;
}

fn pred_write() -> NamedNode {
    NamedNode::new_unchecked("http://nostralink.org/NostrRelay#writes")
}

fn pred_read() -> NamedNode {
    NamedNode::new_unchecked("http://nostralink.org/NostrRelay#reads")
}

fn pred_discovery() -> NamedNode {
    NamedNode::new_unchecked("http://nostralink.org/NostrRelay#discovers")
}

impl RelaysPrefsManager for RdfEventsStore {
    fn set_flags_for_relay(
        &self,
        pubk: &PublicKey,
        relay_node: NamedNode,
        flags: AtomicRelayServiceFlags,
    ) -> Result<(), RdfStoreError> {
        let user_nn = pubk.named_node()?;

        let qr = QuadRef::new(
            &user_nn,
            NamedNodeRef::new_unchecked(
                "http://nostralink.org/NostrRelay#writes",
            ),
            &relay_node,
            &GraphName::DefaultGraph,
        );

        if flags.has_write() {
            let _ = self.store.insert(qr);
        } else {
            let _ = self.store.remove(qr);
        }

        let qr = QuadRef::new(
            &user_nn,
            NamedNodeRef::new_unchecked(
                "http://nostralink.org/NostrRelay#reads",
            ),
            &relay_node,
            &GraphName::DefaultGraph,
        );

        if flags.has_read() {
            let _ = self.store.insert(qr);
        } else {
            let _ = self.store.remove(qr);
        }

        let qr = QuadRef::new(
            &user_nn,
            NamedNodeRef::new_unchecked(
                "http://nostralink.org/NostrRelay#discovers",
            ),
            &relay_node,
            &GraphName::DefaultGraph,
        );

        if flags.has_discovery() {
            let _ = self.store.insert(qr);
        } else {
            let _ = self.store.remove(qr);
        }

        Ok(())
    }

    fn relay_flags_for_pubk(
        &self,
        pubk: &PublicKey,
        relay_node: &NamedNode,
    ) -> Result<AtomicRelayServiceFlags, RdfStoreError> {
        let user_nn = pubk.named_node()?;
        let flags = AtomicRelayServiceFlags::new(RelayServiceFlags::NONE);

        let results = self.store.quads_for_pattern(
            Some((&user_nn).into()),
            None,
            Some((relay_node).into()),
            None,
        );

        for quad_item in results {
            let quad = quad_item.map_err(|_| RdfStoreError::QuadError)?;

            if quad.predicate == pred_write() {
                flags.add(RelayServiceFlags::WRITE);
            }
            if quad.predicate == pred_read() {
                flags.add(RelayServiceFlags::READ);
            }
            if quad.predicate == pred_discovery() {
                flags.add(RelayServiceFlags::DISCOVERY);
            }
        }

        Ok(flags)
    }

    fn read_relays_for_pubk(
        &self,
        pubk: &PublicKey,
    ) -> Result<Vec<RelayUrl>, RdfStoreError> {
        let subs = [
            subl("query_relay_readers", Literal::from(1))
                .map_err(|_| RdfStoreError::SubstitutionError)?,
            subl("query_relay_writers", Literal::from(0))
                .map_err(|_| RdfStoreError::SubstitutionError)?,
            subl("query_relay_discoverers", Literal::from(0))
                .map_err(|_| RdfStoreError::SubstitutionError)?,
            subnn("nip21", pubk.named_node()?)
                .map_err(|_| RdfStoreError::SubstitutionError)?,
        ];

        let results = self
            .run_query(
                &nrq_get("user_relays")
                    .map_err(|_| RdfStoreError::QueryError)?,
                subs,
                None,
            )
            .map_err(|_| RdfStoreError::QueryError)?;

        Ok(results
            .rows
            .iter()
            .filter_map(|row| match row.get("url") {
                Some(url_s) => match RelayUrl::parse(&url_s.to_string()) {
                    Ok(url) => Some(url),
                    Err(_e) => None,
                },
                None => None,
            })
            .collect())
    }

    fn write_relays_for_pubk(
        &self,
        pubk: &PublicKey,
    ) -> Result<Vec<RelayUrl>, RdfStoreError> {
        let subs = [
            subl("query_relay_readers", Literal::from(0))
                .map_err(|_| RdfStoreError::SubstitutionError)?,
            subl("query_relay_writers", Literal::from(1))
                .map_err(|_| RdfStoreError::SubstitutionError)?,
            subl("query_relay_discoverers", Literal::from(0))
                .map_err(|_| RdfStoreError::SubstitutionError)?,
            subnn("nip21", pubk.named_node()?)
                .map_err(|_| RdfStoreError::SubstitutionError)?,
        ];

        let results = self
            .run_query(
                &nrq_get("user_relays")
                    .map_err(|_| RdfStoreError::QueryError)?,
                subs,
                None,
            )
            .map_err(|_| RdfStoreError::QueryError)?;

        Ok(results
            .rows
            .iter()
            .filter_map(|row| match row.get("url") {
                Some(url_s) => match RelayUrl::parse(&url_s.to_string()) {
                    Ok(url) => Some(url),
                    Err(_e) => None,
                },
                None => None,
            })
            .collect())
    }
}