ns_indexer/api/
service.rs1use axum::{
2 extract::{Query, State},
3 Extension,
4};
5use std::sync::Arc;
6use validator::Validate;
7
8use ns_axum_web::{
9 context::ReqContext,
10 erring::{HTTPError, SuccessResponse},
11 object::PackObject,
12};
13use ns_protocol::state::ServiceState;
14
15use crate::api::{IndexerAPI, QueryName};
16use crate::db;
17
18pub struct ServiceAPI;
19
20impl ServiceAPI {
21 pub async fn get(
22 State(app): State<Arc<IndexerAPI>>,
23 Extension(ctx): Extension<Arc<ReqContext>>,
24 to: PackObject<()>,
25 input: Query<QueryName>,
26 ) -> Result<PackObject<SuccessResponse<ServiceState>>, HTTPError> {
27 input.validate()?;
28 if input.code.is_none() {
29 return Err(HTTPError::new(400, "service code is required".to_string()));
30 }
31
32 let name = input.name.clone();
33 let code = input.code.unwrap();
34 ctx.set_kvs(vec![
35 ("action", "get_service_state".into()),
36 ("name", name.clone().into()),
37 ("code", code.into()),
38 ])
39 .await;
40
41 let mut service_state = db::ServiceState::with_pk(name, code);
42 service_state.get_one(&app.scylla, vec![]).await?;
43
44 Ok(to.with(SuccessResponse::new(service_state.to_index()?)))
45 }
46
47 pub async fn get_best(
48 State(app): State<Arc<IndexerAPI>>,
49 Extension(ctx): Extension<Arc<ReqContext>>,
50 to: PackObject<()>,
51 input: Query<QueryName>,
52 ) -> Result<PackObject<SuccessResponse<ServiceState>>, HTTPError> {
53 input.validate()?;
54 if input.code.is_none() {
55 return Err(HTTPError::new(400, "service code is required".to_string()));
56 }
57
58 let name = input.name.clone();
59 let code = input.code.unwrap() as u64;
60 ctx.set_kvs(vec![
61 ("action", "get_best_service_state".into()),
62 ("name", name.clone().into()),
63 ("code", code.into()),
64 ])
65 .await;
66
67 {
68 let best_names_state = app.state.confirming_names.read().await;
69 if let Some(states) = best_names_state.get(&name) {
70 for ss in states.iter().rev() {
71 if ss.1.code == code {
72 return Ok(to.with(SuccessResponse::new(ss.1.clone())));
73 }
74 }
75 }
76 }
77
78 Err(HTTPError::new(404, "not found".to_string()))
79 }
80
81 pub async fn list_by_name(
82 State(app): State<Arc<IndexerAPI>>,
83 Extension(ctx): Extension<Arc<ReqContext>>,
84 to: PackObject<()>,
85 input: Query<QueryName>,
86 ) -> Result<PackObject<SuccessResponse<Vec<ServiceState>>>, HTTPError> {
87 input.validate()?;
88
89 let name = input.name.clone();
90 ctx.set_kvs(vec![
91 ("action", "list_service_states_by_name".into()),
92 ("name", name.clone().into()),
93 ])
94 .await;
95
96 let res = db::ServiceState::list_by_name(&app.scylla, &name, vec![]).await?;
97 let mut service_states: Vec<ServiceState> = Vec::with_capacity(res.len());
98 for i in res {
99 service_states.push(i.to_index()?);
100 }
101 Ok(to.with(SuccessResponse::new(service_states)))
102 }
103}