freechat/json-api/src/meta.rs
shockrah a941165ea5 + adding /neighbor/update route to dispatch
! This route needs way more testing as its currently failing the prelim test listed right now

! Some more misc changes in testing/mod.rs that aren't imporant at all to anyone
It's just an extra comment
2021-05-11 17:25:51 -07:00

119 lines
4.3 KiB
Rust

// Basic handler for getting meta data about the server
use std::collections::HashMap;
use crate::http::set_json_body;
use db::Neighbor;
use mysql_async::Pool;
use hyper::{Response, Body, StatusCode};
use hyper::body::to_bytes;
use hyper::body::Bytes;
use serde_json::{json, to_string, Result as JsonResult};
use serde::{Serialize, Deserialize};
use lazy_static::lazy_static;
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pub name: String,
pub description: String,
pub url: String,
pub wsurl: String,
pub tags: Vec<String>
}
lazy_static! {
// NOTE: this object must be access by proxy through get_config()
#[derive(Deserialize, Serialize)]
static ref BASIC_CONFIG: Config = {
use std::fs::File;
use std::io::BufReader;
match File::open("config.json") {
Ok(file) => {
let reader = BufReader::new(file);
let rr: JsonResult<Config> = serde_json::from_reader(reader);
match rr {
Ok(meta) => meta,
Err(e) => panic!("{}", e)
}
},
Err(e) => panic!("{}", e)
}
};
}
pub fn get_config() -> Config {
// We have to do this (for now) because lazy_static silently hides the actual fields
// we care about
Config {
name: BASIC_CONFIG.name.clone(),
description: BASIC_CONFIG.description.clone(),
url: BASIC_CONFIG.url.clone(),
wsurl: BASIC_CONFIG.wsurl.clone(),
tags: BASIC_CONFIG.tags.clone()
}
}
pub async fn server_meta(response: &mut Response<Body>) {
// NOTE: This route _is_ open but we should do something to rate limit the
// number of requests we service as it could be ripe for abuse
*response.body_mut() = Body::from(to_string(&get_config()).unwrap());
}
pub async fn server_neighbors(p: &Pool, response: &mut Response<Body>) {
// This method refers to what servers have been added as **related** by the admins
// It returns a list of servers meta objects which converted to JSON
match db::neighbors::get_all(p).await {
Ok(neighbors) => set_json_body(response, json!({"neighbors": neighbors})),
Err(e) => {
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
eprintln!("500 /neighbors/list {}", e);
}
}
}
pub async fn add_neighbor(p: &Pool, response: &mut Response<Body>, body: Body) {
let body: Bytes = to_bytes(body).await.unwrap_or(Bytes::new());
let json: JsonResult<Neighbor> = serde_json::from_slice(&body);
if let Ok(neighbor) = json {
// Before we try adding the new neighbor, make sure there isn't already
// an entry with the same url
if let Ok(row) = db::neighbors::get(p, &neighbor.url).await {
match row.is_some() {
true => *response.status_mut() = StatusCode::CONFLICT,
false => if let Err(e) = db::neighbors::add_neighbor(p, neighbor).await {
eprintln!("{}", e);
}
};
} else {
eprintln!();
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
}
} else {
*response.status_mut() = StatusCode::BAD_REQUEST;
}
}
pub async fn update_neighbor(p: &Pool, response: &mut Response<Body>, params: HashMap<String, String>, body: Body) {
// First collect the target url from the map and try to parse the body
let target = params.get("url");
let body: Bytes = to_bytes(body).await.unwrap_or(Bytes::new());
let s: String = String::from_utf8_lossy(&body).to_string();
let json: JsonResult<Neighbor> = serde_json::from_str(&s);
println!("\tjson result: {:?}", json);
println!("\tbody {}", s);
// Verify query string parameter **and** body before attempting to reach database
match (target, json) {
(Some(target_url), Ok(neighbor)) => {
// Only return a 500 if something happened on db-lib's end
if let Err(e) = db::neighbors::update(p, target_url, neighbor).await {
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
eprintln!("/neighbor/update [DB-LIB] {}", e);
}
// Nothing to do on success 200 is already set by hyper
},
_ => *response.status_mut() = StatusCode::BAD_REQUEST
}
}