mirror of
https://github.com/4cuck/nitter-status.git
synced 2026-10-27 00:57:39 +00:00
120 lines
4.1 KiB
Rust
120 lines
4.1 KiB
Rust
use std::{collections::HashMap, fmt::Write, sync::Arc};
|
|
|
|
use axum::{
|
|
extract::{Path, State},
|
|
http::HeaderValue,
|
|
response::{Html, IntoResponse, Redirect},
|
|
Form,
|
|
};
|
|
use chrono::{TimeZone, Utc};
|
|
use entities::{
|
|
health_check::{self, ResponseTimeStat},
|
|
host_overrides::{
|
|
self,
|
|
keys::{HostOverrides, LOCKED_FALSE, LOCKED_TRUE},
|
|
},
|
|
instance_stats,
|
|
};
|
|
use sea_orm::{sea_query::OnConflict, ActiveValue, DatabaseConnection, EntityTrait};
|
|
use tower_sessions::Session;
|
|
|
|
use crate::{Result, ServerError};
|
|
|
|
use super::get_specific_login_host;
|
|
|
|
pub async fn stats_view(
|
|
State(ref template): State<Arc<tera::Tera>>,
|
|
State(ref db): State<DatabaseConnection>,
|
|
Path(instance): Path<i32>,
|
|
session: Session,
|
|
) -> Result<axum::response::Response> {
|
|
let (host, _login) = get_specific_login_host(instance, &session, db).await?;
|
|
|
|
let mut context = tera::Context::new();
|
|
context.insert("HOST_DOMAIN", &host.domain);
|
|
context.insert("HOST_ID", &instance);
|
|
|
|
let res = Html(template.render("instance_stats.html.j2", &context)?).into_response();
|
|
Ok(res)
|
|
}
|
|
|
|
/// Returns the statistics in the CSV format required by dygraph
|
|
pub async fn health_csv_api(
|
|
State(ref db): State<DatabaseConnection>,
|
|
Path(instance): Path<i32>,
|
|
session: Session,
|
|
) -> Result<axum::response::Response> {
|
|
let (host, _login) = get_specific_login_host(instance, &session, db).await?;
|
|
// Nächstes mal:
|
|
// Fetch request times and show an additional(?) red dot for failed requests"
|
|
// Siehe globale? API mit response times
|
|
let start = std::time::Instant::now();
|
|
let healthy_data = ResponseTimeStat::fetch(db, None, None, host.id).await?;
|
|
let queried = std::time::Instant::now();
|
|
let mut data = String::with_capacity((4 + 3 + 3 + 3 + 3 + 3 + 4) * healthy_data.len());
|
|
|
|
data.push_str("Date,Healthy Rsp Time,Dead Rsp Time\n");
|
|
|
|
for entry in healthy_data {
|
|
let time = Utc
|
|
.timestamp_opt(entry.time, 0)
|
|
.unwrap()
|
|
.format("%Y-%m-%dT%H:%M:%SZ");
|
|
let (rsp_healthy, rsp_dead) = match (entry.resp_time, entry.healthy) {
|
|
(None, true) => (-1, 0), // no respons etime but healthy/unhealthy
|
|
(None, false) => (0, -1), // we don't really expect thse two cases and return -1
|
|
(Some(time), true) => (time, 0),
|
|
(Some(time), false) => (0, time),
|
|
};
|
|
writeln!(&mut data, "{time},{},{}", rsp_healthy, rsp_dead)
|
|
.map_err(|e| ServerError::CSV(e.to_string()))?;
|
|
}
|
|
let formatted = std::time::Instant::now();
|
|
let query_time = queried - start;
|
|
let format_time = formatted - queried;
|
|
tracing::debug!(?query_time, ?format_time);
|
|
|
|
let mut res = data.into_response();
|
|
res.headers_mut()
|
|
.insert("content-type", HeaderValue::from_str("text/csv").unwrap());
|
|
Ok(res)
|
|
}
|
|
|
|
/// Returns the statistics in the CSV format required by dygraph
|
|
pub async fn stats_csv_api(
|
|
State(ref db): State<DatabaseConnection>,
|
|
Path(instance): Path<i32>,
|
|
session: Session,
|
|
) -> Result<axum::response::Response> {
|
|
let (host, _login) = get_specific_login_host(instance, &session, db).await?;
|
|
|
|
let start = std::time::Instant::now();
|
|
let healthy_data = instance_stats::StatsCSVEntry::fetch(db, Some(&[host.id])).await?;
|
|
let queried = std::time::Instant::now();
|
|
let mut data = String::with_capacity(8 * healthy_data.len());
|
|
|
|
data.push_str("Date,Tokens AVG,Limited Tokens AVG,Requests AVG\n");
|
|
|
|
for entry in healthy_data {
|
|
let time = Utc
|
|
.timestamp_opt(entry.time, 0)
|
|
.unwrap()
|
|
.format("%Y-%m-%dT%H:%M:%SZ");
|
|
writeln!(
|
|
&mut data,
|
|
"{time},{},{},{}",
|
|
entry.total_accs_avg, entry.limited_accs_avg, entry.total_requests_avg
|
|
)
|
|
.map_err(|e| ServerError::CSV(e.to_string()))?;
|
|
}
|
|
let formatted = std::time::Instant::now();
|
|
let query_time = queried - start;
|
|
let format_time = formatted - queried;
|
|
tracing::debug!(?query_time, ?format_time);
|
|
|
|
let mut res = data.into_response();
|
|
res.headers_mut()
|
|
.insert("content-type", HeaderValue::from_str("text/csv").unwrap());
|
|
Ok(res)
|
|
}
|