Skip to content

Commit

Permalink
Support PDF Inscriptions (#1352)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey authored Jan 24, 2023
1 parent 58a6c8f commit c29bee8
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ tempfile = "3.2.0"
tokio = { version = "1.17.0", features = ["rt-multi-thread"] }
tokio-stream = "0.1.9"
tokio-util = {version = "0.7.3", features = ["compat"] }
tower-http = { version = "0.3.3", features = ["set-header"] }
tower-http = { version = "0.3.3", features = ["cors", "set-header"] }

[dev-dependencies]
executable-path = "1.0.0"
Expand Down
2 changes: 2 additions & 0 deletions src/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub(crate) enum Media {
Audio,
Iframe,
Image,
Pdf,
Text,
Unknown,
}
Expand Down Expand Up @@ -48,6 +49,7 @@ impl FromStr for Media {
}

const TABLE: &[(&str, Media, &[&str])] = &[
("application/pdf", Media::Pdf, &["pdf"]),
("audio/flac", Media::Audio, &["flac"]),
("audio/mpeg", Media::Audio, &["mp3"]),
("audio/wav", Media::Audio, &["wav"]),
Expand Down
47 changes: 43 additions & 4 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use {
super::*,
crate::templates::{
BlockHtml, ClockSvg, HomeHtml, InputHtml, InscriptionHtml, InscriptionsHtml, OutputHtml,
PageContent, PageHtml, PreviewAudioHtml, PreviewImageHtml, PreviewTextHtml, PreviewUnknownHtml,
RangeHtml, RareTxt, SatHtml, TransactionHtml,
PageContent, PageHtml, PreviewAudioHtml, PreviewImageHtml, PreviewPdfHtml, PreviewTextHtml,
PreviewUnknownHtml, RangeHtml, RareTxt, SatHtml, TransactionHtml,
},
axum::{
body,
Expand All @@ -28,7 +28,10 @@ use {
},
std::{cmp::Ordering, str},
tokio_stream::StreamExt,
tower_http::set_header::SetResponseHeaderLayer,
tower_http::{
cors::{Any, CorsLayer},
set_header::SetResponseHeaderLayer,
},
};

mod error;
Expand Down Expand Up @@ -163,7 +166,12 @@ impl Server {
.layer(SetResponseHeaderLayer::overriding(
header::STRICT_TRANSPORT_SECURITY,
HeaderValue::from_static("max-age=31536000; includeSubDomains; preload"),
));
))
.layer(
CorsLayer::new()
.allow_methods([http::Method::GET])
.allow_origin(Any),
);

match (self.http_port(), self.https_port()) {
(Some(http_port), None) => {
Expand Down Expand Up @@ -751,6 +759,16 @@ impl Server {
.ok_or_not_found(|| format!("inscription {inscription_id} content"))?
.into_response(),
),
Media::Pdf => Ok(
(
[(
header::CONTENT_SECURITY_POLICY,
"script-src-elem 'self' https://cdn.jsdelivr.net",
)],
PreviewPdfHtml { inscription_id },
)
.into_response(),
),
Media::Text => {
let content = inscription
.body()
Expand Down Expand Up @@ -1995,6 +2013,27 @@ mod tests {
);
}

#[test]
fn pdf_preview() {
let server = TestServer::new();
server.mine_blocks(1);

let txid = server.bitcoin_rpc_server.broadcast_tx(TransactionTemplate {
inputs: &[(1, 0, 0)],
witness: inscription("application/pdf", "hello").to_witness(),
..Default::default()
});
let inscription_id = InscriptionId::from(txid);

server.mine_blocks(1);

server.assert_response_regex(
format!("/preview/{inscription_id}"),
StatusCode::OK,
format!(r".*<canvas data-inscription={inscription_id}></canvas>.*"),
);
}

#[test]
fn image_preview() {
let server = TestServer::new();
Expand Down
4 changes: 3 additions & 1 deletion src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ pub(crate) use {
inscription::InscriptionHtml,
inscriptions::InscriptionsHtml,
output::OutputHtml,
preview::{PreviewAudioHtml, PreviewImageHtml, PreviewTextHtml, PreviewUnknownHtml},
preview::{
PreviewAudioHtml, PreviewImageHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml,
},
range::RangeHtml,
rare::RareTxt,
sat::SatHtml,
Expand Down
5 changes: 5 additions & 0 deletions src/templates/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ pub(crate) struct PreviewImageHtml {
pub(crate) inscription_id: InscriptionId,
}

#[derive(boilerplate::Boilerplate)]
pub(crate) struct PreviewPdfHtml {
pub(crate) inscription_id: InscriptionId,
}

#[derive(boilerplate::Boilerplate)]
pub(crate) struct PreviewTextHtml<'a> {
pub(crate) text: &'a str,
Expand Down
14 changes: 14 additions & 0 deletions static/preview-pdf.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
html {
height: 100%;
}

body {
height: 100%;
margin: 0;
}

canvas {
height: 100%;
width: 100%;
object-fit: contain;
}
23 changes: 23 additions & 0 deletions static/preview-pdf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import pdfjs from 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.2.146/+esm';

pdfjs.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.2.146/build/pdf.worker.min.js';

let canvas = document.querySelector('canvas');

let pdf = await pdfjs.getDocument(`/content/${canvas.dataset.inscription}`).promise;

let page = await pdf.getPage(1);

let scale = window.devicePixelRatio || 1;

let viewport = page.getViewport({ scale });

canvas.width = Math.ceil(viewport.width * scale);

canvas.height = Math.ceil(viewport.height * scale);

page.render({
canvasContext: canvas.getContext('2d'),
transform: [scale, 0, 0, scale, 0, 0],
viewport,
});
11 changes: 11 additions & 0 deletions templates/preview-pdf.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<link rel=stylesheet href=/static/preview-pdf.css>
<script src=/static/preview-pdf.js defer type=module></script>
</head>
<body>
<canvas data-inscription={{self.inscription_id}}></canvas>
</body>
</html>

0 comments on commit c29bee8

Please sign in to comment.