diff --git a/meilisearch-http/Cargo.toml b/meilisearch-http/Cargo.toml index c7331b871..e3c858980 100644 --- a/meilisearch-http/Cargo.toml +++ b/meilisearch-http/Cargo.toml @@ -14,6 +14,13 @@ name = "meilisearch" path = "src/main.rs" [dependencies] +actix-cors = "0.2.0" +actix-files = "0.2.1" +actix-http = "1" +actix-rt = "1" +actix-service = "1.0.5" +actix-web = "2" +actix-web-macros = "0.1.0" chrono = { version = "0.4.11", features = ["serde"] } crossbeam-channel = "0.4.2" env_logger = "0.7.1" @@ -34,20 +41,13 @@ serde_json = { version = "1.0.50", features = ["preserve_order"] } serde_qs = "0.5.2" sha2 = "0.8.1" siphasher = "0.3.2" +slice-group-by = "0.2.6" structopt = "0.3.12" sysinfo = "0.12.0" +tokio = { version = "0.2.18", features = ["macros"] } ureq = { version = "0.12.0", features = ["tls"], default-features = false } walkdir = "2.3.1" whoami = "0.8.1" -slice-group-by = "0.2.6" -actix-rt = "1" -actix-web = "2" -actix-http = "1" -actix-files = "0.2.1" -actix-cors = "0.2.0" -actix-service = "1.0.5" -actix-web-macros = "0.1.0" -tokio = { version = "0.2.18", features = ["macros"] } [dev-dependencies] http-service = "0.4.0" diff --git a/meilisearch-http/src/data.rs b/meilisearch-http/src/data.rs index 97a3526a7..cdfdfb80d 100644 --- a/meilisearch-http/src/data.rs +++ b/meilisearch-http/src/data.rs @@ -37,7 +37,7 @@ pub struct DataInner { pub server_pid: Pid, } -#[derive(Default, Clone)] +#[derive(Clone)] pub struct ApiKeys { pub public: Option, pub private: Option, diff --git a/meilisearch-http/src/error.rs b/meilisearch-http/src/error.rs index db0ce6c2d..638726ece 100644 --- a/meilisearch-http/src/error.rs +++ b/meilisearch-http/src/error.rs @@ -91,11 +91,11 @@ impl fmt::Display for ResponseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::BadParameter(param, err) => write!(f, "Url parameter {} error: {}", param, err), - Self::BadRequest(err) => write!(f, "{}", err), + Self::BadRequest(err) => f.write_str(err), Self::CreateIndex(err) => write!(f, "Impossible to create index; {}", err), Self::DocumentNotFound(document_id) => write!(f, "Document with id {} not found", document_id), Self::IndexNotFound(index_uid) => write!(f, "Index {} not found", index_uid), - Self::Internal(err) => write!(f, "{}", err), + Self::Internal(err) => f.write_str(err), Self::InvalidIndexUid => f.write_str("Index must have a valid uid; Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_)."), Self::InvalidToken(err) => write!(f, "Invalid API key: {}", err), Self::Maintenance => f.write_str("Server is in maintenance, please try again later"), diff --git a/meilisearch-http/src/helpers/authentication.rs b/meilisearch-http/src/helpers/authentication.rs index f91b7c3c5..f42898683 100644 --- a/meilisearch-http/src/helpers/authentication.rs +++ b/meilisearch-http/src/helpers/authentication.rs @@ -33,7 +33,7 @@ where fn new_transform(&self, service: S) -> Self::Future { ok(LoggingMiddleware { - acl: (*self).clone(), + acl: self.clone(), service: Rc::new(RefCell::new(service)), }) } @@ -61,6 +61,8 @@ where fn call(&mut self, req: ServiceRequest) -> Self::Future { let mut svc = self.service.clone(); + // This unwrap is left because this error should never appear. If that's the case, then + // it means that actix-web has an issue or someone changes the type `Data`. let data = req.app_data::().unwrap(); if data.api_keys.master.is_none() { diff --git a/meilisearch-http/src/main.rs b/meilisearch-http/src/main.rs index 637bfaddb..620571bfc 100644 --- a/meilisearch-http/src/main.rs +++ b/meilisearch-http/src/main.rs @@ -18,8 +18,6 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; #[actix_rt::main] async fn main() -> Result<(), MainError> { let opt = Opt::from_args(); - // let local = tokio::task::LocalSet::new(); - // let _sys = actix_rt::System::run_in_tokio("server", &local); match opt.env.as_ref() { "production" => { diff --git a/meilisearch-http/src/routes/document.rs b/meilisearch-http/src/routes/document.rs index eea5d760d..6fab12570 100644 --- a/meilisearch-http/src/routes/document.rs +++ b/meilisearch-http/src/routes/document.rs @@ -13,7 +13,7 @@ use crate::Data; type Document = IndexMap; -#[derive(Default, Deserialize)] +#[derive(Deserialize)] struct DocumentParam { index_uid: String, document_id: String, @@ -46,7 +46,7 @@ async fn get_document( let reader = data.db.main_read_txn()?; let response = index - .document::(&reader, None, document_id)? + .document(&reader, None, document_id)? .ok_or(ResponseError::document_not_found(&path.document_id))?; Ok(HttpResponse::Ok().json(response)) @@ -78,7 +78,7 @@ async fn delete_document( Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } -#[derive(Default, Deserialize)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct BrowseQuery { offset: Option, @@ -116,9 +116,11 @@ async fn get_all_documents( .as_ref() .map(|a| a.split(',').collect()); - let mut response = Vec::::new(); + let mut response = Vec::new(); for document_id in documents_ids { - if let Ok(Some(document)) = index.document(&reader, attributes.as_ref(), document_id) { + if let Ok(Some(document)) = + index.document::(&reader, attributes.as_ref(), document_id) + { response.push(document); } } @@ -135,7 +137,7 @@ fn find_primary_key(document: &IndexMap) -> Option { None } -#[derive(Default, Deserialize)] +#[derive(Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct UpdateDocumentsQuery { primary_key: Option, @@ -171,7 +173,9 @@ async fn update_multiple_documents( let mut writer = data.db.main_write_txn()?; - schema.set_primary_key(&id)?; + schema + .set_primary_key(&id) + .map_err(ResponseError::bad_request)?; index.main.put_schema(&mut writer, &schema)?; writer.commit()?; } diff --git a/meilisearch-http/src/routes/index.rs b/meilisearch-http/src/routes/index.rs index b664d0121..d43967bdd 100644 --- a/meilisearch-http/src/routes/index.rs +++ b/meilisearch-http/src/routes/index.rs @@ -157,13 +157,13 @@ async fn create_index( )); } - let uid = match body.uid.clone() { + let uid = match &body.uid { Some(uid) => { if uid .chars() .all(|x| x.is_ascii_alphanumeric() || x == '-' || x == '_') { - uid + uid.to_owned() } else { return Err(ResponseError::InvalidIndexUid); } @@ -183,8 +183,8 @@ async fn create_index( let mut writer = data.db.main_write_txn()?; - let name = body.name.clone().unwrap_or(uid.clone()); - created_index.main.put_name(&mut writer, &name)?; + let name = body.name.as_ref().unwrap_or(&uid); + created_index.main.put_name(&mut writer, name)?; let created_at = created_index .main @@ -208,7 +208,7 @@ async fn create_index( writer.commit()?; Ok(HttpResponse::Created().json(IndexResponse { - name, + name: name.to_string(), uid, created_at, updated_at, @@ -246,8 +246,8 @@ async fn update_index( let mut writer = data.db.main_write_txn()?; - if let Some(name) = body.name.clone() { - index.main.put_name(&mut writer, &name)?; + if let Some(name) = &body.name { + index.main.put_name(&mut writer, name)?; } if let Some(id) = body.primary_key.clone() { @@ -314,7 +314,7 @@ async fn delete_index( Ok(HttpResponse::NoContent().finish()) } -#[derive(Default, Deserialize)] +#[derive(Deserialize)] struct UpdateParam { index_uid: String, update_id: u64, diff --git a/meilisearch-http/src/routes/key.rs b/meilisearch-http/src/routes/key.rs index 7cca1bbb1..46e59cd6b 100644 --- a/meilisearch-http/src/routes/key.rs +++ b/meilisearch-http/src/routes/key.rs @@ -1,4 +1,5 @@ use actix_web::web; +use actix_web::HttpResponse; use actix_web_macros::get; use serde::Serialize; @@ -9,16 +10,16 @@ pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(list); } -#[derive(Default, Serialize)] +#[derive(Serialize)] struct KeysResponse { private: Option, public: Option, } #[get("/keys", wrap = "Authentication::Admin")] -async fn list(data: web::Data) -> web::Json { +async fn list(data: web::Data) -> HttpResponse { let api_keys = data.api_keys.clone(); - web::Json(KeysResponse { + HttpResponse::Ok().json(KeysResponse { private: api_keys.private, public: api_keys.public, }) diff --git a/meilisearch-http/src/routes/mod.rs b/meilisearch-http/src/routes/mod.rs index 33b71c684..a63e0dc75 100644 --- a/meilisearch-http/src/routes/mod.rs +++ b/meilisearch-http/src/routes/mod.rs @@ -11,12 +11,12 @@ pub mod stats; pub mod stop_words; pub mod synonym; -#[derive(Default, Deserialize)] +#[derive(Deserialize)] pub struct IndexParam { index_uid: String, } -#[derive(Default, Serialize)] +#[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct IndexUpdateResponse { pub update_id: u64, diff --git a/meilisearch-http/src/routes/search.rs b/meilisearch-http/src/routes/search.rs index e64550448..1189e79a8 100644 --- a/meilisearch-http/src/routes/search.rs +++ b/meilisearch-http/src/routes/search.rs @@ -2,11 +2,12 @@ use std::collections::{HashSet, HashMap}; use log::warn; use actix_web::web; +use actix_web::HttpResponse; use actix_web_macros::get; use serde::Deserialize; use crate::error::ResponseError; -use crate::helpers::meilisearch::{IndexSearchExt, SearchResult}; +use crate::helpers::meilisearch::IndexSearchExt; use crate::helpers::Authentication; use crate::routes::IndexParam; use crate::Data; @@ -34,7 +35,7 @@ async fn search_with_url_query( data: web::Data, path: web::Path, params: web::Query, -) -> Result, ResponseError> { +) -> Result { let index = data .db .open_index(&path.index_uid) @@ -137,5 +138,5 @@ async fn search_with_url_query( } } - Ok(web::Json(search_builder.search(&reader)?)) + Ok(HttpResponse::Ok().json(search_builder.search(&reader)?)) } diff --git a/meilisearch-http/src/routes/setting.rs b/meilisearch-http/src/routes/setting.rs index 2af339931..262af8b84 100644 --- a/meilisearch-http/src/routes/setting.rs +++ b/meilisearch-http/src/routes/setting.rs @@ -94,14 +94,14 @@ async fn get_all( let searchable_attributes = schema.clone().map(|s| { s.indexed_name() .iter() - .map(|s| (*s).to_string()) + .map(|s| s.to_string()) .collect::>() }); let displayed_attributes = schema.clone().map(|s| { s.displayed_name() .iter() - .map(|s| (*s).to_string()) + .map(|s| s.to_string()) .collect::>() }); @@ -312,7 +312,7 @@ async fn get_searchable( let reader = data.db.main_read_txn()?; let schema = index.main.schema(&reader)?; let searchable_attributes: Option> = - schema.map(|s| s.indexed_name().iter().map(|i| (*i).to_string()).collect()); + schema.map(|s| s.indexed_name().iter().map(|i| i.to_string()).collect()); Ok(HttpResponse::Ok().json(searchable_attributes)) } @@ -385,12 +385,8 @@ async fn get_displayed( let schema = index.main.schema(&reader)?; - let displayed_attributes: Option> = schema.map(|s| { - s.displayed_name() - .iter() - .map(|i| (*i).to_string()) - .collect() - }); + let displayed_attributes: Option> = + schema.map(|s| s.displayed_name().iter().map(|i| i.to_string()).collect()); Ok(HttpResponse::Ok().json(displayed_attributes)) } diff --git a/meilisearch-http/src/routes/stats.rs b/meilisearch-http/src/routes/stats.rs index 8a793f9bb..92945e588 100644 --- a/meilisearch-http/src/routes/stats.rs +++ b/meilisearch-http/src/routes/stats.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use actix_web::web; +use actix_web::HttpResponse; use actix_web_macros::get; use chrono::{DateTime, Utc}; use log::error; @@ -34,7 +35,7 @@ struct IndexStatsResponse { async fn index_stats( data: web::Data, path: web::Path, -) -> Result, ResponseError> { +) -> Result { let index = data .db .open_index(&path.index_uid) @@ -48,11 +49,13 @@ async fn index_stats( let update_reader = data.db.update_read_txn()?; - let is_indexing = data - .is_indexing(&update_reader, &path.index_uid)? - .unwrap_or_default(); + let is_indexing = + data.is_indexing(&update_reader, &path.index_uid)? + .ok_or(ResponseError::internal( + "Impossible to know if the database is indexing", + ))?; - Ok(web::Json(IndexStatsResponse { + Ok(HttpResponse::Ok().json(IndexStatsResponse { number_of_documents, is_indexing, fields_frequency, @@ -68,7 +71,7 @@ struct StatsResult { } #[get("/stats", wrap = "Authentication::Private")] -async fn get_stats(data: web::Data) -> Result, ResponseError> { +async fn get_stats(data: web::Data) -> Result { let mut index_list = HashMap::new(); let reader = data.db.main_read_txn()?; @@ -83,9 +86,9 @@ async fn get_stats(data: web::Data) -> Result, Resp let fields_frequency = index.main.fields_frequency(&reader)?.unwrap_or_default(); - let is_indexing = data - .is_indexing(&update_reader, &index_uid)? - .unwrap_or_default(); + let is_indexing = data.is_indexing(&update_reader, &index_uid)?.ok_or( + ResponseError::internal("Impossible to know if the database is indexing"), + )?; let response = IndexStatsResponse { number_of_documents, @@ -110,7 +113,7 @@ async fn get_stats(data: web::Data) -> Result, Resp let last_update = data.last_update(&reader)?; - Ok(web::Json(StatsResult { + Ok(HttpResponse::Ok().json(StatsResult { database_size, last_update, indexes: index_list, @@ -126,8 +129,8 @@ struct VersionResponse { } #[get("/version", wrap = "Authentication::Private")] -async fn get_version() -> web::Json { - web::Json(VersionResponse { +async fn get_version() -> HttpResponse { + HttpResponse::Ok().json(VersionResponse { commit_sha: env!("VERGEN_SHA").to_string(), build_date: env!("VERGEN_BUILD_TIMESTAMP").to_string(), pkg_version: env!("CARGO_PKG_VERSION").to_string(), @@ -195,7 +198,7 @@ impl SysInfo { } #[get("/sys-info", wrap = "Authentication::Private")] -async fn get_sys_info(data: web::Data) -> web::Json { +async fn get_sys_info(data: web::Data) -> HttpResponse { let mut sys = System::new(); let mut info = SysInfo::new(); @@ -226,7 +229,7 @@ async fn get_sys_info(data: web::Data) -> web::Json { } sys.refresh_all(); - web::Json(info) + HttpResponse::Ok().json(info) } #[derive(Serialize)] @@ -290,7 +293,7 @@ impl SysInfoPretty { } #[get("/sys-info/pretty", wrap = "Authentication::Private")] -async fn get_sys_info_pretty(data: web::Data) -> web::Json { +async fn get_sys_info_pretty(data: web::Data) -> HttpResponse { let mut sys = System::new(); let mut info = SysInfoPretty::new(); @@ -328,5 +331,5 @@ async fn get_sys_info_pretty(data: web::Data) -> web::Json sys.refresh_all(); - web::Json(info) + HttpResponse::Ok().json(info) }