notecrumbs

a nostr opengraph server build on nostrdb and egui
git clone git://jb55.com/notecrumbs
Log | Files | Refs | README | LICENSE

html.rs (5190B)


      1 use crate::Error;
      2 use crate::{
      3     abbrev::{abbrev_str, abbreviate},
      4     render, Notecrumbs,
      5 };
      6 use html_escape;
      7 use http_body_util::Full;
      8 use hyper::{
      9     body::Bytes, header, server::conn::http1, service::service_fn, Request, Response, StatusCode,
     10 };
     11 use hyper_util::rt::TokioIo;
     12 use log::error;
     13 use nostr_sdk::prelude::{Nip19, ToBech32};
     14 use nostrdb::{BlockType, Blocks, Mention, Ndb, Note, Transaction};
     15 use std::io::Write;
     16 
     17 pub fn render_note_content(body: &mut Vec<u8>, ndb: &Ndb, note: &Note, blocks: &Blocks) {
     18     for block in blocks.iter(note) {
     19         let blocktype = block.blocktype();
     20 
     21         match block.blocktype() {
     22             BlockType::Url => {
     23                 let url = html_escape::encode_text(block.as_str());
     24                 write!(body, r#"<a href="{}">{}</a>"#, url, url);
     25             }
     26 
     27             BlockType::Hashtag => {
     28                 let hashtag = html_escape::encode_text(block.as_str());
     29                 write!(body, r#"<span class="hashtag">#{}</span>"#, hashtag);
     30             }
     31 
     32             BlockType::Text => {
     33                 let text = html_escape::encode_text(block.as_str());
     34                 write!(body, r"{}", text);
     35             }
     36 
     37             BlockType::Invoice => {
     38                 write!(body, r"{}", block.as_str());
     39             }
     40 
     41             BlockType::MentionIndex => {
     42                 write!(body, r"@nostrich");
     43             }
     44 
     45             BlockType::MentionBech32 => {
     46                 let pk = match block.as_mention().unwrap() {
     47                     Mention::Event(_)
     48                     | Mention::Note(_)
     49                     | Mention::Profile(_)
     50                     | Mention::Pubkey(_)
     51                     | Mention::Secret(_)
     52                     | Mention::Addr(_) => {
     53                         write!(
     54                             body,
     55                             r#"<a href="/{}">@{}</a>"#,
     56                             block.as_str(),
     57                             &abbrev_str(block.as_str())
     58                         );
     59                     }
     60 
     61                     Mention::Relay(relay) => {
     62                         write!(
     63                             body,
     64                             r#"<a href="/{}">{}</a>"#,
     65                             block.as_str(),
     66                             &abbrev_str(relay.as_str())
     67                         );
     68                     }
     69                 };
     70             }
     71         };
     72     }
     73 }
     74 
     75 pub fn serve_note_html(
     76     app: &Notecrumbs,
     77     nip19: &Nip19,
     78     note_data: &render::NoteRenderData,
     79     r: Request<hyper::body::Incoming>,
     80 ) -> Result<Response<Full<Bytes>>, Error> {
     81     let mut data = Vec::new();
     82 
     83     // indices
     84     //
     85     // 0: name
     86     // 1: abbreviated description
     87     // 2: hostname
     88     // 3: bech32 entity
     89     // 4: Full content
     90 
     91     let hostname = "https://damus.io";
     92     let abbrev_content = html_escape::encode_text(abbreviate(&note_data.note.content, 64));
     93     let profile_name = html_escape::encode_text(&note_data.profile.name);
     94 
     95     write!(
     96         data,
     97         r#"
     98         <html>
     99         <head>
    100           <title>{0} on nostr</title>
    101           <meta name="viewport" content="width=device-width, initial-scale=1">
    102           <meta charset="UTF-8">
    103 
    104           <meta property="og:description" content="{1}" />
    105           <meta property="og:image" content="{2}/{3}.png"/>
    106           <meta property="og:image:alt" content="{0}: {1}" />
    107           <meta property="og:image:height" content="600" />
    108           <meta property="og:image:width" content="1200" />
    109           <meta property="og:image:type" content="image/png" />
    110           <meta property="og:site_name" content="Damus" />
    111           <meta property="og:title" content="{0} on nostr" />
    112           <meta property="og:url" content="{2}/{3}"/>
    113           <meta name="og:type" content="website"/>
    114           <meta name="twitter:image:src" content="{2}/{3}.png" />
    115           <meta name="twitter:site" content="@damusapp" />
    116           <meta name="twitter:card" content="summary_large_image" />
    117           <meta name="twitter:title" content="{0} on nostr" />
    118           <meta name="twitter:description" content="{1}" />
    119       
    120         </head>
    121         <body>
    122           <h3>Note!</h3>
    123           <div class="note">
    124               <div class="note-content">"#,
    125         profile_name,
    126         abbrev_content,
    127         hostname,
    128         nip19.to_bech32().unwrap()
    129     )?;
    130 
    131     let ok = (|| -> Result<(), nostrdb::Error> {
    132         let txn = Transaction::new(&app.ndb)?;
    133         let note_id = note_data.note.id.ok_or(nostrdb::Error::NotFound)?;
    134         let note = app.ndb.get_note_by_id(&txn, &note_id)?;
    135         let blocks = app.ndb.get_blocks_by_key(&txn, note.key().unwrap())?;
    136 
    137         render_note_content(&mut data, &app.ndb, &note, &blocks);
    138 
    139         Ok(())
    140     })();
    141 
    142     if let Err(err) = ok {
    143         error!("error rendering html: {}", err);
    144         write!(
    145             data,
    146             "{}",
    147             html_escape::encode_text(&note_data.note.content)
    148         );
    149     }
    150 
    151     write!(
    152         data,
    153         "
    154                </div>
    155             </div>
    156         </body>
    157     </html>
    158     "
    159     );
    160 
    161     Ok(Response::builder()
    162         .header(header::CONTENT_TYPE, "text/html")
    163         .status(StatusCode::OK)
    164         .body(Full::new(Bytes::from(data)))?)
    165 }