hacker-challenge/src/http_server.rs
Valentyn Faychuk fc933c0647
connections refactoring
Signed-off-by: Valentyn Faychuk <valy@detee.ltd>
2024-12-24 01:09:06 +02:00

105 lines
3.2 KiB
Rust

use crate::{datastore, datastore::State, solana::SolClient};
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
const HOMEPAGE: &str = include_str!("HOMEPAGE.md");
#[get("/")]
async fn homepage(sol_client: web::Data<Arc<SolClient>>) -> impl Responder {
let text = HOMEPAGE
.to_string()
.replace("TOKEN_ADDRESS", &sol_client.get_token_address())
.replace("MINT_AUTHORITY", &sol_client.get_wallet_pubkey());
HttpResponse::Ok().body(text)
}
#[derive(Serialize)]
pub struct NodesResp {
pub ip: String,
pub joined_at: String,
pub last_keepalive: String,
pub mint_requests: u64,
pub mints: u64,
pub ratls_attacks: u64,
pub total_ratls_conns: u64,
pub public: bool,
}
impl From<(String, datastore::NodeInfo)> for NodesResp {
fn from((ip, node_info): (String, datastore::NodeInfo)) -> Self {
let joined_at: DateTime<Utc> = node_info.started_at.into();
let last_keepalive: DateTime<Utc> = node_info.keepalive.into();
let joined_at = joined_at.format("%Y-%m-%d %H:%M:%S").to_string();
let last_keepalive = last_keepalive.format("%Y-%m-%d %H:%M:%S").to_string();
NodesResp {
ip,
joined_at,
last_keepalive,
mints: node_info.mints,
total_ratls_conns: node_info.mratls_conns,
ratls_attacks: node_info.net_attacks,
public: node_info.public,
mint_requests: node_info.mint_requests,
}
}
}
#[get("/nodes")]
async fn get_nodes(ds: web::Data<Arc<State>>) -> HttpResponse {
HttpResponse::Ok()
.json(ds.get_nodes().into_iter().map(Into::<NodesResp>::into).collect::<Vec<NodesResp>>())
}
#[derive(Deserialize)]
struct MintReq {
wallet: String,
}
#[post("/mint")]
async fn mint(
state: web::Data<Arc<State>>,
sol_client: web::Data<Arc<SolClient>>,
req: web::Json<MintReq>,
) -> impl Responder {
let recipient = req.into_inner().wallet;
state.increase_mint_requests();
let result =
web::block(move || sol_client.mint(&recipient).map_err(|e| e.to_string())).await.unwrap(); // TODO: check if this can get a BlockingError
match result {
Ok(s) => {
state.increase_mints();
HttpResponse::Ok().body(format!(r#"{{" signature": "{s} "}}"#))
}
Err(e) => HttpResponse::InternalServerError().body(format!(r#"{{ "error": "{e}" }}"#)),
}
}
#[get("/metrics")]
async fn metrics(ds: web::Data<Arc<State>>) -> HttpResponse {
let mut metrics = String::new();
for (ip, node) in ds.get_nodes() {
metrics.push_str(node.to_metrics(&ip).as_str());
}
HttpResponse::Ok().content_type("text/plain; version=0.0.4; charset=utf-8").body(metrics)
}
pub async fn http_new_server(state: Arc<State>, sol_client: Arc<SolClient>) {
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(state.clone()))
.app_data(web::Data::new(sol_client.clone()))
.service(homepage)
.service(get_nodes)
.service(mint)
.service(metrics)
})
.bind("0.0.0.0:31372")
.unwrap()
.run()
.await
.unwrap();
}