use actix_web::{web, HttpResponse};
use crate::pages::templates::ATOM_TURNS;
use crate::{DataBaseRo, WebData};
#[derive(serde_derive::Serialize)]
struct FeedData {
gameuid: String,
gameuidenc: String,
upddatetime: String,
entries: Vec<EntriesData>,
selflink: String,
}
#[derive(serde_derive::Serialize)]
struct EntriesData {
new: bool,
turn: i32,
turn_ts_str: String,
turn_ts: i64,
}
#[actix_web::get("/atoms/{path}.xml")]
pub async fn atom_turns(
path: web::Path<String>,
data: web::Data<WebData<'_>>,
data_ro: web::Data<DataBaseRo>,
) -> HttpResponse {
let gameuid = path.into_inner();
let gameuid = match gameuid.char_indices().nth(128) {
None => gameuid,
Some((idx, _)) => gameuid[..idx].to_string(),
};
let dbclient = match data_ro.0.get().await {
Ok(client) => client,
Err(e) => {
log::error!("{}", e);
return HttpResponse::ServiceUnavailable().body(actix_web::body::None::new());
}
};
let stmt = match dbclient.prepare("select g.game_uid, t.turn, t.turn_ts from games.games g left join games.turns t on t.game_uid = g.game_uid where g.game_uid = $1 order by t.turn_ts desc limit 50;").await {
Ok(stmt) => stmt,
Err(e) => {
log::error!("{}", e);
return HttpResponse::ServiceUnavailable().body(actix_web::body::None::new());
}
};
let rows = match dbclient.query(&stmt, &[&gameuid]).await {
Ok(rows) => rows,
Err(e) => {
log::error!("{}", e);
return HttpResponse::ServiceUnavailable().body(actix_web::body::None::new());
}
};
if rows.is_empty() {
log::info!("Empty data for {}", gameuid);
return HttpResponse::NotFound().body(actix_web::body::None::new());
}
let mut upd_date_time = None;
let mut entries = Vec::with_capacity(rows.len());
for row in rows {
if let Some(turn) = row.get::<_, Option<i32>>(1) {
if let Some(turn_ts) = row.get::<_, Option<chrono::NaiveDateTime>>(2) {
use chrono::TimeZone;
let entry_ts = chrono::Utc::from_utc_datetime(&chrono::Utc, &turn_ts);
entries.insert(
0,
EntriesData {
new: turn <= 0,
turn,
turn_ts_str: entry_ts.to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
turn_ts: entry_ts.timestamp(),
},
);
upd_date_time.get_or_insert(entry_ts);
}
}
}
let upd_date_time = upd_date_time.unwrap_or_else(chrono::Utc::now);
let body = match data.handlebars_xml.render(
ATOM_TURNS,
&FeedData {
gameuid: gameuid.to_string(),
gameuidenc: pct_str::PctString::encode(gameuid.chars(), pct_str::URIReserved)
.into_string(),
entries,
upddatetime: upd_date_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
selflink: format!("{}://{}/", data.base_proto, data.base_domain),
},
) {
Ok(b) => b,
Err(e) => {
log::error!("{}", e);
return HttpResponse::ServiceUnavailable().body(actix_web::body::None::new());
}
};
HttpResponse::Ok()
.insert_header(("Content-Type", "application/atom+xml"))
.insert_header((
"Date",
upd_date_time
.format("%a, %d %b %Y %H:%M:%S GMT")
.to_string(),
))
.body(body)
}