mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-26 10:18:10 -07:00
global: fixes
This commit is contained in:
@@ -10,7 +10,7 @@ use brk_types::{AddrStats, AddrValidation, Transaction, Txid, Utxo, Version};
|
||||
use crate::{
|
||||
AppState, CacheStrategy,
|
||||
extended::TransformResponseExtended,
|
||||
params::{AddrParam, AddrTxidsParam, ValidateAddrParam},
|
||||
params::{AddrParam, AddrTxidsParam, Empty, ValidateAddrParam},
|
||||
};
|
||||
|
||||
pub trait AddrRoutes {
|
||||
@@ -28,6 +28,7 @@ impl AddrRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<AddrParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let strategy = state.addr_cache(Version::ONE, &path.addr, false);
|
||||
@@ -96,6 +97,7 @@ impl AddrRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<AddrParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let hash = state.sync(|q| q.addr_mempool_hash(&path.addr));
|
||||
@@ -118,6 +120,7 @@ impl AddrRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<AddrParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let strategy = state.addr_cache(Version::ONE, &path.addr, false);
|
||||
@@ -140,6 +143,7 @@ impl AddrRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<ValidateAddrParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, move |_q| Ok(AddrValidation::from_addr(&path.addr))).await
|
||||
|
||||
@@ -11,7 +11,9 @@ use brk_types::{
|
||||
use crate::{
|
||||
AppState, CacheStrategy,
|
||||
extended::TransformResponseExtended,
|
||||
params::{BlockHashParam, BlockHashStartIndex, BlockHashTxIndex, HeightParam, TimestampParam},
|
||||
params::{
|
||||
BlockHashParam, BlockHashStartIndex, BlockHashTxIndex, Empty, HeightParam, TimestampParam,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait BlockRoutes {
|
||||
@@ -26,7 +28,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_json(&headers, strategy, &uri, move |q| q.block(&path.hash)).await
|
||||
},
|
||||
@@ -48,7 +50,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/block/{hash}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<BlockHashParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<BlockHashParam>, _: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_json(&headers, strategy, &uri, move |q| {
|
||||
let height = q.height_by_hash(&path.hash)?;
|
||||
@@ -71,7 +73,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/block/{hash}/header",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<BlockHashParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<BlockHashParam>, _: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_text(&headers, strategy, &uri, move |q| q.block_header_hex(&path.hash)).await
|
||||
},
|
||||
@@ -94,7 +96,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<HeightParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
state.cached_text(&headers, state.height_cache(Version::ONE, path.height), &uri, move |q| q.block_hash_by_height(path.height).map(|h| h.to_string())).await
|
||||
},
|
||||
|op| {
|
||||
@@ -118,7 +120,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<TimestampParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.timestamp_cache(Version::ONE, path.timestamp), &uri, move |q| q.block_by_timestamp(path.timestamp)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -140,7 +142,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_bytes(&headers, strategy, &uri, move |q| q.block_raw(&path.hash)).await
|
||||
},
|
||||
@@ -165,7 +167,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.block_status_cache(Version::ONE, &path.hash), &uri, move |q| q.block_status(&path.hash)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -186,7 +188,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/blocks/tip/height",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_text(&headers, CacheStrategy::Tip, &uri, |q| Ok(q.indexed_height().to_string())).await
|
||||
},
|
||||
|op| {
|
||||
@@ -203,7 +205,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/blocks/tip/hash",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_text(&headers, CacheStrategy::Tip, &uri, |q| Ok(q.tip_blockhash().to_string())).await
|
||||
},
|
||||
|op| {
|
||||
@@ -223,7 +225,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashTxIndex>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_text(&headers, strategy, &uri, move |q| q.block_txid_at_index(&path.hash, path.index).map(|t| t.to_string())).await
|
||||
},
|
||||
@@ -248,7 +250,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_json(&headers, strategy, &uri, move |q| q.block_txids(&path.hash)).await
|
||||
},
|
||||
@@ -273,7 +275,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_json(&headers, strategy, &uri, move |q| q.block_txs(&path.hash, TxIndex::default())).await
|
||||
},
|
||||
@@ -299,7 +301,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<BlockHashStartIndex>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_cache(Version::ONE, &path.hash);
|
||||
state.cached_json(&headers, strategy, &uri, move |q| q.block_txs(&path.hash, path.start_index)).await
|
||||
},
|
||||
@@ -322,7 +324,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/blocks",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.blocks(None))
|
||||
.await
|
||||
@@ -344,7 +346,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<HeightParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.height_cache(Version::ONE, path.height), &uri, move |q| q.blocks(Some(path.height))).await
|
||||
},
|
||||
|op| {
|
||||
@@ -364,7 +366,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/blocks",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.blocks_v1(None))
|
||||
.await
|
||||
@@ -386,7 +388,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<HeightParam>,
|
||||
State(state): State<AppState>| {
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.height_cache(Version::ONE, path.height), &uri, move |q| q.blocks_v1(Some(path.height))).await
|
||||
},
|
||||
|op| {
|
||||
|
||||
@@ -5,7 +5,7 @@ use axum::{
|
||||
};
|
||||
use brk_types::{MempoolBlock, RecommendedFees};
|
||||
|
||||
use crate::{AppState, extended::TransformResponseExtended};
|
||||
use crate::{AppState, extended::TransformResponseExtended, params::Empty};
|
||||
|
||||
pub trait FeesRoutes {
|
||||
fn add_fees_routes(self) -> Self;
|
||||
@@ -16,7 +16,7 @@ impl FeesRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/api/v1/fees/mempool-blocks",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| {
|
||||
q.mempool_blocks()
|
||||
@@ -37,7 +37,7 @@ impl FeesRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/fees/recommended",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| {
|
||||
q.recommended_fees()
|
||||
@@ -58,7 +58,7 @@ impl FeesRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/fees/precise",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| {
|
||||
q.recommended_fees()
|
||||
|
||||
@@ -6,7 +6,9 @@ use axum::{
|
||||
use brk_types::{DifficultyAdjustment, HistoricalPrice, Prices, Timestamp, Version};
|
||||
|
||||
use crate::{
|
||||
AppState, CacheStrategy, extended::TransformResponseExtended, params::OptionalTimestampParam,
|
||||
AppState, CacheStrategy,
|
||||
extended::TransformResponseExtended,
|
||||
params::{Empty, OptionalTimestampParam},
|
||||
};
|
||||
|
||||
pub trait GeneralRoutes {
|
||||
@@ -18,7 +20,7 @@ impl GeneralRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/api/v1/difficulty-adjustment",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, |q| {
|
||||
q.difficulty_adjustment()
|
||||
@@ -39,7 +41,7 @@ impl GeneralRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/prices",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| {
|
||||
Ok(Prices {
|
||||
|
||||
@@ -5,7 +5,7 @@ use axum::{
|
||||
};
|
||||
use brk_types::{Dollars, MempoolInfo, MempoolRecentTx, Txid};
|
||||
|
||||
use crate::{AppState, extended::TransformResponseExtended};
|
||||
use crate::{AppState, extended::TransformResponseExtended, params::Empty};
|
||||
|
||||
pub trait MempoolRoutes {
|
||||
fn add_mempool_routes(self) -> Self;
|
||||
@@ -16,7 +16,7 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/api/mempool",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| q.mempool_info())
|
||||
.await
|
||||
@@ -35,7 +35,7 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/mempool/txids",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| q.mempool_txids())
|
||||
.await
|
||||
@@ -54,7 +54,7 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/mempool/recent",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| q.mempool_recent())
|
||||
.await
|
||||
@@ -73,7 +73,7 @@ impl MempoolRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/mempool/price",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, state.mempool_cache(), &uri, |q| q.live_price())
|
||||
.await
|
||||
|
||||
@@ -17,7 +17,7 @@ use brk_types::{
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{CacheStrategy, Error, extended::TransformResponseExtended};
|
||||
use crate::{CacheStrategy, Error, extended::TransformResponseExtended, params::Empty};
|
||||
|
||||
use super::AppState;
|
||||
use super::series_legacy;
|
||||
@@ -46,7 +46,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/metrics",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_catalog().clone())).await
|
||||
},
|
||||
|op| op
|
||||
@@ -68,6 +68,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_count())).await
|
||||
@@ -91,6 +92,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.indexes().to_vec())).await
|
||||
@@ -186,6 +188,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<LegacySeriesParam>
|
||||
| {
|
||||
@@ -273,6 +276,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<LegacySeriesWithIndex>| {
|
||||
state
|
||||
@@ -299,6 +303,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<LegacySeriesWithIndex>| {
|
||||
state
|
||||
@@ -325,6 +330,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<LegacySeriesWithIndex>| {
|
||||
state
|
||||
|
||||
@@ -14,7 +14,7 @@ use brk_types::{
|
||||
use crate::{
|
||||
AppState, CacheStrategy,
|
||||
extended::TransformResponseExtended,
|
||||
params::{BlockCountParam, PoolSlugAndHeightParam, PoolSlugParam, TimePeriodParam},
|
||||
params::{BlockCountParam, Empty, PoolSlugAndHeightParam, PoolSlugParam, TimePeriodParam},
|
||||
};
|
||||
|
||||
pub trait MiningRoutes {
|
||||
@@ -30,7 +30,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pools",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
// Pool list is compiled-in, only changes on deploy
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.all_pools())).await
|
||||
},
|
||||
@@ -48,7 +48,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pools/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.mining_pools(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -66,7 +66,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pool/{slug}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.pool_detail(path.slug)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -84,7 +84,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/hashrate/pools",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, |q| q.pools_hashrate(None)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -101,7 +101,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/hashrate/pools/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.pools_hashrate(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
@@ -119,7 +119,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pool/{slug}/hashrate",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.pool_hashrate(path.slug)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -137,7 +137,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pool/{slug}/blocks",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.pool_blocks(path.slug, None)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -155,7 +155,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pool/{slug}/blocks/{height}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(PoolSlugAndHeightParam {slug, height}): Path<PoolSlugAndHeightParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(PoolSlugAndHeightParam {slug, height}): Path<PoolSlugAndHeightParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.height_cache(Version::ONE, height), &uri, move |q| q.pool_blocks(slug, Some(height))).await
|
||||
},
|
||||
|op| {
|
||||
@@ -173,7 +173,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/hashrate",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, |q| q.hashrate(None)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -190,7 +190,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/hashrate/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.hashrate(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
@@ -208,7 +208,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/difficulty-adjustments",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, |q| q.difficulty_adjustments(None)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -225,7 +225,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/difficulty-adjustments/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.difficulty_adjustments(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
@@ -243,7 +243,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/reward-stats/{block_count}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<BlockCountParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<BlockCountParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.reward_stats(path.block_count)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -261,7 +261,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/fees/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.block_fees(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -279,7 +279,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/rewards/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.block_rewards(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -297,7 +297,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/fee-rates/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.block_fee_rates(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -315,7 +315,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/sizes-weights/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| q.block_sizes_weights(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
|
||||
@@ -25,7 +25,7 @@ use brk_types::{
|
||||
use crate::{
|
||||
AppState, CacheParams, CacheStrategy, Result,
|
||||
extended::{HeaderMapExtended, TransformResponseExtended},
|
||||
params::SeriesParam,
|
||||
params::{Empty, SeriesParam},
|
||||
};
|
||||
|
||||
/// Shared response pipeline for every series endpoint.
|
||||
@@ -42,9 +42,7 @@ pub(super) async fn serve(
|
||||
to_bytes: impl FnOnce(&BrkQuery, ResolvedQuery) -> BrkResult<Bytes> + Send + 'static,
|
||||
) -> Result<Response> {
|
||||
let max_weight = state.max_weight_for(&addr);
|
||||
let resolved = state
|
||||
.run(move |q| q.resolve(params, max_weight))
|
||||
.await?;
|
||||
let resolved = state.run(move |q| q.resolve(params, max_weight)).await?;
|
||||
|
||||
let format = resolved.format();
|
||||
let csv_filename = resolved.csv_filename();
|
||||
@@ -114,7 +112,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/api/series",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_catalog().clone())).await
|
||||
},
|
||||
|op| op
|
||||
@@ -135,6 +133,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_count())).await
|
||||
@@ -154,6 +153,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.indexes().to_vec())).await
|
||||
@@ -216,6 +216,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<SeriesParam>
|
||||
| {
|
||||
@@ -309,6 +310,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<SeriesNameWithIndex>| {
|
||||
state
|
||||
@@ -334,6 +336,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<SeriesNameWithIndex>| {
|
||||
state
|
||||
@@ -357,6 +360,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
_: Empty,
|
||||
State(state): State<AppState>,
|
||||
Path(path): Path<SeriesNameWithIndex>| {
|
||||
state
|
||||
|
||||
@@ -29,6 +29,7 @@ use vecdb::ReadableOptionVec;
|
||||
use crate::{
|
||||
AppState, CacheStrategy, Result,
|
||||
extended::{HeaderMapExtended, TransformResponseExtended},
|
||||
params::Empty,
|
||||
};
|
||||
|
||||
pub const SUNSET: &str = "2027-01-01T00:00:00Z";
|
||||
@@ -43,7 +44,8 @@ pub async fn handler(
|
||||
Query(params): Query<SeriesSelection>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Response> {
|
||||
let mut response = super::series::serve(state, uri, headers, addr, params, legacy_bytes).await?;
|
||||
let mut response =
|
||||
super::series::serve(state, uri, headers, addr, params, legacy_bytes).await?;
|
||||
if response.status() == StatusCode::OK {
|
||||
response.headers_mut().insert_deprecation(SUNSET);
|
||||
}
|
||||
@@ -151,7 +153,7 @@ impl ApiSeriesLegacyRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/api/series/cost-basis",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| q.urpd_cohorts())
|
||||
.await
|
||||
@@ -177,6 +179,7 @@ impl ApiSeriesLegacyRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(params): Path<CostBasisCohortParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| {
|
||||
|
||||
@@ -7,7 +7,7 @@ use axum::{
|
||||
};
|
||||
use brk_types::{DiskUsage, Health, SyncStatus};
|
||||
|
||||
use crate::{CacheStrategy, VERSION, extended::TransformResponseExtended};
|
||||
use crate::{CacheStrategy, VERSION, extended::TransformResponseExtended, params::Empty};
|
||||
|
||||
use super::AppState;
|
||||
|
||||
@@ -20,7 +20,7 @@ impl ServerRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/health",
|
||||
get_with(
|
||||
async |State(state): State<AppState>| -> axum::Json<Health> {
|
||||
async |_: Empty, State(state): State<AppState>| -> axum::Json<Health> {
|
||||
let uptime = state.started_instant.elapsed();
|
||||
let started_at = state.started_at.to_string();
|
||||
let sync = state
|
||||
@@ -55,7 +55,7 @@ impl ServerRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/version",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Deploy, &uri, |_| {
|
||||
Ok(env!("CARGO_PKG_VERSION"))
|
||||
@@ -75,7 +75,7 @@ impl ServerRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/server/sync",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| {
|
||||
let tip_height = q.client().get_last_height()?;
|
||||
@@ -99,7 +99,7 @@ impl ServerRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/server/disk",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
let brk_path = state.data_path.clone();
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| {
|
||||
|
||||
@@ -5,15 +5,16 @@ use aide::axum::{
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
http::{HeaderMap, Uri},
|
||||
response::Response,
|
||||
};
|
||||
use brk_types::{
|
||||
CpfpInfo, MerkleProof, RbfResponse, Transaction, TxOutspend, TxStatus, Txid, Version,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
AppState, CacheStrategy,
|
||||
AppState, CacheStrategy, Error, Result,
|
||||
extended::TransformResponseExtended,
|
||||
params::{TxIndexParam, TxidParam, TxidVout, TxidsParam},
|
||||
params::{Empty, TxIndexParam, TxidParam, TxidVout, TxidsParam},
|
||||
};
|
||||
|
||||
pub trait TxRoutes {
|
||||
@@ -26,7 +27,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/tx-index/{index}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxIndexParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxIndexParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_text(&headers, CacheStrategy::Immutable(Version::ONE), &uri, move |q| q.txid_by_index(param.index).map(|t| t.to_string())).await
|
||||
},
|
||||
|op| op
|
||||
@@ -44,7 +45,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/cpfp/{txid}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.cpfp(¶m.txid)).await
|
||||
},
|
||||
|op| op
|
||||
@@ -62,7 +63,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/tx/{txid}/rbf",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.mempool_cache(), &uri, move |q| q.tx_rbf(¶m.txid)).await
|
||||
},
|
||||
|op| op
|
||||
@@ -84,6 +85,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(param): Path<TxidParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.transaction(¶m.txid)).await
|
||||
@@ -109,6 +111,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(param): Path<TxidParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_text(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.transaction_hex(¶m.txid)).await
|
||||
@@ -130,7 +133,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/tx/{txid}/merkleblock-proof",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_text(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.merkleblock_proof(¶m.txid)).await
|
||||
},
|
||||
|op| op
|
||||
@@ -148,7 +151,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/tx/{txid}/merkle-proof",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.merkle_proof(¶m.txid)).await
|
||||
},
|
||||
|op| op
|
||||
@@ -170,6 +173,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<TxidVout>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let v = Version::ONE;
|
||||
@@ -204,6 +208,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(param): Path<TxidParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let v = Version::ONE;
|
||||
@@ -232,7 +237,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/tx/{txid}/raw",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, Path(param): Path<TxidParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.cached_bytes(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.transaction_raw(¶m.txid)).await
|
||||
},
|
||||
|op| op
|
||||
@@ -254,6 +259,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(param): Path<TxidParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, state.tx_cache(Version::ONE, ¶m.txid), &uri, move |q| q.transaction_status(¶m.txid)).await
|
||||
@@ -275,9 +281,10 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/transaction-times",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
let params = TxidsParam::from_query(uri.query().unwrap_or(""));
|
||||
state.cached_json(&headers, state.mempool_cache(), &uri, move |q| q.transaction_times(¶ms.txids)).await
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| -> Result<Response> {
|
||||
let params = TxidsParam::from_query(uri.query().unwrap_or(""))
|
||||
.map_err(Error::bad_request)?;
|
||||
Ok(state.cached_json(&headers, state.mempool_cache(), &uri, move |q| q.transaction_times(¶ms.txids)).await)
|
||||
},
|
||||
|op| op
|
||||
.id("get_transaction_times")
|
||||
@@ -292,12 +299,12 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/tx",
|
||||
post_with(
|
||||
async |State(state): State<AppState>, body: String| {
|
||||
async |_: Empty, State(state): State<AppState>, body: String| {
|
||||
let hex = body.trim().to_string();
|
||||
state.run(move |q| q.broadcast_transaction(&hex))
|
||||
.await
|
||||
.map(|txid| txid.to_string())
|
||||
.map_err(crate::Error::from)
|
||||
.map_err(Error::from)
|
||||
},
|
||||
|op| {
|
||||
op.id("post_tx")
|
||||
|
||||
@@ -8,7 +8,7 @@ use brk_types::{Cohort, Date, Urpd, Version};
|
||||
use crate::{
|
||||
CacheStrategy,
|
||||
extended::TransformResponseExtended,
|
||||
params::{UrpdCohortParam, UrpdParams, UrpdQuery},
|
||||
params::{Empty, UrpdCohortParam, UrpdParams, UrpdQuery},
|
||||
};
|
||||
|
||||
use super::AppState;
|
||||
@@ -22,7 +22,7 @@ impl ApiUrpdRoutes for ApiRouter<AppState> {
|
||||
self.api_route(
|
||||
"/api/urpd",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, State(state): State<AppState>| {
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Deploy, &uri, |q| q.urpd_cohorts())
|
||||
.await
|
||||
@@ -47,6 +47,7 @@ impl ApiUrpdRoutes for ApiRouter<AppState> {
|
||||
async |uri: Uri,
|
||||
headers: HeaderMap,
|
||||
Path(params): Path<UrpdCohortParam>,
|
||||
_: Empty,
|
||||
State(state): State<AppState>| {
|
||||
state
|
||||
.cached_json(&headers, CacheStrategy::Tip, &uri, move |q| {
|
||||
|
||||
Vendored
+1
-5
@@ -52,9 +52,5 @@ pub(crate) fn init(mode: CdnCacheMode) {
|
||||
/// Cached-tier directive for stable responses. Defaults to `Live` if [`init`]
|
||||
/// was never called (tests, library use without a `Server`).
|
||||
pub(super) fn cdn_cached() -> &'static str {
|
||||
CDN_CACHE_MODE
|
||||
.get()
|
||||
.copied()
|
||||
.unwrap_or_default()
|
||||
.as_str()
|
||||
CDN_CACHE_MODE.get().copied().unwrap_or_default().as_str()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
use aide::OperationInput;
|
||||
use axum::{extract::FromRequestParts, http::request::Parts};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
/// Extractor that rejects requests carrying any query string.
|
||||
/// Used on path-only endpoints to prevent cache-busting via injected
|
||||
/// query params (the cache key includes the URI).
|
||||
pub struct Empty;
|
||||
|
||||
impl<S> FromRequestParts<S> for Empty
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Error;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
match parts.uri.query() {
|
||||
Some(q) if !q.is_empty() => Err(Error::bad_request(format!(
|
||||
"this endpoint does not accept query parameters (got `?{q}`)"
|
||||
))),
|
||||
_ => Ok(Empty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OperationInput for Empty {}
|
||||
@@ -4,6 +4,7 @@ mod block_count_param;
|
||||
mod blockhash_param;
|
||||
mod blockhash_start_index;
|
||||
mod blockhash_tx_index;
|
||||
mod empty;
|
||||
mod height_param;
|
||||
mod pool_slug_param;
|
||||
mod series_param;
|
||||
@@ -22,6 +23,7 @@ pub use block_count_param::*;
|
||||
pub use blockhash_param::*;
|
||||
pub use blockhash_start_index::*;
|
||||
pub use blockhash_tx_index::*;
|
||||
pub use empty::*;
|
||||
pub use height_param::*;
|
||||
pub use pool_slug_param::*;
|
||||
pub use series_param::*;
|
||||
|
||||
@@ -13,19 +13,25 @@ pub struct TxidsParam {
|
||||
|
||||
impl TxidsParam {
|
||||
/// Parsed manually from URI since serde_urlencoded doesn't support repeated keys.
|
||||
pub fn from_query(query: &str) -> Self {
|
||||
Self {
|
||||
txids: query
|
||||
.split('&')
|
||||
.filter_map(|pair| {
|
||||
let (key, val) = pair.split_once('=')?;
|
||||
if key == "txId[]" || key == "txId%5B%5D" {
|
||||
Txid::from_str(val).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
/// Rejects unknown keys to prevent cache-busting via injected query params.
|
||||
pub fn from_query(query: &str) -> Result<Self, String> {
|
||||
if query.is_empty() {
|
||||
return Ok(Self { txids: Vec::new() });
|
||||
}
|
||||
let mut txids = Vec::new();
|
||||
for pair in query.split('&') {
|
||||
let (key, val) = pair.split_once('=').ok_or_else(|| {
|
||||
format!("malformed query parameter `{pair}`, expected `txId[]=<txid>`")
|
||||
})?;
|
||||
if key == "txId[]" || key == "txId%5B%5D" {
|
||||
let txid = Txid::from_str(val).map_err(|e| format!("invalid txid `{val}`: {e}"))?;
|
||||
txids.push(txid);
|
||||
} else {
|
||||
return Err(format!(
|
||||
"unknown query parameter `{key}`, expected `txId[]`"
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(Self { txids })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,10 +197,9 @@ impl AppState {
|
||||
let encoding = ContentEncoding::negotiate(headers);
|
||||
let cache_key = format!("{}-{}-{}", uri, params.etag, encoding.as_str());
|
||||
let result = self
|
||||
.get_or_insert(
|
||||
&cache_key,
|
||||
async move { self.run(move |q| f(q, encoding)).await },
|
||||
)
|
||||
.get_or_insert(&cache_key, async move {
|
||||
self.run(move |q| f(q, encoding)).await
|
||||
})
|
||||
.await;
|
||||
|
||||
match result {
|
||||
@@ -296,7 +295,10 @@ impl AppState {
|
||||
uri,
|
||||
params,
|
||||
|h| {
|
||||
h.insert(header::CONTENT_TYPE, HeaderValue::from_static("application/json"));
|
||||
h.insert(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("application/json"),
|
||||
);
|
||||
},
|
||||
move |_q, enc| {
|
||||
let value = value_result?;
|
||||
|
||||
Reference in New Issue
Block a user