Merge branch 'main' of ssh://github.com/Tensamin/Omega
This commit is contained in:
commit
26b8480372
13 changed files with 754 additions and 1617 deletions
|
|
@ -1,4 +1,3 @@
|
|||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||
use crate::get_public_key;
|
||||
use crate::server::omikron_manager::get_random_omikron;
|
||||
use crate::sql::sql;
|
||||
|
|
@ -11,7 +10,6 @@ use actix_web::HttpResponse;
|
|||
use actix_web::http::{StatusCode, header};
|
||||
use base64::Engine as _;
|
||||
use json::JsonValue;
|
||||
use json::number::Number;
|
||||
|
||||
pub async fn handle(path: &str, body_string: Option<String>) -> HttpResponse {
|
||||
if path == "OPTIONS" {
|
||||
|
|
@ -35,6 +33,9 @@ pub async fn handle(path: &str, body_string: Option<String>) -> HttpResponse {
|
|||
};
|
||||
|
||||
let (status, body_text) = match path_parts.as_slice() {
|
||||
// ==================================================
|
||||
// DOWNLOAD IOTA FRONTEND
|
||||
// ==================================================
|
||||
["api", "download", "iota_frontend"] => {
|
||||
let file_path = "downloads/[iota_frontend].zip";
|
||||
|
||||
|
|
@ -50,87 +51,107 @@ pub async fn handle(path: &str, body_string: Option<String>) -> HttpResponse {
|
|||
.body(file_bytes);
|
||||
}
|
||||
Err(_) => {
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
return HttpResponse::NotFound()
|
||||
.insert_header(("Access-Control-Allow-Origin", "*"))
|
||||
.body("File not found");
|
||||
.body(res.dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// GET RANDOM OMIKRON
|
||||
// ==================================================
|
||||
["api", "get", "omikron"] => {
|
||||
if let Ok(omikron_conn) = get_random_omikron().await {
|
||||
if let Ok((public_key, ip_address)) =
|
||||
sql::get_omikron_by_id(omikron_conn.get_omikron_id().await).await
|
||||
{
|
||||
(
|
||||
StatusCode::OK,
|
||||
format!(
|
||||
"{{\"id\": {}, \"public_key\": \"{}\", \"ip_address\": \"{}\"}}",
|
||||
omikron_conn.get_omikron_id().await,
|
||||
public_key,
|
||||
ip_address
|
||||
),
|
||||
)
|
||||
let id = omikron_conn.get_omikron_id().await;
|
||||
|
||||
if let Ok((public_key, ip_address)) = sql::get_omikron_by_id(id).await {
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["id"] = id.into();
|
||||
res["public_key"] = public_key.into();
|
||||
res["ip_address"] = ip_address.into();
|
||||
|
||||
(StatusCode::OK, res.dump())
|
||||
} else {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"selected an invalid omikron".to_string(),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error".into();
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, res.dump())
|
||||
}
|
||||
} else {
|
||||
(
|
||||
StatusCode::NOT_FOUND,
|
||||
"couldn't find online omikron".to_string(),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::NOT_FOUND, res.dump())
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// GET OMIKRON BY ID
|
||||
// ==================================================
|
||||
["api", "get", "omikron", id] => {
|
||||
let id = id.parse::<i64>().unwrap_or(0);
|
||||
|
||||
if id == 0 {
|
||||
not_found()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_bad_request".into();
|
||||
(StatusCode::BAD_REQUEST, res.dump())
|
||||
} else if let Ok((public_key, ip_address)) = get_omikron_by_id(id).await {
|
||||
(
|
||||
StatusCode::OK,
|
||||
format!(
|
||||
"{{\"id\": {}, \"public_key\": \"{}\", \"ip_address\": \"{}\"}}",
|
||||
id, public_key, ip_address
|
||||
),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["id"] = id.into();
|
||||
res["public_key"] = public_key.into();
|
||||
res["ip_address"] = ip_address.into();
|
||||
(StatusCode::OK, res.dump())
|
||||
} else if let Some(omikron_id) = get_iota_primary_omikron_connection(id) {
|
||||
if let Ok((public_key, ip_address)) = get_omikron_by_id(omikron_id).await {
|
||||
(
|
||||
StatusCode::OK,
|
||||
format!(
|
||||
"{{\"id\": {}, \"public_key\": \"{}\", \"ip_address\": \"{}\"}}",
|
||||
omikron_id, public_key, ip_address
|
||||
),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["id"] = omikron_id.into();
|
||||
res["public_key"] = public_key.into();
|
||||
res["ip_address"] = ip_address.into();
|
||||
(StatusCode::OK, res.dump())
|
||||
} else {
|
||||
not_found()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::NOT_FOUND, res.dump())
|
||||
}
|
||||
} else if let Ok((_, iota_id, _, _, _, _, _, _, _, _, _, _)) = get_by_user_id(id).await
|
||||
{
|
||||
if let Some(omikron_id) = get_iota_primary_omikron_connection(iota_id) {
|
||||
if let Ok((public_key, ip_address)) = get_omikron_by_id(omikron_id).await {
|
||||
(
|
||||
StatusCode::OK,
|
||||
format!(
|
||||
"{{\"id\": {}, \"public_key\": \"{}\", \"ip_address\": \"{}\"}}",
|
||||
omikron_id, public_key, ip_address
|
||||
),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["id"] = omikron_id.into();
|
||||
res["public_key"] = public_key.into();
|
||||
res["ip_address"] = ip_address.into();
|
||||
(StatusCode::OK, res.dump())
|
||||
} else {
|
||||
not_found()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::NOT_FOUND, res.dump())
|
||||
}
|
||||
} else {
|
||||
not_found()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::NOT_FOUND, res.dump())
|
||||
}
|
||||
} else {
|
||||
not_found()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::NOT_FOUND, res.dump())
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// GET ID BY USERNAME
|
||||
// ==================================================
|
||||
["api", "get", "id", username] => {
|
||||
if username.is_empty() {
|
||||
not_found()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_bad_request".into();
|
||||
(StatusCode::BAD_REQUEST, res.dump())
|
||||
} else if let Ok((
|
||||
id,
|
||||
iota_id,
|
||||
|
|
@ -146,37 +167,49 @@ pub async fn handle(path: &str, body_string: Option<String>) -> HttpResponse {
|
|||
_,
|
||||
)) = sql::get_by_username(username).await
|
||||
{
|
||||
let cv = CommunicationValue::new(CommunicationType::success)
|
||||
.add_data_str(DataTypes::username, username)
|
||||
.add_data_str(DataTypes::public_key, public_key)
|
||||
.add_data(DataTypes::user_id, JsonValue::Number(Number::from(id)))
|
||||
.add_data(DataTypes::iota_id, JsonValue::Number(Number::from(iota_id)))
|
||||
.add_data(
|
||||
DataTypes::sub_level,
|
||||
JsonValue::Number(Number::from(sub_level)),
|
||||
)
|
||||
.add_data(DataTypes::sub_end, JsonValue::Number(Number::from(sub_end)));
|
||||
(StatusCode::OK, cv.to_json().to_string())
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["username"] = username.into();
|
||||
res["public_key"] = public_key.into();
|
||||
res["user_id"] = id.into();
|
||||
res["iota_id"] = iota_id.into();
|
||||
res["sub_level"] = sub_level.into();
|
||||
res["sub_end"] = sub_end.into();
|
||||
|
||||
(StatusCode::OK, res.dump())
|
||||
} else {
|
||||
(
|
||||
StatusCode::OK,
|
||||
CommunicationValue::new(CommunicationType::error_not_found)
|
||||
.to_json()
|
||||
.to_string(),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::OK, res.dump())
|
||||
}
|
||||
}
|
||||
["api", "get", "public_key"] => (StatusCode::OK, public_key_to_base64(&get_public_key())),
|
||||
|
||||
// ==================================================
|
||||
// GET SERVER PUBLIC KEY
|
||||
// ==================================================
|
||||
["api", "get", "public_key"] => {
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["public_key"] = public_key_to_base64(&get_public_key()).into();
|
||||
(StatusCode::OK, res.dump())
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// GET USER BY ID
|
||||
// ==================================================
|
||||
["api", "get", "user", id] => {
|
||||
let id: i64 = id.parse().unwrap_or(0);
|
||||
|
||||
if id == 0 {
|
||||
bad_request()
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_bad_request".into();
|
||||
(StatusCode::BAD_REQUEST, res.dump())
|
||||
} else if let Ok((
|
||||
id,
|
||||
iota_id,
|
||||
username,
|
||||
display,
|
||||
status,
|
||||
status_msg,
|
||||
about,
|
||||
avatar,
|
||||
sub_level,
|
||||
|
|
@ -186,47 +219,46 @@ pub async fn handle(path: &str, body_string: Option<String>) -> HttpResponse {
|
|||
_,
|
||||
)) = sql::get_by_user_id(id).await
|
||||
{
|
||||
let mut cv = CommunicationValue::new(CommunicationType::success)
|
||||
.add_data_str(DataTypes::username, username)
|
||||
.add_data_str(DataTypes::public_key, public_key)
|
||||
.add_data(DataTypes::user_id, JsonValue::Number(Number::from(id)))
|
||||
.add_data(DataTypes::iota_id, JsonValue::Number(Number::from(iota_id)))
|
||||
.add_data(
|
||||
DataTypes::sub_level,
|
||||
JsonValue::Number(Number::from(sub_level)),
|
||||
)
|
||||
.add_data(DataTypes::sub_end, JsonValue::Number(Number::from(sub_end)));
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "success".into();
|
||||
res["username"] = username.into();
|
||||
res["public_key"] = public_key.into();
|
||||
res["user_id"] = id.into();
|
||||
res["iota_id"] = iota_id.into();
|
||||
res["sub_level"] = sub_level.into();
|
||||
res["sub_end"] = sub_end.into();
|
||||
|
||||
if let Some(display) = display {
|
||||
cv = cv.add_data_str(DataTypes::display, display);
|
||||
res["display"] = display.into();
|
||||
}
|
||||
if let Some(status) = status {
|
||||
cv = cv.add_data_str(DataTypes::status, status);
|
||||
if let Some(status_msg) = status_msg {
|
||||
res["status_message"] = status_msg.into();
|
||||
}
|
||||
if let Some(about) = about {
|
||||
cv = cv.add_data_str(DataTypes::about, about);
|
||||
res["about"] = about.into();
|
||||
}
|
||||
if let Some(avatar) = avatar {
|
||||
cv = cv.add_data_str(
|
||||
DataTypes::avatar,
|
||||
base64::engine::general_purpose::STANDARD.encode(avatar),
|
||||
);
|
||||
res["avatar"] = base64::engine::general_purpose::STANDARD
|
||||
.encode(avatar)
|
||||
.into();
|
||||
}
|
||||
(StatusCode::OK, cv.to_json().to_string())
|
||||
|
||||
(StatusCode::OK, res.dump())
|
||||
} else {
|
||||
(
|
||||
StatusCode::OK,
|
||||
CommunicationValue::new(CommunicationType::error_not_found)
|
||||
.to_json()
|
||||
.to_string(),
|
||||
)
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error_not_found".into();
|
||||
(StatusCode::OK, res.dump())
|
||||
}
|
||||
}
|
||||
_ => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
CommunicationValue::new(CommunicationType::error)
|
||||
.to_json()
|
||||
.to_string(),
|
||||
),
|
||||
|
||||
// ==================================================
|
||||
// DEFAULT
|
||||
// ==================================================
|
||||
_ => {
|
||||
let mut res = JsonValue::new_object();
|
||||
res["status"] = "error".into();
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, res.dump())
|
||||
}
|
||||
};
|
||||
let body_bytes = body_text.into_bytes();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,3 @@ pub mod omikron_connection;
|
|||
pub mod omikron_manager;
|
||||
pub mod server;
|
||||
pub mod short_link;
|
||||
pub mod socket;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,10 @@
|
|||
use crate::{
|
||||
log,
|
||||
server::{api, short_link::get_short_link, socket},
|
||||
server::{api, short_link::get_short_link},
|
||||
util::file_util::get_directory,
|
||||
};
|
||||
|
||||
use actix_web::{App, HttpRequest, HttpResponse, HttpServer, Responder, http::header, web};
|
||||
use actix_web_actors::ws;
|
||||
|
||||
use rustls::ServerConfig;
|
||||
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
|
||||
|
|
@ -42,7 +41,6 @@ pub async fn start(port: u16) -> anyhow::Result<()> {
|
|||
App::new()
|
||||
.route("/api/{path:.*}", web::to(api_handler))
|
||||
.route("/direct/{path:.*}", web::to(direct_handler))
|
||||
.route("/ws/{path:.*}", web::get().to(ws_handler))
|
||||
})
|
||||
.bind_rustls_0_23(addr, config)?
|
||||
.run()
|
||||
|
|
@ -64,16 +62,6 @@ async fn direct_handler(req: HttpRequest) -> impl Responder {
|
|||
.finish()
|
||||
}
|
||||
}
|
||||
async fn ws_handler(
|
||||
req: HttpRequest,
|
||||
stream: web::Payload,
|
||||
path: web::Path<String>,
|
||||
) -> Result<HttpResponse, actix_web::Error> {
|
||||
let path = path.into_inner();
|
||||
println!("WS handler reached: {}", path);
|
||||
|
||||
ws::start(socket::WsSession::new(path), &req, stream)
|
||||
}
|
||||
|
||||
async fn api_handler(req: HttpRequest, body: web::Bytes) -> HttpResponse {
|
||||
let path = req.uri().path().to_string();
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use actix::{Actor, ActorContext, AsyncContext, StreamHandler};
|
||||
use actix_web_actors::ws;
|
||||
|
||||
use crate::data::communication::{CommunicationType, CommunicationValue};
|
||||
use crate::log;
|
||||
use crate::server::omikron_connection::OmikronConnection;
|
||||
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
use actix::Message;
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "()")]
|
||||
pub struct WsSendMessage(pub String);
|
||||
|
||||
impl actix::Handler<WsSendMessage> for WsSession {
|
||||
type Result = ();
|
||||
|
||||
fn handle(&mut self, msg: WsSendMessage, ctx: &mut Self::Context) {
|
||||
ctx.text(msg.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WsSession {
|
||||
path: String,
|
||||
last_heartbeat: Instant,
|
||||
omikron: Option<Arc<OmikronConnection>>,
|
||||
}
|
||||
|
||||
impl WsSession {
|
||||
pub fn new(path: String) -> Self {
|
||||
Self {
|
||||
path,
|
||||
last_heartbeat: Instant::now(),
|
||||
omikron: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn start_heartbeat(&self, ctx: &mut ws::WebsocketContext<Self>) {
|
||||
ctx.run_interval(Duration::from_secs(5), |act, ctx| {
|
||||
if Instant::now().duration_since(act.last_heartbeat) > IDLE_TIMEOUT {
|
||||
log!("[ws_handler] Heartbeat failed. Disconnecting.");
|
||||
ctx.close(None);
|
||||
ctx.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
let ping = CommunicationValue::new(CommunicationType::ping)
|
||||
.to_json()
|
||||
.to_string();
|
||||
|
||||
ctx.text(ping);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Actor for WsSession {
|
||||
type Context = ws::WebsocketContext<Self>;
|
||||
|
||||
fn started(&mut self, ctx: &mut Self::Context) {
|
||||
self.start_heartbeat(ctx);
|
||||
|
||||
if self.path == "omikron" {
|
||||
let addr = ctx.address();
|
||||
let connection = OmikronConnection::new(addr);
|
||||
self.omikron = Some(connection);
|
||||
}
|
||||
}
|
||||
|
||||
fn stopped(&mut self, _: &mut Self::Context) {
|
||||
log!(
|
||||
"[ws] WebSocket handling task for path: {} is finished.",
|
||||
self.path
|
||||
);
|
||||
|
||||
if let Some(conn) = &self.omikron {
|
||||
let conn = conn.clone();
|
||||
actix_rt::spawn(async move {
|
||||
conn.handle_close().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsSession {
|
||||
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
||||
match msg {
|
||||
Ok(ws::Message::Text(text)) => {
|
||||
self.last_heartbeat = Instant::now();
|
||||
|
||||
if let Some(conn) = &self.omikron {
|
||||
let conn_clone = conn.clone();
|
||||
actix_rt::spawn(async move {
|
||||
conn_clone.handle_message(text.to_string()).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ws::Message::Ping(msg)) => {
|
||||
self.last_heartbeat = Instant::now();
|
||||
ctx.pong(&msg);
|
||||
}
|
||||
|
||||
Ok(ws::Message::Pong(_)) => {
|
||||
self.last_heartbeat = Instant::now();
|
||||
log!("[ws_handler] Received Pong. Connection alive.");
|
||||
}
|
||||
|
||||
Ok(ws::Message::Close(reason)) => {
|
||||
log!("[ws_handler] Received Close. Disconnecting.");
|
||||
ctx.close(reason);
|
||||
ctx.stop();
|
||||
}
|
||||
|
||||
Ok(ws::Message::Binary(_)) => {
|
||||
log!("[ws_handler] Binary message ignored.");
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
log!("[ERROR] WS Error: {}. Closing.", e);
|
||||
ctx.stop();
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue