Skip to content

Commit b5d8aca

Browse files
committed
spender routes with axum are ready
1 parent 752ca76 commit b5d8aca

File tree

2 files changed

+167
-1
lines changed

2 files changed

+167
-1
lines changed

sentry/src/routes/channel.rs

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
Application, Auth,
2020
};
2121
use adapter::{client::Locked, Adapter, Dummy};
22-
use axum::{Extension, Json};
22+
use axum::{Extension, Json, extract::Path};
2323
use futures::future::try_join_all;
2424
use hyper::{Body, Request, Response};
2525
use primitives::{
@@ -268,6 +268,57 @@ pub async fn get_spender_limits<C: Locked + 'static>(
268268
Ok(success_response(serde_json::to_string(&res)?))
269269
}
270270

271+
pub async fn get_spender_limits_axum<C: Locked + 'static>(
272+
Path(params): Path<HashMap<String, String>>,
273+
Extension(app): Extension<Arc<Application<C>>>,
274+
Extension(channel_context): Extension<ChainOf<Channel>>,
275+
) -> Result<Json<SpenderResponse>, ResponseError> {
276+
let channel = &channel_context.context;
277+
278+
let spender = params.get("addr").ok_or(ResponseError::BadRequest("Invalid spender address".to_string()))?;
279+
let spender = Address::from_str(spender)?;
280+
281+
let latest_spendable = fetch_spendable(app.pool.clone(), &spender, &channel.id()).await?;
282+
283+
let latest_spendable = match latest_spendable {
284+
Some(spendable) => spendable,
285+
None => {
286+
create_or_update_spendable_document(
287+
&app.adapter,
288+
app.pool.clone(),
289+
&channel_context,
290+
spender,
291+
)
292+
.await?
293+
}
294+
};
295+
296+
let new_state = match get_corresponding_new_state(&app.pool, &app.logger, channel).await? {
297+
Some(new_state) => new_state,
298+
None => return Ok(Json(SpenderResponse {
299+
spender: Spender {
300+
total_deposited: latest_spendable.deposit.total,
301+
total_spent: None,
302+
},
303+
})),
304+
};
305+
306+
let total_spent = new_state
307+
.balances
308+
.spenders
309+
.get(&spender)
310+
.map(|spent| spent.to_owned());
311+
312+
// returned output
313+
let res = SpenderResponse {
314+
spender: Spender {
315+
total_deposited: latest_spendable.deposit.total,
316+
total_spent,
317+
},
318+
};
319+
Ok(Json(res))
320+
}
321+
271322
/// GET `/v5/channel/0xXXX.../spender/all` request.
272323
///
273324
/// Response: [`AllSpendersResponse`]
@@ -325,6 +376,56 @@ pub async fn get_all_spender_limits<C: Locked + 'static>(
325376
Ok(success_response(serde_json::to_string(&res)?))
326377
}
327378

379+
pub async fn get_all_spender_limits_axum<C: Locked + 'static>(
380+
Extension(app): Extension<Arc<Application<C>>>,
381+
Extension(channel_context): Extension<ChainOf<Channel>>,
382+
Qs(query): Qs<AllSpendersQuery>
383+
) -> Result<Json<AllSpendersResponse>, ResponseError> {
384+
let channel = channel_context.context;
385+
386+
let limit = app.config.spendable_find_limit;
387+
let skip = query
388+
.page
389+
.checked_mul(limit.into())
390+
.ok_or_else(|| ResponseError::FailedValidation("Page and/or limit is too large".into()))?;
391+
392+
let new_state = get_corresponding_new_state(&app.pool, &app.logger, &channel).await?;
393+
394+
let mut all_spender_limits: HashMap<Address, Spender> = HashMap::new();
395+
396+
let (all_spendables, pagination) =
397+
get_all_spendables_for_channel(app.pool.clone(), &channel.id(), skip, limit.into()).await?;
398+
399+
// Using for loop to avoid async closures
400+
for spendable in all_spendables {
401+
let spender = spendable.spender;
402+
let total_spent = match new_state {
403+
Some(ref new_state) => new_state.balances.spenders.get(&spender).map(|balance| {
404+
spendable
405+
.deposit
406+
.total
407+
.checked_sub(balance)
408+
.unwrap_or_default()
409+
}),
410+
None => None,
411+
};
412+
413+
let spender_info = Spender {
414+
total_deposited: spendable.deposit.total,
415+
total_spent,
416+
};
417+
418+
all_spender_limits.insert(spender, spender_info);
419+
}
420+
421+
let res = AllSpendersResponse {
422+
spenders: all_spender_limits,
423+
pagination,
424+
};
425+
426+
Ok(Json(res))
427+
}
428+
328429
/// POST `/v5/channel/0xXXX.../spender/0xXXX...` request
329430
///
330431
/// Internally to make the validator worker add a spender leaf in `NewState` we'll just update `Accounting`
@@ -384,6 +485,63 @@ pub async fn add_spender_leaf<C: Locked + 'static>(
384485
Ok(success_response(serde_json::to_string(&res)?))
385486
}
386487

