Files
mapbattle/src/main.rs

118 lines
3.5 KiB
Rust

pub mod osm;
mod data;
mod geo_utils;
use crate::osm::scores;
use std::error::Error;
use std::fs;
use chrono::NaiveDateTime;
use reqwest::Client;
use xml::reader::EventReader;
use actix_web::{get, App, HttpResponse, HttpServer, Responder};
use crate::data::{Team, Player, TeamLegend};
use std::collections::HashMap;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use tokio::time;
use std::time::Duration;
const DATE_FORMAT: &str = "%Y-%m-%dT%H:%M:%SZ";
#[get("/legend-data")]
async fn legend_data() -> impl Responder {
let teams = read_scores();
let legends: Vec<TeamLegend> = teams.into_iter()
.map(|t| TeamLegend{name: t.name, color: t.color}).collect();
HttpResponse::Ok()
.content_type("application/json")
.body(serde_json::to_string(&legends).unwrap())
}
#[get("/geojson")]
async fn geojson_endpoint() -> impl Responder {
let utils = geo_utils::GeoUtils::new();
let teams = read_scores();
let feature_collection = utils.get_colored_collection_copy(teams);
HttpResponse::Ok()
.content_type("application/json")
.body(serde_json::to_string(&feature_collection).unwrap())
}
#[get("/")]
async fn index() -> impl Responder {
let html: String = fs::read_to_string("map.html").expect("file should be present");
HttpResponse::Ok()
.content_type("text/html")
.body(html)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut interval = time::interval(Duration::from_secs(60 * 5));
let _maintainance = tokio::task::spawn(async move {
loop {
interval.tick().await;
let _ = update_scores().await;
}
});
HttpServer::new(|| {
App::new()
.service(index)
.service(geojson_endpoint)
.service(legend_data)
})
.bind(("0.0.0.0", 8080))?
.run()
.await
}
async fn update_scores()-> Result<(), Box<dyn Error>> {
let client = Client::builder()
.user_agent("MapBattle/0.1")
.build()?;
// Load players from a database?
let mut teams: Vec<Team> = vec![
Team{
name: String::from("potato"),
color: String::from("#df1aeaff"),
scores: HashMap::new(),
players: vec![
Player {
username: String::from("ammaratef45")
}
]
}
];
// Configure time range
let start_date = NaiveDateTime::parse_from_str("2025-11-13T11:55:07Z", DATE_FORMAT)?;
let end_date = NaiveDateTime::parse_from_str("2025-11-13T15:55:07Z", DATE_FORMAT)?;
for team in &mut teams {
for player in team.players.clone() {
println!("Processing player: {} ({})", player.username, team.name);
let body = scores::get_changesets_for_user(player.username.clone(), &client).await?;
let reader = EventReader::from_str(&body);
let changesets = scores::extract_changesets_from_reader(reader);
let changesets = scores::time_bound_changesets(changesets, start_date, end_date);
let territory_scores = scores::changesets_to_points(changesets).await;
team.add_scores(&territory_scores);
}
}
let file = File::create("scores.json")?;
let mut writer = BufWriter::new(file);
serde_json::to_writer_pretty(&mut writer, &teams)?;
writer.flush()?;
Ok(())
}
fn read_scores() -> Vec<Team> {
let text: String = fs::read_to_string("scores.json").expect("file should be present");
serde_json::from_str(&text).unwrap()
}