OispaHallaAnticheat / src / server.rs
server.rs
Raw
//! Rocket-kirjastoon pohjautuva palvelin, joka tarjoaa verkkorajapinnan vilpinestolle

use std::sync::Arc;
use std::sync::Mutex;

use rocket::http::Method;
use rocket::State;
use rocket_cors::AllowedHeaders;
use rocket_cors::AllowedOrigins;

use serde::Serialize;
use rocket_contrib::json::Json;

use crate::DEBUG_INFO;
use crate::parser::parse_data;
use crate::board::print_board;

use crate::validator::validate_history;
use crate::validator::validate_first_move;

/// sallitut CORS-lähteet, eli mistä osoitteista käyttäjän selain saa kutsua api:ta.
/// HUOM: Kukaan ei valvo ominaisuuden toteutusta käyttäjän puolella, tämä ei suojaa palvelinta millään tasolla.
static ALLOWED_ORIGINS_STR: [&'static str; 7] = [
    "http://localhost:8080",
    "https://oispahalla.com/",
    "http://oispahalla.com",
    "http://oispahalla-dev.netlify.app/",
    "https://oispahalla-dev.netlify.app/",
    "https://dev--oispahalla-dev.netlify.app",
    "https://dev.oispahalla.com/"
];

/// Kuinka monta kertaa /validate funktiota on kutsuttu
struct RequestCount(Arc<Mutex<usize>>);

/// Käynnistää Rocket-palvelimen ja tekee tarvitut määritykset
pub fn start_server(){
    let rc = RequestCount(Arc::new(Mutex::new(0)));
    let allowed_origins = AllowedOrigins::some_exact(&ALLOWED_ORIGINS_STR);
    let routes = routes![alive, hello, config];
    let cors = rocket_cors::CorsOptions {
        allowed_origins,
        allowed_methods: vec![Method::Get].into_iter().map(From::from).collect(),
        allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
        allow_credentials: true,
        ..Default::default()
    }
    .to_cors().expect("Cors did not set up correctly!");
    rocket::ignite().manage(rc).mount("/HAC", routes).attach(cors).launch();
}

/// Malli jossa /get_config palauttaa dataa
#[derive(Serialize)]
struct ConfigResponse {
    allowed_origins: [&'static str; 7],
    platform: &'static str,
    version: String,
    rust_version: &'static str,
    request_count: usize
}

/// /get_config
#[get("/get_config")]
fn config(rc: State<RequestCount>) -> Json<ConfigResponse>{
    pub mod built_info {
        // The file has been placed there by the build script.
        include!(concat!(env!("OUT_DIR"), "/built.rs"));
    }
    let version = std::env::var("HAC_VERSION").unwrap_or(match built_info::GIT_COMMIT_HASH {
        Some(v)=>String::from(v),
        _ => String::from("unknown version")
    });
    Json(
        ConfigResponse{
            allowed_origins: ALLOWED_ORIGINS_STR,
            platform: built_info::TARGET,
            version: version,
            rust_version: built_info::RUSTC_VERSION,
            request_count: *rc.0.lock().unwrap()
        }
    )
}

/// /alive
/// Kuuluisi aina palauttaa plaintext-merkkijonon "true"
#[get("/alive")]
fn alive() -> String{
    format!("true")
}

/// Malli jossa /validate palauttaa dataa
#[derive(Serialize)]
struct ValidationResponse{
    run_hash: String,
    board_w: usize,
    board_h: usize,
    valid: bool,
    score: usize,
    score_margin: usize,
    breaks: usize,
    length: usize
}

/// /validate/<run_json>
/// Missä <run_json> on pelattua peliä kuvaava merkkijono
#[get("/validate/<run_json>")]
fn hello(run_json: String, rc: State<RequestCount>) -> Json<ValidationResponse> {
    let history = parse_data(run_json);
    let length = history.history.len();
    println!("Loaded record with the length of {}.", length);
    if DEBUG_INFO{
        let mut index = 0;
        for i in &history.history{
            println!("History at index {}:", index);
            print_board(i.0, history.width, history.height);
            println!("move to direction {:?} and add {:?}", i.1, i.2);
            index += 1;
        }
        println!("#\t#\t#\t#\t");
    }
    let hash = history.hash_v1();
    let w = history.width;
    let h = history.height;
    let result0 = validate_first_move(&history);
    let (result1, score, score_margin, breaks) = validate_history(history);
    let valid = result0 && result1;
    println!( "Run <{}>", hash );
    println!( "\tBoard size: {}x{}", w, h );
    println!( "\tRun score: {}", score );
    println!( "\tBreaks used: {}", breaks );
    println!( "\tValid: {}", valid );
    //let out = format!("{}\"hash\": {}, \"board_w\": {}, \"board_h\": {}, \"valid\": {:#?}, \"score\": {}, \"breaks\": {}{}", "{", hash, w, h, valid, score, breaks, "}");
    let out = ValidationResponse{
        run_hash: hash,
        board_w: w,
        board_h: h,
        valid: valid,
        score: score,
        score_margin: score_margin,
        breaks: breaks,
        length: length
    };
    // Add one to the 
    let mut request_count = rc.0.lock().unwrap();
    *request_count += 1;
    // Return the json
    Json(out)
}