mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2025-07-17 12:48:04 +00:00
Refactor project
This commit is contained in:
src
controllers
account_controller.rscalls_controller.rscomments_controller.rsconversations_controller.rsfriends_controller.rsgroups_controller.rslikes_controller.rsmod.rsnotifications_controller.rsposts_controller.rssearch_controller.rsserver_controller.rssettings_controller.rssurveys_controller.rsuser_controller.rsuser_ws_controller.rsvirtual_directory_controller.rsweb_app_controller.rs
data
helpers
lib.rsmain.rsroutes.rsserver.rsuser_ws_routes.rs@ -8,13 +8,13 @@ use crate::api_data::res_check_security_answers::ResCheckSecurityAnswers;
|
||||
use crate::api_data::res_check_security_questions_exists::ResCheckSecurityQuestionsExists;
|
||||
use crate::api_data::res_get_security_questions::ResGetSecurityQuestions;
|
||||
use crate::constants::PASSWORD_RESET_TOKEN_LENGTH;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::ResultBoxError;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::data::new_account::NewAccount;
|
||||
use crate::data::user::{User, UserID};
|
||||
use crate::helpers::{account_helper, user_helper};
|
||||
use crate::routes::RequestResult;
|
||||
|
||||
/// Account controller
|
||||
///
|
||||
|
@ -13,7 +13,7 @@ use crate::api_data::joined_call_message::JoinedCallMessage;
|
||||
use crate::api_data::left_call_message::LeftCallMessage;
|
||||
use crate::api_data::new_call_signal::NewCallSignalAPI;
|
||||
use crate::api_data::user_calls_config::UserCallsConfig;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::controllers::user_ws_controller;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::call_signal::{CallSignal, CloseCallStream, IceCandidate, NewUserCallSignal, SdpType, UserCallOfferRequest};
|
||||
|
@ -5,7 +5,7 @@
|
||||
use crate::api_data::comment_api::CommentAPI;
|
||||
use crate::api_data::res_create_comment::ResCreateComment;
|
||||
use crate::constants::PATH_COMMENTS_IMAGES;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::controllers::user_ws_controller;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::comment::Comment;
|
||||
|
@ -11,7 +11,7 @@ use crate::api_data::list_unread_conversations_api::UnreadConversationAPI;
|
||||
use crate::api_data::res_count_unread_conversations::ResultCountUnreadConversations;
|
||||
use crate::api_data::res_create_conversation::ResCreateConversation;
|
||||
use crate::api_data::res_find_private_conversations::ResFindPrivateConversations;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::controllers::user_ws_controller;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::Res;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use crate::api_data::friend_api::FriendAPI;
|
||||
use crate::api_data::friendship_status_api::FriendshipStatusAPI;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::data::notification::NotifEventType;
|
||||
|
@ -10,7 +10,7 @@ use crate::api_data::group_member_api::GroupMemberAPI;
|
||||
use crate::api_data::res_change_group_logo::ResChangeGroupLogo;
|
||||
use crate::api_data::res_create_group::GroupCreationResult;
|
||||
use crate::constants::{DEFAULT_GROUP_LOGO, PATH_GROUPS_LOGOS};
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::group::{Group, GroupAccessLevel, GroupPostsCreationLevel, GroupRegistrationLevel, GroupVisibilityLevel};
|
||||
use crate::data::group_id::GroupID;
|
||||
|
@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::ExecError;
|
||||
use crate::data::group::GroupAccessLevel;
|
||||
|
@ -1,5 +1,3 @@
|
||||
pub mod routes;
|
||||
pub mod server;
|
||||
|
||||
pub mod server_controller;
|
||||
pub mod user_ws_controller;
|
||||
@ -19,5 +17,4 @@ pub mod notifications_controller;
|
||||
pub mod virtual_directory_controller;
|
||||
pub mod web_app_controller;
|
||||
pub mod calls_controller;
|
||||
pub mod user_ws_routes;
|
||||
pub mod user_ws_actions;
|
@ -5,7 +5,7 @@
|
||||
use crate::api_data::notification_api::NotificationAPI;
|
||||
use crate::api_data::res_count_all_unreads::ResCountAllUnread;
|
||||
use crate::api_data::res_number_unread_notifications::ResNumberUnreadNotifications;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::controllers::user_ws_controller;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::{Res, ResultBoxError};
|
||||
|
@ -6,7 +6,7 @@ use crate::api_data::post_api::PostAPI;
|
||||
use crate::api_data::posts_targets_api::PostsTargets;
|
||||
use crate::api_data::res_create_post::ResCreatePost;
|
||||
use crate::constants::{PATH_POST_IMAGES, PATH_POST_PDF};
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::{ExecError, ResultBoxError};
|
||||
use crate::data::group::GroupAccessLevel;
|
||||
|
@ -1,291 +0,0 @@
|
||||
use std::error::Error;
|
||||
|
||||
use crate::controllers::{account_controller, calls_controller, comments_controller, conversations_controller, friends_controller, groups_controller, likes_controller, notifications_controller, posts_controller, search_controller, server_controller, settings_controller, surveys_controller, user_controller, user_ws_controller, virtual_directory_controller, web_app_controller};
|
||||
use crate::controllers::routes::Method::{GET, POST};
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
|
||||
/// Project routes
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
#[derive(PartialEq)]
|
||||
pub enum Method {
|
||||
GET,
|
||||
POST,
|
||||
}
|
||||
|
||||
/// Limitation policy of a request for a given IP address
|
||||
///
|
||||
/// All the limit are on a per-hour basis (the first request that triggers the limit is the one
|
||||
/// that is recorded)
|
||||
pub enum LimitPolicy {
|
||||
// No limit is applied to the request
|
||||
NONE,
|
||||
|
||||
// An acceptable threshold of successful requests (= 200) is defined, then the requests are
|
||||
// rejected (they are not even processed)
|
||||
SUCCESS(u64),
|
||||
|
||||
// An acceptable threshold of unsuccessful requests (!= 200) is defined, then the requests are
|
||||
// rejected (they are not even processed)
|
||||
FAILURE(u64),
|
||||
|
||||
// An acceptable threshold of request (successful or unsuccessful) is defined then the requests
|
||||
// are rejected (they are not even processed)
|
||||
ANY(u64),
|
||||
}
|
||||
|
||||
impl LimitPolicy {
|
||||
pub fn is_none(&self) -> bool {
|
||||
matches!(self, LimitPolicy::NONE)
|
||||
}
|
||||
|
||||
pub fn get_count(&self) -> u64 {
|
||||
match self {
|
||||
LimitPolicy::NONE => 0,
|
||||
LimitPolicy::SUCCESS(n) => n.clone(),
|
||||
LimitPolicy::FAILURE(n) => n.clone(),
|
||||
LimitPolicy::ANY(n) => n.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Define types
|
||||
pub type RequestResult = Result<(), Box<dyn Error>>;
|
||||
pub type RequestProcess = Box<dyn Fn(&mut HttpRequestHandler) -> RequestResult>;
|
||||
|
||||
pub struct Route {
|
||||
/// The Verb used for the request
|
||||
pub method: Method,
|
||||
|
||||
/// The URI of the request, with the leading "/"
|
||||
pub uri: &'static str,
|
||||
|
||||
/// If set to true, unauthenticated requests will be rejected
|
||||
pub need_login: bool,
|
||||
|
||||
/// The function called to process a request
|
||||
pub func: RequestProcess,
|
||||
|
||||
/// Request rate policy
|
||||
pub limit_policy: LimitPolicy,
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn get_without_login(uri: &'static str, func: RequestProcess) -> Route {
|
||||
Route {
|
||||
method: GET,
|
||||
need_login: false,
|
||||
uri,
|
||||
func,
|
||||
limit_policy: LimitPolicy::NONE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post_without_login(uri: &'static str, func: RequestProcess) -> Route {
|
||||
Route {
|
||||
method: POST,
|
||||
need_login: false,
|
||||
uri,
|
||||
func,
|
||||
limit_policy: LimitPolicy::NONE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limited_post_without_login(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
|
||||
Route {
|
||||
method: POST,
|
||||
need_login: false,
|
||||
uri,
|
||||
func,
|
||||
limit_policy,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post(uri: &'static str, func: RequestProcess) -> Route {
|
||||
Route {
|
||||
method: POST,
|
||||
need_login: true,
|
||||
uri,
|
||||
func,
|
||||
limit_policy: LimitPolicy::NONE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limited_post(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
|
||||
Route {
|
||||
method: POST,
|
||||
need_login: true,
|
||||
uri,
|
||||
func,
|
||||
limit_policy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the list of routes available
|
||||
pub fn get_routes() -> Vec<Route> {
|
||||
vec![
|
||||
// Server meta routes
|
||||
Route::get_without_login("/", Box::new(server_controller::main_index)),
|
||||
|
||||
// Main user WebSocket
|
||||
Route::post("/ws/token", Box::new(user_ws_controller::get_token)),
|
||||
|
||||
// Account controller
|
||||
Route::limited_post_without_login("/account/create", Box::new(account_controller::create), LimitPolicy::SUCCESS(10)),
|
||||
Route::limited_post_without_login("/account/login", Box::new(account_controller::login_user), LimitPolicy::FAILURE(10)),
|
||||
Route::limited_post_without_login("/user/connectUSER", Box::new(account_controller::login_user), LimitPolicy::FAILURE(10)), // TODO : remove
|
||||
Route::post("/account/logout", Box::new(account_controller::logout_user)),
|
||||
Route::post("/user/disconnectUSER", Box::new(account_controller::logout_user)), // TODO : remove
|
||||
Route::post("/account/disconnect_all_devices", Box::new(account_controller::disconnect_all_devices)),
|
||||
Route::post("/account/id", Box::new(account_controller::user_id)),
|
||||
Route::post("/user/getCurrentUserID", Box::new(account_controller::user_id)), // TODO : remove
|
||||
Route::limited_post_without_login("/account/exists_email", Box::new(account_controller::exists_mail), LimitPolicy::ANY(30)),
|
||||
Route::limited_post_without_login("/account/has_security_questions", Box::new(account_controller::has_security_questions), LimitPolicy::FAILURE(10)),
|
||||
Route::limited_post_without_login("/account/get_security_questions", Box::new(account_controller::get_security_questions), LimitPolicy::FAILURE(10)),
|
||||
Route::limited_post_without_login("/account/check_security_answers", Box::new(account_controller::check_security_answers), LimitPolicy::FAILURE(10)),
|
||||
Route::limited_post_without_login("/account/check_password_reset_token", Box::new(account_controller::check_password_reset_token), LimitPolicy::FAILURE(10)),
|
||||
Route::limited_post_without_login("/account/reset_user_passwd", Box::new(account_controller::reset_user_password), LimitPolicy::FAILURE(10)),
|
||||
Route::limited_post("/account/export_data", Box::new(account_controller::export_data), LimitPolicy::ANY(10)),
|
||||
Route::post("/account/delete", Box::new(account_controller::delete_account)),
|
||||
|
||||
// User controller
|
||||
Route::post("/user/getInfo", Box::new(user_controller::get_single)),
|
||||
Route::post("/user/getInfos", Box::new(user_controller::get_single)),
|
||||
Route::post("/user/getInfoMultiple", Box::new(user_controller::get_multiple)),
|
||||
Route::post("/user/getInfosMultiple", Box::new(user_controller::get_multiple)),
|
||||
Route::post("/user/getAdvancedUserInfo", Box::new(user_controller::get_advanced_info)),
|
||||
Route::post("/user/getAdvancedUserInfos", Box::new(user_controller::get_advanced_info)),
|
||||
|
||||
// Settings controller
|
||||
Route::post("/settings/get_general", Box::new(settings_controller::get_general)),
|
||||
Route::post("/settings/set_general", Box::new(settings_controller::set_general)),
|
||||
Route::post("/settings/check_user_directory_availability", Box::new(settings_controller::check_virtual_directory)),
|
||||
Route::post("/settings/get_language", Box::new(settings_controller::get_language)),
|
||||
Route::post("/settings/set_language", Box::new(settings_controller::set_language)),
|
||||
Route::post("/settings/get_security", Box::new(settings_controller::get_security)),
|
||||
Route::post("/settings/set_security", Box::new(settings_controller::set_security)),
|
||||
Route::post("/settings/check_password", Box::new(settings_controller::check_password)),
|
||||
Route::post("/settings/update_password", Box::new(settings_controller::update_password)),
|
||||
Route::post("/settings/get_account_image", Box::new(settings_controller::get_account_image_settings)),
|
||||
Route::post("/settings/upload_account_image", Box::new(settings_controller::upload_account_image)),
|
||||
Route::post("/settings/delete_account_image", Box::new(settings_controller::delete_account_image)),
|
||||
Route::post("/settings/set_account_image_visibility", Box::new(settings_controller::set_account_image_visibility)),
|
||||
Route::post("/settings/upload_custom_emoji", Box::new(settings_controller::upload_custom_emoji)),
|
||||
Route::post("/settings/delete_custom_emoji", Box::new(settings_controller::delete_custom_emoji)),
|
||||
|
||||
|
||||
// Friends controller
|
||||
Route::post("/friends/getList", Box::new(friends_controller::get_list)),
|
||||
Route::post("/friends/get_single_infos", Box::new(friends_controller::get_single_friendship_info)),
|
||||
Route::post("/friends/get_user_list", Box::new(friends_controller::get_other_user_list)),
|
||||
Route::post("/friends/getStatus", Box::new(friends_controller::get_status)),
|
||||
Route::post("/friends/sendRequest", Box::new(friends_controller::send_request)),
|
||||
Route::post("/friends/removeRequest", Box::new(friends_controller::cancel_request)),
|
||||
Route::post("/friends/respondRequest", Box::new(friends_controller::respond_request)),
|
||||
Route::post("/friends/remove", Box::new(friends_controller::remove_friend)),
|
||||
Route::post("/friends/setFollowing", Box::new(friends_controller::set_following)),
|
||||
Route::post("/friends/set_can_post_texts", Box::new(friends_controller::set_can_post_texts)),
|
||||
|
||||
|
||||
// Conversations controller
|
||||
Route::post("/conversations/create", Box::new(conversations_controller::create)),
|
||||
Route::post("/conversations/getList", Box::new(conversations_controller::get_list)),
|
||||
Route::post("/conversations/getInfoOne", Box::new(conversations_controller::get_single)),
|
||||
Route::post("/conversations/getInfosOne", Box::new(conversations_controller::get_single)),
|
||||
Route::post("/conversations/updateSettings", Box::new(conversations_controller::update_settings)),
|
||||
Route::post("/conversations/getPrivate", Box::new(conversations_controller::find_private)),
|
||||
Route::post("/conversations/refresh", Box::new(conversations_controller::refresh_list)),
|
||||
Route::post("/conversations/refresh_single", Box::new(conversations_controller::refresh_single)),
|
||||
Route::post("/conversations/get_older_messages", Box::new(conversations_controller::get_older_messages)),
|
||||
Route::post("/conversations/sendMessage", Box::new(conversations_controller::send_message)),
|
||||
Route::post("/conversations/get_number_unread", Box::new(conversations_controller::count_unread)),
|
||||
Route::post("/conversations/get_list_unread", Box::new(conversations_controller::list_unread)),
|
||||
Route::post("/conversations/delete", Box::new(conversations_controller::delete_conversation)),
|
||||
Route::post("/conversations/updateMessage", Box::new(conversations_controller::update_message)),
|
||||
Route::post("/conversations/deleteMessage", Box::new(conversations_controller::delete_message)),
|
||||
|
||||
|
||||
// Search controller
|
||||
Route::post("/search/user", Box::new(search_controller::search_user)),
|
||||
Route::post("/user/search", Box::new(search_controller::search_user)),
|
||||
Route::post("/search/global", Box::new(search_controller::search_global)),
|
||||
|
||||
|
||||
// Groups controller
|
||||
Route::post("/groups/create", Box::new(groups_controller::create)),
|
||||
Route::post("/groups/get_my_list", Box::new(groups_controller::get_list_user)),
|
||||
Route::post("/groups/get_info", Box::new(groups_controller::get_info_single)),
|
||||
Route::post("/groups/get_multiple_info", Box::new(groups_controller::get_info_multiple)),
|
||||
Route::post("/groups/get_advanced_info", Box::new(groups_controller::get_advanced_info)),
|
||||
Route::post("/groups/get_settings", Box::new(groups_controller::get_settings)),
|
||||
Route::post("/groups/set_settings", Box::new(groups_controller::set_settings)),
|
||||
Route::post("/groups/checkVirtualDirectory", Box::new(groups_controller::check_virtual_dir)),
|
||||
Route::post("/groups/upload_logo", Box::new(groups_controller::upload_logo)),
|
||||
Route::post("/groups/delete_logo", Box::new(groups_controller::delete_logo)),
|
||||
Route::post("/groups/get_members", Box::new(groups_controller::get_members)),
|
||||
Route::post("/groups/invite", Box::new(groups_controller::invite_user)),
|
||||
Route::post("/groups/cancel_invitation", Box::new(groups_controller::cancel_invitation)),
|
||||
Route::post("/groups/respond_invitation", Box::new(groups_controller::respond_invitation)),
|
||||
Route::post("/groups/send_request", Box::new(groups_controller::send_request)),
|
||||
Route::post("/groups/cancel_request", Box::new(groups_controller::cancel_request)),
|
||||
Route::post("/groups/delete_member", Box::new(groups_controller::delete_member)),
|
||||
Route::post("/groups/update_membership_level", Box::new(groups_controller::update_membership)),
|
||||
Route::post("/groups/respond_request", Box::new(groups_controller::respond_request)),
|
||||
Route::post("/groups/get_membership", Box::new(groups_controller::get_membership)),
|
||||
Route::post("/groups/remove_membership", Box::new(groups_controller::remove_membership)),
|
||||
Route::post("/groups/set_following", Box::new(groups_controller::set_following)),
|
||||
Route::limited_post("/groups/delete", Box::new(groups_controller::delete_group), LimitPolicy::FAILURE(10)),
|
||||
|
||||
|
||||
// Posts controller
|
||||
Route::post("/posts/get_user", Box::new(posts_controller::get_list_user)),
|
||||
Route::post("/posts/get_group", Box::new(posts_controller::get_list_group)),
|
||||
Route::post("/posts/get_latest", Box::new(posts_controller::get_latest)),
|
||||
Route::post("/posts/get_single", Box::new(posts_controller::get_single)),
|
||||
Route::post("/posts/create", Box::new(posts_controller::create_post)),
|
||||
Route::post("/posts/set_visibility_level", Box::new(posts_controller::set_visibility_level)),
|
||||
Route::post("/posts/update_content", Box::new(posts_controller::update_content)),
|
||||
Route::post("/posts/delete", Box::new(posts_controller::delete)),
|
||||
Route::post("/posts/getAvailableTargets", Box::new(posts_controller::get_targets)),
|
||||
|
||||
|
||||
// Comments controller
|
||||
Route::post("/comments/create", Box::new(comments_controller::create)),
|
||||
Route::post("/comments/get_single", Box::new(comments_controller::get_single)),
|
||||
Route::post("/comments/edit", Box::new(comments_controller::edit)),
|
||||
Route::post("/comments/delete", Box::new(comments_controller::delete)),
|
||||
|
||||
|
||||
// Likes controller
|
||||
Route::post("/likes/update", Box::new(likes_controller::update)),
|
||||
|
||||
|
||||
// Surveys controller
|
||||
Route::post("/surveys/get_info", Box::new(surveys_controller::get_info_single)),
|
||||
Route::post("/surveys/send_response", Box::new(surveys_controller::send_response)),
|
||||
Route::post("/surveys/cancel_response", Box::new(surveys_controller::cancel_response)),
|
||||
Route::post("/surveys/create_new_choice", Box::new(surveys_controller::create_new_choice)),
|
||||
Route::post("/surveys/block_new_choices_creation", Box::new(surveys_controller::block_new_choices_creation)),
|
||||
|
||||
|
||||
// Notifications controller
|
||||
Route::post("/notifications/count_unread", Box::new(notifications_controller::count_unread)),
|
||||
Route::post("/notifications/count_all_news", Box::new(notifications_controller::count_all_news)),
|
||||
Route::post("/notifications/get_list_unread", Box::new(notifications_controller::get_list_unread)),
|
||||
Route::post("/notifications/mark_seen", Box::new(notifications_controller::mark_seen)),
|
||||
Route::post("/notifications/delete_all", Box::new(notifications_controller::delete_all)),
|
||||
|
||||
|
||||
// Virtual directory controller
|
||||
Route::post("/user/findbyfolder", Box::new(virtual_directory_controller::find_user)),
|
||||
Route::post("/virtualDirectory/find", Box::new(virtual_directory_controller::find)),
|
||||
|
||||
|
||||
// Web application controller
|
||||
Route::post("/webApp/getMemberships", Box::new(web_app_controller::get_memberships)),
|
||||
|
||||
// Calls controller
|
||||
Route::post("/calls/config", Box::new(calls_controller::get_legacy_config)),
|
||||
]
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::api_data::global_search_result_api::GlobalSearchResultAPI;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::global_search_result::GlobalSearchResult;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
|
@ -1,328 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
use std::pin::Pin;
|
||||
|
||||
use actix_web::{App, FromRequest, http, HttpMessage, HttpRequest, HttpResponse, HttpServer, web};
|
||||
use actix_web::dev::{Decompress, Payload, PayloadStream};
|
||||
use actix_web::error::{ErrorBadRequest, ErrorInternalServerError, PayloadError};
|
||||
use actix_web::web::{Bytes, BytesMut};
|
||||
use bytes::{Buf, BufMut};
|
||||
use encoding_rs::UTF_8;
|
||||
use futures::{FutureExt, Stream, StreamExt};
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::task::{Context, Poll};
|
||||
use percent_encoding::percent_decode_str;
|
||||
|
||||
use crate::api_data::http_error::HttpError;
|
||||
use crate::constants::MAX_REQUEST_SIZE;
|
||||
use crate::controllers::{rtc_relay_controller, user_ws_controller};
|
||||
use crate::controllers::routes::{get_routes, RequestResult, Route};
|
||||
use crate::controllers::routes::Method::{GET, POST};
|
||||
use crate::data::base_request_handler::{BaseRequestHandler, PostFile, RequestValue};
|
||||
use crate::data::config::Config;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::helpers::requests_limit_helper;
|
||||
|
||||
/// Main server functions
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
/// Custom stream to give a limit to requests size
|
||||
struct LimitedStream {
|
||||
stream: Box<dyn Stream<Item=Result<Bytes, PayloadError>> + Unpin + 'static>,
|
||||
already_read: usize,
|
||||
max_size: usize,
|
||||
}
|
||||
|
||||
impl<'a> Stream for LimitedStream
|
||||
{
|
||||
type Item = Result<Bytes, PayloadError>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
if self.already_read >= self.max_size {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
|
||||
let res = Pin::new(self.stream.as_mut()).poll_next(cx);
|
||||
|
||||
if let Poll::Ready(Some(Ok(d))) = &res {
|
||||
self.already_read = self.already_read + d.len();
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom request value
|
||||
struct CustomRequest {
|
||||
req: web::HttpRequest,
|
||||
body: HashMap<String, RequestValue>,
|
||||
}
|
||||
|
||||
/// Process in our way incoming requests
|
||||
impl FromRequest for CustomRequest {
|
||||
type Error = actix_web::Error;
|
||||
type Future = LocalBoxFuture<'static, Result<CustomRequest, actix_web::Error>>;
|
||||
type Config = ();
|
||||
|
||||
fn from_request(req: &HttpRequest, payload: &mut Payload<PayloadStream>) -> Self::Future {
|
||||
let req = req.clone();
|
||||
let payload = Box::new(payload.take());
|
||||
|
||||
async move {
|
||||
let content_length_size;
|
||||
|
||||
// Check the size, if provided
|
||||
if req.headers().contains_key("Content-Length") {
|
||||
if let Some(v) = req.headers().get("Content-Length") {
|
||||
content_length_size = String::from_utf8_lossy(v.as_bytes()).parse::<usize>().unwrap_or(0);
|
||||
if content_length_size > MAX_REQUEST_SIZE {
|
||||
return Err(actix_web::error::ErrorBadRequest("Request too big!"));
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
} else {
|
||||
return Err(actix_web::error::ErrorBadRequest("Content-Length header is required!"));
|
||||
}
|
||||
|
||||
let payload = LimitedStream {
|
||||
stream: payload,
|
||||
already_read: 0,
|
||||
max_size: content_length_size,
|
||||
};
|
||||
|
||||
|
||||
let mut body_args = HashMap::new();
|
||||
|
||||
// Process "application/x-www-form-urlencoded" requests
|
||||
if req.content_type().eq("application/x-www-form-urlencoded") {
|
||||
|
||||
// Maximum size of the request
|
||||
let limit = 16384;
|
||||
|
||||
// Ready body
|
||||
let mut body = BytesMut::with_capacity(8192);
|
||||
let mut stream = Decompress::from_headers(payload, req.headers());
|
||||
while let Some(item) = stream.next().await {
|
||||
let chunk = item?;
|
||||
|
||||
|
||||
if body.len() + chunk.len() > limit {
|
||||
return Err(actix_web::error::ErrorBadRequest("Overflow - too long"));
|
||||
} else {
|
||||
body.extend_from_slice(&chunk);
|
||||
}
|
||||
}
|
||||
let body = body.freeze();
|
||||
|
||||
|
||||
// Decode body as a string
|
||||
let encoding = req.encoding()?;
|
||||
|
||||
let body_str = if encoding == UTF_8 {
|
||||
String::from_utf8_lossy(body.as_ref()).to_string()
|
||||
} else {
|
||||
encoding
|
||||
.decode_without_bom_handling_and_without_replacement(&body)
|
||||
.map(|s| s.into_owned())
|
||||
.ok_or_else(|| ErrorBadRequest("Can not decode body"))?
|
||||
};
|
||||
|
||||
// Parse body arguments (following the pattern key1=value1&key2=value2)
|
||||
if body_str.len() > 0 {
|
||||
for v in body_str.split("&") {
|
||||
if v.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let args: Vec<&str> = v.split("=").collect();
|
||||
|
||||
if args.len() != 2 {
|
||||
return Err(actix_web::error::ErrorBadRequest(format!("{} is invalid!", args[0])));
|
||||
}
|
||||
|
||||
// Add the value to the body
|
||||
body_args.insert(
|
||||
percent_decode_str(args[0]).decode_utf8_lossy().to_string(),
|
||||
RequestValue::String(percent_decode_str(args[1]).decode_utf8_lossy().to_string()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Process "multipart/form-data" request
|
||||
else if req.content_type().starts_with("multipart/form-data") {
|
||||
let mut req = actix_multipart::Multipart::new(req.headers(), payload);
|
||||
|
||||
// Process the list of arguments
|
||||
while let Some(el) = req.next().await {
|
||||
let mut field = el?;
|
||||
|
||||
let content_type = field.content_disposition().ok_or(
|
||||
ErrorInternalServerError("Missing content type"))?;
|
||||
let name = content_type.get_name().ok_or(
|
||||
ErrorInternalServerError("Missing field name!"))?;
|
||||
|
||||
// Handle file upload
|
||||
if content_type.get_filename().is_some() {
|
||||
let filename = content_type.get_filename().unwrap();
|
||||
let mut buf = BytesMut::new();
|
||||
|
||||
while let Some(chunk) = field.next().await {
|
||||
let data = chunk.unwrap();
|
||||
buf.put(data);
|
||||
}
|
||||
|
||||
body_args.insert(name.to_string(),
|
||||
RequestValue::File(PostFile {
|
||||
name: filename.to_string(),
|
||||
buff: buf.to_bytes(),
|
||||
}));
|
||||
}
|
||||
|
||||
// It is a simple field
|
||||
else {
|
||||
let mut content = String::new();
|
||||
|
||||
// Get content
|
||||
while let Some(chunk) = field.next().await {
|
||||
content = format!("{}{}", content, String::from_utf8_lossy(chunk?.bytes()));
|
||||
}
|
||||
|
||||
body_args.insert(name.to_string(), RequestValue::String(content));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CustomRequest {
|
||||
req: req.clone(),
|
||||
body: body_args,
|
||||
})
|
||||
}.boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a "simple request" aka not a WebSocket request
|
||||
fn process_simple_route(route: &Route, req: &mut HttpRequestHandler) -> RequestResult {
|
||||
if requests_limit_helper::trigger_before(req, route).is_err() {
|
||||
req.too_many_requests("Too many request. Please try again later.")?;
|
||||
}
|
||||
|
||||
// Validate client token
|
||||
req.check_client_token()?;
|
||||
|
||||
// Check user token, if required
|
||||
if route.need_login || req.has_post_parameter("userToken1") {
|
||||
req.check_user_token()?;
|
||||
}
|
||||
|
||||
let res: RequestResult = (route.func)(req);
|
||||
|
||||
requests_limit_helper::trigger_after(res.is_ok(), req, route)?;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// Process an incoming request
|
||||
async fn process_request(custom_req: CustomRequest) -> HttpResponse {
|
||||
let req = &custom_req.req;
|
||||
let routes = get_routes();
|
||||
|
||||
// We search the appropriate route for the request
|
||||
let mut route: Option<&Route> = None;
|
||||
for el in &routes {
|
||||
|
||||
// Check verb
|
||||
if !(req.method() == http::Method::GET && el.method == GET) &&
|
||||
!(req.method() == http::Method::POST && el.method == POST) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check path
|
||||
if !el.uri.eq(req.uri()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
route = Some(el);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if a route was found
|
||||
if let None = route {
|
||||
return HttpResponse::NotFound().json(HttpError::not_found("Method not found!"));
|
||||
}
|
||||
let route = route.unwrap();
|
||||
|
||||
// Clean requests limit
|
||||
requests_limit_helper::clean_cache().unwrap();
|
||||
|
||||
// Execute the request
|
||||
let mut request = HttpRequestHandler::new(custom_req.req, custom_req.body);
|
||||
|
||||
match process_simple_route(route, &mut request) {
|
||||
|
||||
// Set default error response if required
|
||||
Err(e) => {
|
||||
let err_msg = e.to_string();
|
||||
|
||||
if !request.has_response() {
|
||||
request.internal_error(e).unwrap_err();
|
||||
}
|
||||
|
||||
println!("{} - {} - {} - {}",
|
||||
request.remote_ip(),
|
||||
request.response_status_code(),
|
||||
request.request_path(),
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
// Set default success response if required
|
||||
Ok(_) => {
|
||||
if !request.has_response() {
|
||||
request.success("Success").unwrap()
|
||||
}
|
||||
|
||||
println!("{} - {} - {}",
|
||||
request.remote_ip(),
|
||||
request.response_status_code(),
|
||||
request.request_path()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Send the response
|
||||
match request.response() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
println!("Error while getting response: {}", e);
|
||||
HttpResponse::InternalServerError().body("Response error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Given the configuration, start the server
|
||||
pub async fn start_server(conf: &Config) -> std::io::Result<()> {
|
||||
|
||||
// Initialize limit helper
|
||||
requests_limit_helper::init();
|
||||
|
||||
let addr = conf.server_listen_address();
|
||||
println!("Start to listen on http://{}/", addr);
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
|
||||
// User WebSocket route
|
||||
.service(actix_web::web::resource("/ws").to(user_ws_controller::ws_route))
|
||||
|
||||
// RTC Relay WebSocket route
|
||||
.service(actix_web::web::resource("/rtc_proxy/ws").to(rtc_relay_controller::open_ws))
|
||||
|
||||
// API routes
|
||||
.route("**", web::get().to(process_request))
|
||||
.route("**", web::post().to(process_request))
|
||||
}).bind(&addr)?.run().await
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::routes::RequestResult;
|
||||
|
||||
/// Main server controller
|
||||
///
|
||||
|
@ -8,7 +8,7 @@ use crate::api_data::language_settings_api::LanguageSettingsAPI;
|
||||
use crate::api_data::res_create_custom_emoji::ResCreateCustomEmoji;
|
||||
use crate::api_data::security_settings_api::SecuritySettingsAPI;
|
||||
use crate::constants::SUPPORTED_LANGUAGES;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::general_settings::GeneralSettings;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use crate::api_data::survey_api::SurveyAPI;
|
||||
use crate::constants::MAXIMUM_NUMBER_SURVEY_CHOICES;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::ResultBoxError;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
|
@ -7,7 +7,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::api_data::user_info::APIUserInfo;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::data::user::UserID;
|
||||
|
@ -14,7 +14,6 @@ use serde_json::Value;
|
||||
use crate::api_data::res_get_ws_token::ResGetWsToken;
|
||||
use crate::constants::{USER_LAST_ACTIVITY_REFRESH, WS_ACCESS_TOKEN_LENGTH};
|
||||
use crate::controllers::user_ws_controller::ws_connections_list::{add_connection, find_connection, get_ws_connections_list, remove_connection};
|
||||
use crate::controllers::user_ws_routes::find_user_ws_route;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::config::conf;
|
||||
use crate::data::error::{ExecError, Res, ResultBoxError};
|
||||
@ -26,6 +25,7 @@ use crate::data::user_ws_message::UserWsMessage;
|
||||
use crate::data::user_ws_request_handler::{UserWsRequestHandler, UserWsResponseType};
|
||||
use crate::helpers::{account_helper, events_helper};
|
||||
use crate::helpers::events_helper::Event;
|
||||
use crate::user_ws_routes::find_user_ws_route;
|
||||
use crate::utils::crypt_utils::rand_str;
|
||||
use crate::utils::date_utils::time;
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
//! # WebSocket routes
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::controllers::{calls_controller, likes_controller, user_ws_actions};
|
||||
use crate::data::error::Res;
|
||||
use crate::data::user_ws_request_handler::UserWsRequestHandler;
|
||||
|
||||
pub type WsRequestProcess = Box<dyn Fn(&mut UserWsRequestHandler) -> Res>;
|
||||
|
||||
/// WebSocket route
|
||||
pub struct UserWsRoute {
|
||||
pub route: String,
|
||||
pub handler: WsRequestProcess,
|
||||
}
|
||||
|
||||
impl UserWsRoute {
|
||||
pub fn new<H>(route: &str, handler: H) -> UserWsRoute
|
||||
where H: 'static + Fn(&mut UserWsRequestHandler) -> Res {
|
||||
UserWsRoute {
|
||||
route: route.to_string(),
|
||||
handler: Box::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the list of available WebSocket routes
|
||||
pub fn get_user_ws_routes() -> Vec<UserWsRoute> {
|
||||
vec![
|
||||
// Main controller
|
||||
UserWsRoute::new("$main/set_incognito", user_ws_actions::set_incognito),
|
||||
UserWsRoute::new("$main/register_conv", user_ws_actions::register_conv),
|
||||
UserWsRoute::new("$main/unregister_conv", user_ws_actions::unregister_conv),
|
||||
UserWsRoute::new("$main/register_post", user_ws_actions::register_post),
|
||||
UserWsRoute::new("$main/unregister_post", user_ws_actions::unregister_post),
|
||||
|
||||
// Likes controller
|
||||
UserWsRoute::new("likes/update", likes_controller::update),
|
||||
|
||||
// Calls controller
|
||||
UserWsRoute::new("calls/config", calls_controller::get_config),
|
||||
UserWsRoute::new("calls/join", calls_controller::join_call),
|
||||
UserWsRoute::new("calls/leave", calls_controller::leave_call),
|
||||
UserWsRoute::new("calls/members", calls_controller::get_members_list),
|
||||
UserWsRoute::new("calls/signal", calls_controller::on_client_signal),
|
||||
UserWsRoute::new("calls/mark_ready", calls_controller::mark_user_ready),
|
||||
UserWsRoute::new("calls/request_offer", calls_controller::request_offer),
|
||||
UserWsRoute::new("calls/stop_streaming", calls_controller::stop_streaming),
|
||||
]
|
||||
}
|
||||
|
||||
/// Search for a route
|
||||
pub fn find_user_ws_route(uri: &str) -> Option<UserWsRoute> {
|
||||
get_user_ws_routes().into_iter().find(|r| r.route == uri)
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
use crate::api_data::res_find_user_by_virtual_directory::FindUserByVirtualDirectoryAPIResult;
|
||||
use crate::api_data::res_find_virtual_directory::ResultFindVirtualDirectory;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::helpers::{groups_helper, user_helper};
|
||||
|
@ -3,10 +3,10 @@
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::api_data::user_membership_api::UserMembershipAPI;
|
||||
use crate::controllers::routes::RequestResult;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::helpers::webapp_helper;
|
||||
use crate::routes::RequestResult;
|
||||
|
||||
/// Get the list of memberships of a given user
|
||||
pub fn get_memberships(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
|
Reference in New Issue
Block a user