hacker-challenge-sgx-general/src/http_server.rs

112 lines
3.3 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 serde_json::json;
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(state: web::Data<Arc<State>>) -> HttpResponse {
let nodes = state.get_nodes().await;
HttpResponse::Ok()
.json(nodes.into_iter().map(Into::<NodesResp>::into).collect::<Vec<NodesResp>>())
}
#[derive(Deserialize)]
struct MintReq {
address: String,
}
#[post("/mint")]
async fn mint(
state: web::Data<Arc<State>>,
sol_client: web::Data<Arc<SolClient>>,
req: web::Query<MintReq>,
) -> impl Responder {
let recipient = req.into_inner().address;
state.increase_mint_requests().await;
if state.is_minting() {
return HttpResponse::TooManyRequests().json(json!({ "error": "already mint processing" }));
}
let mint_res = sol_client.mint(&recipient).await;
state.release_minting();
match mint_res {
Ok(s) => {
state.increase_mints().await;
HttpResponse::Ok().json(json!({"signature": s}))
}
Err(e) => HttpResponse::InternalServerError().json(json!({ "error": e.to_string() })),
}
}
#[get("/metrics")]
async fn metrics(state: web::Data<Arc<State>>) -> HttpResponse {
let mut metrics = String::new();
for (ip, node) in state.get_nodes().await {
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();
}