488+
/// POST `/v5/channel/0xXXX.../spender/0xXXX...` request
489+
///
490+
/// Internally to make the validator worker add a spender leaf in `NewState` we'll just update `Accounting`
491+
pub async fn add_spender_leaf_axum<C: Locked + 'static>(
492+
Path(params): Path<HashMap<String, String>>,
493+
Extension(app): Extension<Arc<Application<C>>>,
494+
Extension(channel): Extension<ChainOf<Channel>>,
495+
) -> Result<Json<SpenderResponse>, ResponseError> {
496+
let spender = params.get("addr").ok_or(ResponseError::BadRequest("Invalid spender address".to_string()))?;
497+
let spender = Address::from_str(spender)?;
498+
499+
update_accounting(
500+
app.pool.clone(),
501+
channel.context.id(),
502+
spender,
503+
Side::Spender,
504+
UnifiedNum::from_u64(0),
505+
)
506+
.await?;
507+
508+
let latest_spendable =
509+
fetch_spendable(app.pool.clone(), &spender, &channel.context.id()).await?;
510+
511+
let latest_spendable = match latest_spendable {
512+
Some(spendable) => spendable,
513+
None => {
514+
create_or_update_spendable_document(&app.adapter, app.pool.clone(), &channel, spender)
515+
.await?
516+
}
517+
};
518+
519+
let new_state =
520+
match get_corresponding_new_state(&app.pool, &app.logger, &channel.context).await? {
521+
Some(new_state) => new_state,
522+
None => return Ok(Json(SpenderResponse {
523+
spender: Spender {
524+
total_deposited: latest_spendable.deposit.total,
525+
total_spent: None,
526+
},
527+
})),
528+
};
529+
530+
let total_spent = new_state
531+
.balances
532+
.spenders
533+
.get(&spender)
534+
.map(|spent| spent.to_owned());
535+
536+
let res = SpenderResponse {
537+
spender: Spender {
538+
total_deposited: latest_spendable.deposit.total,
539+
total_spent,
540+
},
541+
};
542+
Ok(Json(res))
543+
}
544+
387545
async fn get_corresponding_new_state(
388546
pool: &DbPool,
389547
logger: &Logger,

sentry/src/routes/routers.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::{
2929
channel::{
3030
add_spender_leaf, channel_dummy_deposit, channel_list, channel_payout,
3131
get_accounting_for_channel, get_all_spender_limits, get_spender_limits, last_approved,
32+
get_spender_limits_axum, get_all_spender_limits_axum, add_spender_leaf_axum,
3233
validator_message::{
3334
create_validator_messages, extract_params, list_validator_messages,
3435
},
@@ -133,12 +134,19 @@ async fn if_dummy_adapter<C: Locked + 'static, B>(
133134
}
134135

135136
pub fn channels_router_axum<C: Locked + 'static>() -> Router {
137+
let spender_routes = Router::new()
138+
.route(
139+
"/:addr", get(get_spender_limits_axum::<C>).post(add_spender_leaf_axum::<C>).route_layer(middleware::from_fn(authentication_required::<C, _>))
140+
)
141+
.route("/all", get(get_all_spender_limits_axum::<C>).route_layer(middleware::from_fn(authentication_required::<C, _>)));
142+
136143
let channel_routes = Router::new()
137144
.route(
138145
"/pay",
139146
post(channel_payout_axum::<C>)
140147
.route_layer(middleware::from_fn(authentication_required::<C, _>)),
141148
)
149+
.nest("/spender", spender_routes)
142150
.layer(
143151
// keeps the order from top to bottom!
144152
ServiceBuilder::new()

0 commit comments

Comments
 (0)