fix requested changes

This commit is contained in:
Quentin de Quelen 2020-04-24 15:00:52 +02:00 committed by qdequele
parent ea308eb798
commit 36c7fd0cf1
No known key found for this signature in database
GPG Key ID: B3F0A000EBF11745
12 changed files with 68 additions and 63 deletions

View File

@ -14,6 +14,13 @@ name = "meilisearch"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [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"] } chrono = { version = "0.4.11", features = ["serde"] }
crossbeam-channel = "0.4.2" crossbeam-channel = "0.4.2"
env_logger = "0.7.1" env_logger = "0.7.1"
@ -34,20 +41,13 @@ serde_json = { version = "1.0.50", features = ["preserve_order"] }
serde_qs = "0.5.2" serde_qs = "0.5.2"
sha2 = "0.8.1" sha2 = "0.8.1"
siphasher = "0.3.2" siphasher = "0.3.2"
slice-group-by = "0.2.6"
structopt = "0.3.12" structopt = "0.3.12"
sysinfo = "0.12.0" sysinfo = "0.12.0"
tokio = { version = "0.2.18", features = ["macros"] }
ureq = { version = "0.12.0", features = ["tls"], default-features = false } ureq = { version = "0.12.0", features = ["tls"], default-features = false }
walkdir = "2.3.1" walkdir = "2.3.1"
whoami = "0.8.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] [dev-dependencies]
http-service = "0.4.0" http-service = "0.4.0"

View File

@ -37,7 +37,7 @@ pub struct DataInner {
pub server_pid: Pid, pub server_pid: Pid,
} }
#[derive(Default, Clone)] #[derive(Clone)]
pub struct ApiKeys { pub struct ApiKeys {
pub public: Option<String>, pub public: Option<String>,
pub private: Option<String>, pub private: Option<String>,

View File

@ -91,11 +91,11 @@ impl fmt::Display for ResponseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::BadParameter(param, err) => write!(f, "Url parameter {} error: {}", param, err), 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::CreateIndex(err) => write!(f, "Impossible to create index; {}", err),
Self::DocumentNotFound(document_id) => write!(f, "Document with id {} not found", document_id), 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::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::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::InvalidToken(err) => write!(f, "Invalid API key: {}", err),
Self::Maintenance => f.write_str("Server is in maintenance, please try again later"), Self::Maintenance => f.write_str("Server is in maintenance, please try again later"),

View File

@ -33,7 +33,7 @@ where
fn new_transform(&self, service: S) -> Self::Future { fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware { ok(LoggingMiddleware {
acl: (*self).clone(), acl: self.clone(),
service: Rc::new(RefCell::new(service)), service: Rc::new(RefCell::new(service)),
}) })
} }
@ -61,6 +61,8 @@ where
fn call(&mut self, req: ServiceRequest) -> Self::Future { fn call(&mut self, req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone(); 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::<Data>().unwrap(); let data = req.app_data::<Data>().unwrap();
if data.api_keys.master.is_none() { if data.api_keys.master.is_none() {

View File

@ -18,8 +18,6 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), MainError> { async fn main() -> Result<(), MainError> {
let opt = Opt::from_args(); 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() { match opt.env.as_ref() {
"production" => { "production" => {

View File

@ -13,7 +13,7 @@ use crate::Data;
type Document = IndexMap<String, Value>; type Document = IndexMap<String, Value>;
#[derive(Default, Deserialize)] #[derive(Deserialize)]
struct DocumentParam { struct DocumentParam {
index_uid: String, index_uid: String,
document_id: String, document_id: String,
@ -46,7 +46,7 @@ async fn get_document(
let reader = data.db.main_read_txn()?; let reader = data.db.main_read_txn()?;
let response = index let response = index
.document::<Document>(&reader, None, document_id)? .document(&reader, None, document_id)?
.ok_or(ResponseError::document_not_found(&path.document_id))?; .ok_or(ResponseError::document_not_found(&path.document_id))?;
Ok(HttpResponse::Ok().json(response)) Ok(HttpResponse::Ok().json(response))
@ -78,7 +78,7 @@ async fn delete_document(
Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id)))
} }
#[derive(Default, Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)]
struct BrowseQuery { struct BrowseQuery {
offset: Option<usize>, offset: Option<usize>,
@ -116,9 +116,11 @@ async fn get_all_documents(
.as_ref() .as_ref()
.map(|a| a.split(',').collect()); .map(|a| a.split(',').collect());
let mut response = Vec::<Document>::new(); let mut response = Vec::new();
for document_id in documents_ids { 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::<Document>(&reader, attributes.as_ref(), document_id)
{
response.push(document); response.push(document);
} }
} }
@ -135,7 +137,7 @@ fn find_primary_key(document: &IndexMap<String, Value>) -> Option<String> {
None None
} }
#[derive(Default, Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)]
struct UpdateDocumentsQuery { struct UpdateDocumentsQuery {
primary_key: Option<String>, primary_key: Option<String>,
@ -171,7 +173,9 @@ async fn update_multiple_documents(
let mut writer = data.db.main_write_txn()?; 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)?; index.main.put_schema(&mut writer, &schema)?;
writer.commit()?; writer.commit()?;
} }

View File

@ -157,13 +157,13 @@ async fn create_index(
)); ));
} }
let uid = match body.uid.clone() { let uid = match &body.uid {
Some(uid) => { Some(uid) => {
if uid if uid
.chars() .chars()
.all(|x| x.is_ascii_alphanumeric() || x == '-' || x == '_') .all(|x| x.is_ascii_alphanumeric() || x == '-' || x == '_')
{ {
uid uid.to_owned()
} else { } else {
return Err(ResponseError::InvalidIndexUid); return Err(ResponseError::InvalidIndexUid);
} }
@ -183,8 +183,8 @@ async fn create_index(
let mut writer = data.db.main_write_txn()?; let mut writer = data.db.main_write_txn()?;
let name = body.name.clone().unwrap_or(uid.clone()); let name = body.name.as_ref().unwrap_or(&uid);
created_index.main.put_name(&mut writer, &name)?; created_index.main.put_name(&mut writer, name)?;
let created_at = created_index let created_at = created_index
.main .main
@ -208,7 +208,7 @@ async fn create_index(
writer.commit()?; writer.commit()?;
Ok(HttpResponse::Created().json(IndexResponse { Ok(HttpResponse::Created().json(IndexResponse {
name, name: name.to_string(),
uid, uid,
created_at, created_at,
updated_at, updated_at,
@ -246,8 +246,8 @@ async fn update_index(
let mut writer = data.db.main_write_txn()?; let mut writer = data.db.main_write_txn()?;
if let Some(name) = body.name.clone() { if let Some(name) = &body.name {
index.main.put_name(&mut writer, &name)?; index.main.put_name(&mut writer, name)?;
} }
if let Some(id) = body.primary_key.clone() { if let Some(id) = body.primary_key.clone() {
@ -314,7 +314,7 @@ async fn delete_index(
Ok(HttpResponse::NoContent().finish()) Ok(HttpResponse::NoContent().finish())
} }
#[derive(Default, Deserialize)] #[derive(Deserialize)]
struct UpdateParam { struct UpdateParam {
index_uid: String, index_uid: String,
update_id: u64, update_id: u64,

View File

@ -1,4 +1,5 @@
use actix_web::web; use actix_web::web;
use actix_web::HttpResponse;
use actix_web_macros::get; use actix_web_macros::get;
use serde::Serialize; use serde::Serialize;
@ -9,16 +10,16 @@ pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(list); cfg.service(list);
} }
#[derive(Default, Serialize)] #[derive(Serialize)]
struct KeysResponse { struct KeysResponse {
private: Option<String>, private: Option<String>,
public: Option<String>, public: Option<String>,
} }
#[get("/keys", wrap = "Authentication::Admin")] #[get("/keys", wrap = "Authentication::Admin")]
async fn list(data: web::Data<Data>) -> web::Json<KeysResponse> { async fn list(data: web::Data<Data>) -> HttpResponse {
let api_keys = data.api_keys.clone(); let api_keys = data.api_keys.clone();
web::Json(KeysResponse { HttpResponse::Ok().json(KeysResponse {
private: api_keys.private, private: api_keys.private,
public: api_keys.public, public: api_keys.public,
}) })

View File

@ -11,12 +11,12 @@ pub mod stats;
pub mod stop_words; pub mod stop_words;
pub mod synonym; pub mod synonym;
#[derive(Default, Deserialize)] #[derive(Deserialize)]
pub struct IndexParam { pub struct IndexParam {
index_uid: String, index_uid: String,
} }
#[derive(Default, Serialize)] #[derive(Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct IndexUpdateResponse { pub struct IndexUpdateResponse {
pub update_id: u64, pub update_id: u64,

View File

@ -2,11 +2,12 @@ use std::collections::{HashSet, HashMap};
use log::warn; use log::warn;
use actix_web::web; use actix_web::web;
use actix_web::HttpResponse;
use actix_web_macros::get; use actix_web_macros::get;
use serde::Deserialize; use serde::Deserialize;
use crate::error::ResponseError; use crate::error::ResponseError;
use crate::helpers::meilisearch::{IndexSearchExt, SearchResult}; use crate::helpers::meilisearch::IndexSearchExt;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::IndexParam; use crate::routes::IndexParam;
use crate::Data; use crate::Data;
@ -34,7 +35,7 @@ async fn search_with_url_query(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<IndexParam>, path: web::Path<IndexParam>,
params: web::Query<SearchQuery>, params: web::Query<SearchQuery>,
) -> Result<web::Json<SearchResult>, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
let index = data let index = data
.db .db
.open_index(&path.index_uid) .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)?))
} }

View File

@ -94,14 +94,14 @@ async fn get_all(
let searchable_attributes = schema.clone().map(|s| { let searchable_attributes = schema.clone().map(|s| {
s.indexed_name() s.indexed_name()
.iter() .iter()
.map(|s| (*s).to_string()) .map(|s| s.to_string())
.collect::<Vec<String>>() .collect::<Vec<String>>()
}); });
let displayed_attributes = schema.clone().map(|s| { let displayed_attributes = schema.clone().map(|s| {
s.displayed_name() s.displayed_name()
.iter() .iter()
.map(|s| (*s).to_string()) .map(|s| s.to_string())
.collect::<HashSet<String>>() .collect::<HashSet<String>>()
}); });
@ -312,7 +312,7 @@ async fn get_searchable(
let reader = data.db.main_read_txn()?; let reader = data.db.main_read_txn()?;
let schema = index.main.schema(&reader)?; let schema = index.main.schema(&reader)?;
let searchable_attributes: Option<Vec<String>> = let searchable_attributes: Option<Vec<String>> =
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)) Ok(HttpResponse::Ok().json(searchable_attributes))
} }
@ -385,12 +385,8 @@ async fn get_displayed(
let schema = index.main.schema(&reader)?; let schema = index.main.schema(&reader)?;
let displayed_attributes: Option<HashSet<String>> = schema.map(|s| { let displayed_attributes: Option<HashSet<String>> =
s.displayed_name() schema.map(|s| s.displayed_name().iter().map(|i| i.to_string()).collect());
.iter()
.map(|i| (*i).to_string())
.collect()
});
Ok(HttpResponse::Ok().json(displayed_attributes)) Ok(HttpResponse::Ok().json(displayed_attributes))
} }

View File

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use actix_web::web; use actix_web::web;
use actix_web::HttpResponse;
use actix_web_macros::get; use actix_web_macros::get;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use log::error; use log::error;
@ -34,7 +35,7 @@ struct IndexStatsResponse {
async fn index_stats( async fn index_stats(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<IndexParam>, path: web::Path<IndexParam>,
) -> Result<web::Json<IndexStatsResponse>, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
let index = data let index = data
.db .db
.open_index(&path.index_uid) .open_index(&path.index_uid)
@ -48,11 +49,13 @@ async fn index_stats(
let update_reader = data.db.update_read_txn()?; let update_reader = data.db.update_read_txn()?;
let is_indexing = data let is_indexing =
.is_indexing(&update_reader, &path.index_uid)? data.is_indexing(&update_reader, &path.index_uid)?
.unwrap_or_default(); .ok_or(ResponseError::internal(
"Impossible to know if the database is indexing",
))?;
Ok(web::Json(IndexStatsResponse { Ok(HttpResponse::Ok().json(IndexStatsResponse {
number_of_documents, number_of_documents,
is_indexing, is_indexing,
fields_frequency, fields_frequency,
@ -68,7 +71,7 @@ struct StatsResult {
} }
#[get("/stats", wrap = "Authentication::Private")] #[get("/stats", wrap = "Authentication::Private")]
async fn get_stats(data: web::Data<Data>) -> Result<web::Json<StatsResult>, ResponseError> { async fn get_stats(data: web::Data<Data>) -> Result<HttpResponse, ResponseError> {
let mut index_list = HashMap::new(); let mut index_list = HashMap::new();
let reader = data.db.main_read_txn()?; let reader = data.db.main_read_txn()?;
@ -83,9 +86,9 @@ async fn get_stats(data: web::Data<Data>) -> Result<web::Json<StatsResult>, Resp
let fields_frequency = index.main.fields_frequency(&reader)?.unwrap_or_default(); let fields_frequency = index.main.fields_frequency(&reader)?.unwrap_or_default();
let is_indexing = data let is_indexing = data.is_indexing(&update_reader, &index_uid)?.ok_or(
.is_indexing(&update_reader, &index_uid)? ResponseError::internal("Impossible to know if the database is indexing"),
.unwrap_or_default(); )?;
let response = IndexStatsResponse { let response = IndexStatsResponse {
number_of_documents, number_of_documents,
@ -110,7 +113,7 @@ async fn get_stats(data: web::Data<Data>) -> Result<web::Json<StatsResult>, Resp
let last_update = data.last_update(&reader)?; let last_update = data.last_update(&reader)?;
Ok(web::Json(StatsResult { Ok(HttpResponse::Ok().json(StatsResult {
database_size, database_size,
last_update, last_update,
indexes: index_list, indexes: index_list,
@ -126,8 +129,8 @@ struct VersionResponse {
} }
#[get("/version", wrap = "Authentication::Private")] #[get("/version", wrap = "Authentication::Private")]
async fn get_version() -> web::Json<VersionResponse> { async fn get_version() -> HttpResponse {
web::Json(VersionResponse { HttpResponse::Ok().json(VersionResponse {
commit_sha: env!("VERGEN_SHA").to_string(), commit_sha: env!("VERGEN_SHA").to_string(),
build_date: env!("VERGEN_BUILD_TIMESTAMP").to_string(), build_date: env!("VERGEN_BUILD_TIMESTAMP").to_string(),
pkg_version: env!("CARGO_PKG_VERSION").to_string(), pkg_version: env!("CARGO_PKG_VERSION").to_string(),
@ -195,7 +198,7 @@ impl SysInfo {
} }
#[get("/sys-info", wrap = "Authentication::Private")] #[get("/sys-info", wrap = "Authentication::Private")]
async fn get_sys_info(data: web::Data<Data>) -> web::Json<SysInfo> { async fn get_sys_info(data: web::Data<Data>) -> HttpResponse {
let mut sys = System::new(); let mut sys = System::new();
let mut info = SysInfo::new(); let mut info = SysInfo::new();
@ -226,7 +229,7 @@ async fn get_sys_info(data: web::Data<Data>) -> web::Json<SysInfo> {
} }
sys.refresh_all(); sys.refresh_all();
web::Json(info) HttpResponse::Ok().json(info)
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -290,7 +293,7 @@ impl SysInfoPretty {
} }
#[get("/sys-info/pretty", wrap = "Authentication::Private")] #[get("/sys-info/pretty", wrap = "Authentication::Private")]
async fn get_sys_info_pretty(data: web::Data<Data>) -> web::Json<SysInfoPretty> { async fn get_sys_info_pretty(data: web::Data<Data>) -> HttpResponse {
let mut sys = System::new(); let mut sys = System::new();
let mut info = SysInfoPretty::new(); let mut info = SysInfoPretty::new();
@ -328,5 +331,5 @@ async fn get_sys_info_pretty(data: web::Data<Data>) -> web::Json<SysInfoPretty>
sys.refresh_all(); sys.refresh_all();
web::Json(info) HttpResponse::Ok().json(info)
} }