You've already forked AstralRinth
forked from didirus/AstralRinth
Improve error handling (#33)
* refactor: improve error handling * fix: specify bind address instead of port * fix: remove temporary testing file * fix(errors): change error names to snake_case * refactor(errors): split indexing error types, remove unused errors * feat: add env variable checking at program start This just checks whether the enviroment variables exist and can parse to the given type and gives a warning if they can't. This should prevent cases where the program fails at runtime due to checking an environment variable that doesn't exist.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use crate::database::DatabaseError;
|
||||
use crate::models::error::ApiError;
|
||||
use crate::models::mods::SearchRequest;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::HttpResponse;
|
||||
use meilisearch_sdk::client::Client;
|
||||
use meilisearch_sdk::document::Document;
|
||||
use meilisearch_sdk::search::Query;
|
||||
@@ -10,24 +12,39 @@ pub mod indexing;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SearchError {
|
||||
#[error("Error while connection to the MeiliSearch database")]
|
||||
IndexDBError(),
|
||||
#[error("Error while connecting to the local server")]
|
||||
LocalDatabaseError(#[from] mongodb::error::Error),
|
||||
#[error("Error while accessing the data from remote")]
|
||||
RemoteWebsiteError(#[from] reqwest::Error),
|
||||
#[error("Error while serializing or deserializing JSON")]
|
||||
#[error("Error while connecting to the MeiliSearch database")]
|
||||
IndexDBError(meilisearch_sdk::errors::Error),
|
||||
#[error("Error while serializing or deserializing JSON: {0}")]
|
||||
SerDeError(#[from] serde_json::Error),
|
||||
#[error("Error while parsing float")]
|
||||
FloatParsingError(#[from] std::num::ParseFloatError),
|
||||
#[error("Error while parsing float")]
|
||||
#[error("Error while parsing an integer: {0}")]
|
||||
IntParsingError(#[from] std::num::ParseIntError),
|
||||
#[error("Error while parsing BSON")]
|
||||
DatabaseError(#[from] DatabaseError),
|
||||
#[error("Environment Error")]
|
||||
EnvError(#[from] dotenv::Error),
|
||||
}
|
||||
|
||||
impl actix_web::ResponseError for SearchError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
SearchError::EnvError(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
SearchError::IndexDBError(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
SearchError::SerDeError(..) => StatusCode::BAD_REQUEST,
|
||||
SearchError::IntParsingError(..) => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(self.status_code()).json(ApiError {
|
||||
error: match self {
|
||||
SearchError::EnvError(..) => "environment_error",
|
||||
SearchError::IndexDBError(..) => "indexdb_error",
|
||||
SearchError::SerDeError(..) => "invalid_input",
|
||||
SearchError::IntParsingError(..) => "invalid_input",
|
||||
},
|
||||
description: &self.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct SearchMod {
|
||||
pub mod_id: i32,
|
||||
@@ -57,38 +74,24 @@ impl Document for SearchMod {
|
||||
}
|
||||
|
||||
pub fn search_for_mod(info: &SearchRequest) -> Result<Vec<SearchMod>, SearchError> {
|
||||
use std::borrow::Cow;
|
||||
let address = &*dotenv::var("MEILISEARCH_ADDR")?;
|
||||
let client = Client::new(address, "");
|
||||
|
||||
let search_query: &str;
|
||||
let mut filters = String::new();
|
||||
let mut offset = 0;
|
||||
let mut index = "relevance";
|
||||
let filters: Cow<_> = match (info.filters.as_deref(), info.version.as_deref()) {
|
||||
(Some(f), Some(v)) => format!("({}) AND ({})", f, v).into(),
|
||||
(Some(f), None) => f.into(),
|
||||
(None, Some(v)) => v.into(),
|
||||
(None, None) => "".into(),
|
||||
};
|
||||
|
||||
match info.query.as_ref() {
|
||||
Some(q) => search_query = q,
|
||||
None => search_query = "{}{}{}",
|
||||
}
|
||||
|
||||
if let Some(f) = info.filters.as_ref() {
|
||||
filters = f.clone();
|
||||
}
|
||||
|
||||
if let Some(v) = info.version.as_ref() {
|
||||
if filters.is_empty() {
|
||||
filters = v.clone();
|
||||
} else {
|
||||
filters = format!("({}) AND ({})", filters, v);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(o) = info.offset.as_ref() {
|
||||
offset = o.parse().unwrap();
|
||||
}
|
||||
|
||||
if let Some(s) = info.index.as_ref() {
|
||||
index = s;
|
||||
}
|
||||
let offset = info.offset.as_deref().unwrap_or("0").parse()?;
|
||||
let index = info.index.as_deref().unwrap_or("relevance");
|
||||
let search_query: &str = info
|
||||
.query
|
||||
.as_deref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or("{}{}{}");
|
||||
|
||||
let mut query = Query::new(search_query).with_limit(10).with_offset(offset);
|
||||
|
||||
@@ -98,8 +101,8 @@ pub fn search_for_mod(info: &SearchRequest) -> Result<Vec<SearchMod>, SearchErro
|
||||
|
||||
Ok(client
|
||||
.get_index(format!("{}_mods", index).as_ref())
|
||||
.unwrap()
|
||||
.map_err(SearchError::IndexDBError)?
|
||||
.search::<SearchMod>(&query)
|
||||
.unwrap()
|
||||
.map_err(SearchError::IndexDBError)?
|
||||
.hits)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user