Also attempt to verify from meta
This commit is contained in:
parent
863d20a79d
commit
968fe675cd
70
src/main.rs
70
src/main.rs
|
@ -1,5 +1,8 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use fluffer::{App, AppErr, Client, Fluff};
|
||||
use germ::ast::{Ast as GeminiAst, Node as GemtextNode};
|
||||
use germ::meta::Meta as GeminiMetadata;
|
||||
use germ::request::request as germ_request;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
@ -17,19 +20,39 @@ enum GementionError {
|
|||
}
|
||||
|
||||
enum VerificationStatus {
|
||||
Verified(String),
|
||||
Verified {
|
||||
endpoint: String,
|
||||
source: VerificationSource,
|
||||
},
|
||||
|
||||
NotVerified(VerificationFailureReason),
|
||||
}
|
||||
|
||||
impl ToString for VerificationStatus {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::Verified(url) => format!("verified: {}", url),
|
||||
Self::Verified { endpoint, source } => format!("verified: {} [{}]", endpoint, source),
|
||||
Self::NotVerified(failure) => failure.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum VerificationSource {
|
||||
Meta,
|
||||
Page,
|
||||
}
|
||||
|
||||
impl Display for VerificationSource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Meta => write!(f, "source=meta"),
|
||||
Self::Page => write!(f, "source=page"),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
enum VerificationFailureReason {
|
||||
/// No titan link to our endpoint exists on this page.
|
||||
NoMentionLinkFound,
|
||||
|
@ -58,25 +81,48 @@ fn is_mention_link(gemtext_link: &str) -> Result<bool, GementionError> {
|
|||
Ok(gemtext_link.starts_with(OUR_ENDPOINT))
|
||||
}
|
||||
|
||||
fn scan_for_mentions(ast: GeminiAst) -> Vec<String> {
|
||||
ast.inner()
|
||||
fn scan_for_mentions(meta: GeminiMetadata, ast: GeminiAst) -> (VerificationSource, Vec<String>) {
|
||||
// Check metadata of the page for a gemention endpoint.
|
||||
println!("meta is {:?}", meta);
|
||||
if let Some(endpoint) = meta.parameters().get("gemention") {
|
||||
let endpoint = endpoint.trim_start_matches("=");
|
||||
return (VerificationSource::Meta, vec![endpoint.to_owned()]);
|
||||
}
|
||||
|
||||
// If that fails, check the page itself for the first available
|
||||
// link that matches.
|
||||
let endpoints = ast
|
||||
.inner()
|
||||
.into_iter()
|
||||
.filter_map(|node| match node {
|
||||
GemtextNode::Link { ref to, .. } if is_mention_link(to).unwrap_or(false) => Some(to),
|
||||
_ => None,
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
.collect();
|
||||
|
||||
(VerificationSource::Page, endpoints)
|
||||
}
|
||||
|
||||
fn verify_mentions<S: AsRef<str>>(expected_link: S, mentions: Vec<String>) -> VerificationStatus {
|
||||
fn verify_mentions<S: AsRef<str>>(
|
||||
expected_link: S,
|
||||
source_and_mentions: (VerificationSource, Vec<String>),
|
||||
) -> VerificationStatus {
|
||||
let (verification_source, mentions) = source_and_mentions;
|
||||
let expected_link = expected_link.as_ref();
|
||||
|
||||
if mentions.len() > 0 {
|
||||
// We have links that go to our endpoint. Scan links for the
|
||||
// one we expect (i.e. for the target), otherwise we say
|
||||
// incorrect link.
|
||||
mentions
|
||||
.into_iter()
|
||||
.find_map(|link| {
|
||||
if link == expected_link {
|
||||
Some(VerificationStatus::Verified(link))
|
||||
Some(VerificationStatus::Verified {
|
||||
source: verification_source,
|
||||
endpoint: link,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -89,18 +135,20 @@ fn verify_mentions<S: AsRef<str>>(expected_link: S, mentions: Vec<String>) -> Ve
|
|||
}
|
||||
}
|
||||
|
||||
async fn verify_mention(target: &str) -> Result<VerificationStatus, GementionError> {
|
||||
let url = Url::parse(&format!("gemini://{}", target))?;
|
||||
let expected_link = Url::parse(OUR_ENDPOINT)?.join(target)?;
|
||||
async fn verify_mention(target_page: &str) -> Result<VerificationStatus, GementionError> {
|
||||
let url = Url::parse(&format!("gemini://{}", target_page))?;
|
||||
let expected_link = Url::parse(OUR_ENDPOINT)?.join(target_page)?;
|
||||
|
||||
let resp = germ_request(&url).await?;
|
||||
let meta = GeminiMetadata::from_string(resp.meta());
|
||||
|
||||
let content = resp
|
||||
.content()
|
||||
.as_deref()
|
||||
.ok_or(GementionError::NoContentFoundForTarget)?;
|
||||
|
||||
let ast = GeminiAst::from_string(content);
|
||||
let mentions = scan_for_mentions(ast);
|
||||
let mentions = scan_for_mentions(meta, ast);
|
||||
Ok(verify_mentions(expected_link, mentions))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue