WebSockets and tokio working

This commit is contained in:
2021-06-04 15:22:55 +02:00
parent 1427443caf
commit a96cbdc059
18 changed files with 542 additions and 2007 deletions

142
src/http.rs Normal file
View File

@ -0,0 +1,142 @@
use hyper::{Request, Response, Body, StatusCode, header, Method, body};
use serde_json::{Value, Map};
use crate::websocket;
use crate::usimp::*;
use crate::error::*;
use crate::usimp;
use std::str::FromStr;
async fn endpoint_handler(req: &mut Request<Body>, endpoint: String) -> Result<Option<OutputEnvelope>, Error> {
if req.method() == Method::OPTIONS {
return Ok(None)
} else if req.method() != Method::POST {
return Err(Error::new(ErrorKind::UsimpError, ErrorClass::ClientProtocolError, None))
}
let to_domain;
if let Some(val) = req.headers().get(header::HeaderName::from_str("To-Domain").unwrap()) {
to_domain = val.to_str().unwrap().to_string()
} else {
return Err(Error::new(ErrorKind::UsimpError, ErrorClass::ClientProtocolError, None))
}
if let Some(val) = req.headers().get(header::CONTENT_TYPE) {
let parts: Vec<String> = val.to_str()?.split(';').map(|v| v.trim().to_ascii_lowercase()).collect();
let p: Vec<&str> = parts.iter().map(|v| v.as_str()).collect();
match p[0..1] {
["application/json"] => {},
_ => return Err(Error::new(ErrorKind::UsimpError, ErrorClass::ClientProtocolError, None))
}
} else {
return Err(Error::new(ErrorKind::UsimpError, ErrorClass::ClientProtocolError, None))
}
let data = serde_json::from_slice(&body::to_bytes(req.body_mut()).await?)?;
let input = InputEnvelope {
endpoint,
to_domain,
from_domain: match req.headers().get(header::HeaderName::from_str("From-Domain").unwrap()) {
Some(val) => Some(val.to_str()?.to_string()),
None => None,
},
request_nr: None,
token: match req.headers().get(header::AUTHORIZATION) {
Some(val) => {
let val = val.to_str()?;
if val.starts_with("usimp ") {
Some(val[6..].to_string())
} else {
return Err(Error::new(ErrorKind::UsimpError, ErrorClass::ClientProtocolError, None))
}
},
None => None,
},
data,
};
Ok(Some(usimp::endpoint(&input).await?))
}
pub async fn handler(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
let mut res = Response::builder();
let parts: Vec<&str> = req.uri().path().split('/').skip(1).collect();
println!("{} {}", req.method(), req.uri());
let val: Result<Response<Body>, Error> = match &parts[..] {
[""] => Ok(res.status(StatusCode::OK).body(Body::from("Hello World")).unwrap()),
["_usimp"] | ["_usimp", ..] => {
res = res
.header(header::SERVER, "Locutus")
.header(header::CACHE_CONTROL, "no-store")
.header(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.header(header::ACCESS_CONTROL_MAX_AGE, 3600);
let output = match &parts[1..] {
["websocket"] => {
res = res
.header(header::ACCESS_CONTROL_ALLOW_METHODS, "GET");
let (r, val) = websocket::handler(req, res).await;
res = r;
match val {
Some(val) => Ok(Some(val)),
None => return Ok(res.body(Body::empty()).unwrap()),
}
},
[endpoint] => {
res = res
.header(header::ACCESS_CONTROL_ALLOW_METHODS, "POST, OPTIONS")
.header(header::ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type, From-Domain, To-Domain, Authorization");
let endpoint = endpoint.to_string();
endpoint_handler(&mut req, endpoint).await
},
_ => Err(Error::new(ErrorKind::UsimpError, ErrorClass::ClientProtocolError, None)),
};
let output = match output {
Ok(Some(val)) => Some(val),
Ok(None) => None,
Err(error) => Some(OutputEnvelope::from(error)),
};
if let Some(output) = output {
let mut data = Value::Object(Map::new());
match output.error {
Some(error) => {
res = match error.class {
ErrorClass::ClientProtocolError => res.status(StatusCode::BAD_REQUEST),
ErrorClass::ServerError => res.status(StatusCode::INTERNAL_SERVER_ERROR),
_ => res.status(StatusCode::OK),
};
data["status"] = Value::from("error");
data["error"] = Value::from(error);
},
None => {
data["status"] = Value::from("success");
},
}
data["request_nr"] = match output.request_nr {
Some(nr) => Value::from(nr),
None => Value::Null,
};
data["data"] = output.data;
return Ok(res.body(Body::from(serde_json::to_string(&data).unwrap() + "\r\n")).unwrap())
} else {
res = res.status(StatusCode::NO_CONTENT);
}
return Ok(res.body(Body::empty()).unwrap())
},
_ => Ok(res.status(StatusCode::NOT_FOUND).body(Body::empty()).unwrap()),
};
match val {
Ok(val) => Ok(val),
Err(error) => {
todo!("help")
}
}
}