Skip to content

Commit 112828f

Browse files
authored
Proxy /r/sat/{sat}/at/{index} endpoint (#4022)
1 parent 0235b18 commit 112828f

File tree

1 file changed

+90
-11
lines changed

1 file changed

+90
-11
lines changed

src/subcommand/server.rs

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ struct Search {
7979
#[folder = "static"]
8080
struct StaticAssets;
8181

82+
lazy_static! {
83+
static ref SAT_AT_INDEX_PATH: Regex = Regex::new(r"^/r/sat/[^/]+/at/[^/]+$").unwrap();
84+
}
85+
8286
#[derive(Debug, Parser, Clone)]
8387
pub struct Server {
8488
#[arg(
@@ -273,7 +277,6 @@ impl Server {
273277
get(r::parent_inscriptions_paginated),
274278
)
275279
.route("/r/sat/{sat_number}", get(r::sat))
276-
.route("/r/sat/{sat_number}/at/{index}", get(r::sat_at_index))
277280
.route("/r/sat/{sat_number}/{page}", get(r::sat_paginated))
278281
.route("/r/tx/{txid}", get(r::tx))
279282
.route(
@@ -291,11 +294,12 @@ impl Server {
291294
)
292295
.route("/r/inscription/{inscription_id}", get(r::inscription))
293296
.route("/r/metadata/{inscription_id}", get(r::metadata))
297+
.route("/r/sat/{sat_number}/at/{index}", get(r::sat_at_index))
294298
.route(
295299
"/r/sat/{sat_number}/at/{index}/content",
296300
get(r::sat_at_index_content),
297301
)
298-
.layer(axum::middleware::from_fn(Self::proxy_fallback));
302+
.layer(axum::middleware::from_fn(Self::proxy_layer));
299303

300304
let router = router.merge(proxiable_routes);
301305

@@ -529,22 +533,37 @@ impl Server {
529533
Ok(acceptor)
530534
}
531535

532-
async fn proxy_fallback(
533-
Extension(server_config): Extension<Arc<ServerConfig>>,
536+
async fn proxy_layer(
537+
server_config: Extension<Arc<ServerConfig>>,
534538
request: http::Request<axum::body::Body>,
535539
next: axum::middleware::Next,
536540
) -> ServerResult {
537-
let mut path = request.uri().path().to_string();
538-
539-
path.remove(0); // remove leading slash
541+
let path = request.uri().path().to_owned();
540542

541543
let response = next.run(request).await;
542-
let status = response.status();
543544

544-
if let Some(proxy) = server_config.proxy.as_ref() {
545-
if status == StatusCode::NOT_FOUND {
545+
if let Some(proxy) = &server_config.proxy {
546+
if response.status() == StatusCode::NOT_FOUND {
546547
return task::block_in_place(|| Server::proxy(proxy, &path));
547548
}
549+
550+
// `/r/sat/<SAT_NUMBER>/at/<INDEX>` does not return a 404 when no
551+
// inscription is present, so we must deserialize and check the body.
552+
if SAT_AT_INDEX_PATH.is_match(&path) {
553+
let (parts, body) = response.into_parts();
554+
555+
let bytes = axum::body::to_bytes(body, usize::MAX)
556+
.await
557+
.map_err(|err| anyhow!(err))?;
558+
559+
if let Ok(api::SatInscription { id: None }) =
560+
serde_json::from_slice::<api::SatInscription>(&bytes)
561+
{
562+
return task::block_in_place(|| Server::proxy(proxy, &path));
563+
}
564+
565+
return Ok(Response::from_parts(parts, axum::body::Body::from(bytes)));
566+
}
548567
}
549568

550569
Ok(response)
@@ -1856,7 +1875,7 @@ impl Server {
18561875

18571876
fn proxy(proxy: &Url, path: &str) -> ServerResult<Response> {
18581877
let response = reqwest::blocking::Client::new()
1859-
.get(format!("{}{}", proxy, path))
1878+
.get(format!("{}{}", proxy, &path[1..]))
18601879
.send()
18611880
.map_err(|err| anyhow!(err))?;
18621881

@@ -7039,6 +7058,66 @@ next
70397058
);
70407059
}
70417060

7061+
#[test]
7062+
fn sat_at_index_proxy() {
7063+
let server = TestServer::builder()
7064+
.index_sats()
7065+
.chain(Chain::Regtest)
7066+
.build();
7067+
7068+
server.mine_blocks(1);
7069+
7070+
let inscription = Inscription {
7071+
content_type: Some("text/html".into()),
7072+
body: Some("foo".into()),
7073+
..default()
7074+
};
7075+
7076+
let txid = server.core.broadcast_tx(TransactionTemplate {
7077+
inputs: &[(1, 0, 0, inscription.to_witness())],
7078+
..default()
7079+
});
7080+
7081+
server.mine_blocks(1);
7082+
7083+
let id = InscriptionId { txid, index: 0 };
7084+
let ordinal: u64 = 5000000000;
7085+
7086+
pretty_assert_eq!(
7087+
server.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
7088+
api::SatInscription { id: Some(id) }
7089+
);
7090+
7091+
let server_with_proxy = TestServer::builder()
7092+
.chain(Chain::Regtest)
7093+
.server_option("--proxy", server.url.as_ref())
7094+
.build();
7095+
let sat_indexed_server_with_proxy = TestServer::builder()
7096+
.index_sats()
7097+
.chain(Chain::Regtest)
7098+
.server_option("--proxy", server.url.as_ref())
7099+
.build();
7100+
7101+
server_with_proxy.mine_blocks(1);
7102+
sat_indexed_server_with_proxy.mine_blocks(1);
7103+
7104+
pretty_assert_eq!(
7105+
server.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
7106+
api::SatInscription { id: Some(id) }
7107+
);
7108+
7109+
pretty_assert_eq!(
7110+
server_with_proxy.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
7111+
api::SatInscription { id: Some(id) }
7112+
);
7113+
7114+
pretty_assert_eq!(
7115+
sat_indexed_server_with_proxy
7116+
.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
7117+
api::SatInscription { id: Some(id) }
7118+
);
7119+
}
7120+
70427121
#[test]
70437122
fn sat_at_index_content_proxy() {
70447123
let server = TestServer::builder()

0 commit comments

Comments
 (0)