Files
nym/nym-node-status-api/src/http/api/services/mod.rs
T
Dinko Zdravac 09b68a8204 Cherry pick NS API from develop (#5074)
* Revert "NS API with directory v2 (#5068)"

This reverts commit cf4fe5f875.

* Merge pull request #5050 from nymtech/dz-node-status-api

Node Status API

* Ns agent workflow (#5055)

* feat: add dockerfile

* add github workflow for node status agent

---------

Co-authored-by: Fran Arbanas <arbanasfran@gmail.com>

* NS API with directory v2 (#5058)

* Use unstable explorer client

* Clean up stale testruns & logging
- log gw identity key
- better agent testrun logging
- log responses
- change response code for agents

* Better logging on agent

* Testrun stores gw identity key instead of gw pk

* Agent 0.1.3

* Agent 0.1.4

* Sqlx offline query data + clippy

* Compatible with directory v2

* Point to internal deps + rebase + v0.1.5

* self described field not null

* Fix build.rs typo

* Fix clippy

---------

Co-authored-by: Fran Arbanas <arbanasfran@gmail.com>
2024-11-01 01:24:41 +01:00

135 lines
3.6 KiB
Rust

use crate::http::{
error::{HttpError, HttpResult},
models::Service,
state::AppState,
PagedResult, Pagination,
};
use axum::{
extract::{Query, State},
Json, Router,
};
use json_path::{ParseJsonPaths, ParsedDetails};
use tracing::instrument;
mod json_path;
pub(crate) fn routes() -> Router<AppState> {
Router::new().route("/", axum::routing::get(mixnodes))
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::IntoParams)]
#[into_params(parameter_in = Query)]
pub(crate) struct ServicesQueryParams {
size: Option<usize>,
page: Option<usize>,
wss: Option<bool>,
hostname: Option<bool>,
entry: Option<bool>,
}
#[utoipa::path(
tag = "Services",
get,
params(
ServicesQueryParams,
),
path = "/v2/services",
responses(
(status = 200, body = PagedService)
)
)]
#[instrument(level = tracing::Level::DEBUG, skip(state))]
async fn mixnodes(
Query(ServicesQueryParams {
size,
page,
wss,
hostname,
entry,
}): Query<ServicesQueryParams>,
State(state): State<AppState>,
) -> HttpResult<Json<PagedResult<Service>>> {
let db = state.db_pool();
let cache = state.cache();
let show_only_wss = wss.unwrap_or(false);
let show_only_with_hostname = hostname.unwrap_or(false);
let show_entry_gateways_only = entry.unwrap_or(false);
let paths = ParseJsonPaths::new().map_err(|e| {
tracing::error!("Invalidly configured ParseJsonPaths: {e}");
HttpError::internal()
})?;
let res = cache.get_gateway_list(db).await;
let res: Vec<Service> = res
.iter()
.map(|g| {
let details = ParsedDetails::new(&paths, g);
let s = Service {
gateway_identity_key: g.gateway_identity_key.clone(),
ip_address: details.ip_address,
service_provider_client_id: details.service_provider_client_id,
hostname: details.hostname,
last_successful_ping_utc: g.last_testrun_utc.clone(),
last_updated_utc: g.last_updated_utc.clone(),
// routing_score: g.routing_score,
routing_score: 1f32,
mixnet_websockets: g
.self_described
.clone()
.and_then(|s| s.get("mixnet_websockets").cloned()),
};
let f = ServiceFilter::new(&s);
(s, f)
})
.filter(|(_, f)| {
let mut keep = f.has_network_requester_sp;
if show_entry_gateways_only {
keep = true;
}
if show_only_wss {
keep &= f.has_wss;
}
if show_only_with_hostname {
keep &= f.has_hostname;
}
keep
})
.map(|(s, _)| s)
.collect();
Ok(Json(PagedResult::paginate(Pagination { size, page }, res)))
}
struct ServiceFilter {
has_wss: bool,
has_network_requester_sp: bool,
has_hostname: bool,
}
impl ServiceFilter {
fn new(s: &Service) -> Self {
let has_wss = match &s.mixnet_websockets {
Some(v) => v.get("wss_port").map(|v2| !v2.is_null()).unwrap_or(false),
None => false,
};
let has_hostname = s.hostname.is_some();
let has_network_requester_sp = match &s.service_provider_client_id {
Some(v) => !v.is_empty(),
None => false,
};
ServiceFilter {
has_wss,
has_hostname,
has_network_requester_sp,
}
}
}