Skip to content

Commit

Permalink
Proxy /r/sat/{sat}/at/{index} endpoint (#4022)
Browse files Browse the repository at this point in the history
  • Loading branch information
arik-so authored Feb 25, 2025
1 parent 0235b18 commit 112828f
Showing 1 changed file with 90 additions and 11 deletions.
101 changes: 90 additions & 11 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ struct Search {
#[folder = "static"]
struct StaticAssets;

lazy_static! {
static ref SAT_AT_INDEX_PATH: Regex = Regex::new(r"^/r/sat/[^/]+/at/[^/]+$").unwrap();
}

#[derive(Debug, Parser, Clone)]
pub struct Server {
#[arg(
Expand Down Expand Up @@ -273,7 +277,6 @@ impl Server {
get(r::parent_inscriptions_paginated),
)
.route("/r/sat/{sat_number}", get(r::sat))
.route("/r/sat/{sat_number}/at/{index}", get(r::sat_at_index))
.route("/r/sat/{sat_number}/{page}", get(r::sat_paginated))
.route("/r/tx/{txid}", get(r::tx))
.route(
Expand All @@ -291,11 +294,12 @@ impl Server {
)
.route("/r/inscription/{inscription_id}", get(r::inscription))
.route("/r/metadata/{inscription_id}", get(r::metadata))
.route("/r/sat/{sat_number}/at/{index}", get(r::sat_at_index))
.route(
"/r/sat/{sat_number}/at/{index}/content",
get(r::sat_at_index_content),
)
.layer(axum::middleware::from_fn(Self::proxy_fallback));
.layer(axum::middleware::from_fn(Self::proxy_layer));

let router = router.merge(proxiable_routes);

Expand Down Expand Up @@ -529,22 +533,37 @@ impl Server {
Ok(acceptor)
}

async fn proxy_fallback(
Extension(server_config): Extension<Arc<ServerConfig>>,
async fn proxy_layer(
server_config: Extension<Arc<ServerConfig>>,
request: http::Request<axum::body::Body>,
next: axum::middleware::Next,
) -> ServerResult {
let mut path = request.uri().path().to_string();

path.remove(0); // remove leading slash
let path = request.uri().path().to_owned();

let response = next.run(request).await;
let status = response.status();

if let Some(proxy) = server_config.proxy.as_ref() {
if status == StatusCode::NOT_FOUND {
if let Some(proxy) = &server_config.proxy {
if response.status() == StatusCode::NOT_FOUND {
return task::block_in_place(|| Server::proxy(proxy, &path));
}

// `/r/sat/<SAT_NUMBER>/at/<INDEX>` does not return a 404 when no
// inscription is present, so we must deserialize and check the body.
if SAT_AT_INDEX_PATH.is_match(&path) {
let (parts, body) = response.into_parts();

let bytes = axum::body::to_bytes(body, usize::MAX)
.await
.map_err(|err| anyhow!(err))?;

if let Ok(api::SatInscription { id: None }) =
serde_json::from_slice::<api::SatInscription>(&bytes)
{
return task::block_in_place(|| Server::proxy(proxy, &path));
}

return Ok(Response::from_parts(parts, axum::body::Body::from(bytes)));
}
}

Ok(response)
Expand Down Expand Up @@ -1856,7 +1875,7 @@ impl Server {

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

Expand Down Expand Up @@ -7039,6 +7058,66 @@ next
);
}

#[test]
fn sat_at_index_proxy() {
let server = TestServer::builder()
.index_sats()
.chain(Chain::Regtest)
.build();

server.mine_blocks(1);

let inscription = Inscription {
content_type: Some("text/html".into()),
body: Some("foo".into()),
..default()
};

let txid = server.core.broadcast_tx(TransactionTemplate {
inputs: &[(1, 0, 0, inscription.to_witness())],
..default()
});

server.mine_blocks(1);

let id = InscriptionId { txid, index: 0 };
let ordinal: u64 = 5000000000;

pretty_assert_eq!(
server.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
api::SatInscription { id: Some(id) }
);

let server_with_proxy = TestServer::builder()
.chain(Chain::Regtest)
.server_option("--proxy", server.url.as_ref())
.build();
let sat_indexed_server_with_proxy = TestServer::builder()
.index_sats()
.chain(Chain::Regtest)
.server_option("--proxy", server.url.as_ref())
.build();

server_with_proxy.mine_blocks(1);
sat_indexed_server_with_proxy.mine_blocks(1);

pretty_assert_eq!(
server.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
api::SatInscription { id: Some(id) }
);

pretty_assert_eq!(
server_with_proxy.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
api::SatInscription { id: Some(id) }
);

pretty_assert_eq!(
sat_indexed_server_with_proxy
.get_json::<api::SatInscription>(format!("/r/sat/{ordinal}/at/-1")),
api::SatInscription { id: Some(id) }
);
}

#[test]
fn sat_at_index_content_proxy() {
let server = TestServer::builder()
Expand Down

0 comments on commit 112828f

Please sign in to comment.