118 lines
3.5 KiB
Rust
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()
|
|
}
|