noosphere_into/transcluder/
content.rs1use std::marker::PhantomData;
2
3use crate::{ResolvedLink, TextTransclude, Transclude, Transcluder};
4use anyhow::Result;
5use async_trait::async_trait;
6use noosphere_core::context::{HasSphereContext, SphereContentRead};
7use noosphere_core::data::Header;
8use noosphere_storage::Storage;
9use subtext::{block::Block, primitive::Entity, Peer};
10use tokio_stream::StreamExt;
11
12#[derive(Clone)]
15pub struct SphereContentTranscluder<R, S>
16where
17 R: HasSphereContext<S> + Clone,
18 S: Storage + 'static,
19{
20 content: R,
21 storage_type: PhantomData<S>,
22}
23
24impl<R, S> SphereContentTranscluder<R, S>
25where
26 R: HasSphereContext<S> + Clone,
27 S: Storage + 'static,
28{
29 pub fn new(content: R) -> Self {
30 SphereContentTranscluder {
31 content,
32 storage_type: PhantomData,
33 }
34 }
35}
36
37#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
38#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
39impl<R, S> Transcluder for SphereContentTranscluder<R, S>
40where
41 R: HasSphereContext<S> + Clone,
42 S: Storage + 'static,
43{
44 async fn transclude(&self, link: &ResolvedLink) -> Result<Option<Transclude>> {
45 match link {
46 ResolvedLink::Hyperlink { .. } => {
47 Ok(None)
49 }
50 ResolvedLink::Slashlink { link, href } => {
51 match link.peer {
52 Peer::None => {
53 }
56 _ => return Ok(None),
57 };
58
59 let slug = match &link.slug {
60 Some(slug) => slug.to_owned(),
61 None => return Ok(None),
62 };
63 Ok(match self.content.read(&slug).await? {
66 Some(file) => {
67 let title = file.memo.get_first_header(&Header::Title);
70
71 let subtext_ast_stream =
72 subtext::stream::<Block<Entity>, _, _>(file.contents).await;
73
74 tokio::pin!(subtext_ast_stream);
75
76 let mut excerpt = None;
77
78 while let Some(Ok(block)) = subtext_ast_stream.next().await {
79 match block {
80 Block::Blank(_) => continue,
81 any_other => {
82 excerpt = Some(any_other.to_text_content());
83 break;
84 }
85 }
86 }
87
88 Some(Transclude::Text(TextTransclude {
89 title,
90 excerpt,
91 link_text: format!("/{slug}"),
92 href: href.to_owned(),
93 }))
94 }
95 None => {
96 Some(Transclude::Text(TextTransclude {
100 title: None,
101 excerpt: None,
102 link_text: format!("/{slug}"),
103 href: href.to_owned(),
104 }))
105 }
106 })
107 }
108 }
109 }
110}