This commit is contained in:
Quentin de Quelen 2020-04-09 10:39:34 +02:00 committed by qdequele
parent 6c581fb3bd
commit 5ec130e6dc
No known key found for this signature in database
GPG Key ID: B3F0A000EBF11745
11 changed files with 122 additions and 140 deletions

View File

@ -14,7 +14,6 @@ name = "meilisearch"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
# async-std = { version = "1.5.0", features = ["attributes"] }
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"
@ -38,7 +37,6 @@ sha2 = "0.8.1"
siphasher = "0.3.2" siphasher = "0.3.2"
structopt = "0.3.12" structopt = "0.3.12"
sysinfo = "0.12.0" sysinfo = "0.12.0"
# tide = "0.6.0"
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"

View File

@ -1,8 +1,8 @@
use std::fmt; use std::fmt;
use serde_json::json; use serde_json::json;
use actix_web as aweb;
use actix_http::ResponseBuilder; use actix_http::ResponseBuilder;
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::*;
#[derive(Debug)] #[derive(Debug)]
pub enum ResponseError { pub enum ResponseError {
@ -12,16 +12,11 @@ pub enum ResponseError {
NotFound(String), NotFound(String),
IndexNotFound(String), IndexNotFound(String),
DocumentNotFound(String), DocumentNotFound(String),
UpdateNotFound(u64),
MissingHeader(String), MissingHeader(String),
FilterParsing(String), FilterParsing(String),
BadParameter(String, String), BadParameter(String, String),
OpenIndex(String), OpenIndex(String),
CreateIndex(String), CreateIndex(String),
CreateTransaction,
CommitTransaction,
Schema,
InferPrimaryKey,
InvalidIndexUid, InvalidIndexUid,
Maintenance, Maintenance,
} }
@ -35,15 +30,10 @@ impl fmt::Display for ResponseError {
Self::NotFound(err) => write!(f, "{} not found", err), Self::NotFound(err) => write!(f, "{} not found", err),
Self::IndexNotFound(index_uid) => write!(f, "Index {} not found", index_uid), Self::IndexNotFound(index_uid) => write!(f, "Index {} not found", index_uid),
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::UpdateNotFound(update_id) => write!(f, "Update with id {} not found", update_id),
Self::MissingHeader(header) => write!(f, "Header {} is missing", header), Self::MissingHeader(header) => write!(f, "Header {} is missing", header),
Self::BadParameter(param, err) => write!(f, "Url parameter {} error: {}", param, err), Self::BadParameter(param, err) => write!(f, "Url parameter {} error: {}", param, err),
Self::OpenIndex(err) => write!(f, "Impossible to open index; {}", err), Self::OpenIndex(err) => write!(f, "Impossible to open index; {}", err),
Self::CreateIndex(err) => write!(f, "Impossible to create index; {}", err), Self::CreateIndex(err) => write!(f, "Impossible to create index; {}", err),
Self::CreateTransaction => write!(f, "Impossible to create transaction"),
Self::CommitTransaction => write!(f, "Impossible to commit transaction"),
Self::Schema => write!(f, "Internal schema is innaccessible"),
Self::InferPrimaryKey => write!(f, "Could not infer primary key"),
Self::InvalidIndexUid => write!(f, "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 => write!(f, "Index must have a valid uid; Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_)."),
Self::Maintenance => write!(f, "Server is in maintenance, please try again later"), Self::Maintenance => write!(f, "Server is in maintenance, please try again later"),
Self::FilterParsing(err) => write!(f, "parsing error: {}", err), Self::FilterParsing(err) => write!(f, "parsing error: {}", err),
@ -51,8 +41,8 @@ impl fmt::Display for ResponseError {
} }
} }
impl error::ResponseError for ResponseError { impl aweb::error::ResponseError for ResponseError {
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> aweb::HttpResponse {
ResponseBuilder::new(self.status_code()).json(json!({ ResponseBuilder::new(self.status_code()).json(json!({
"message": self.to_string(), "message": self.to_string(),
})) }))
@ -66,15 +56,10 @@ impl error::ResponseError for ResponseError {
Self::NotFound(_) => StatusCode::NOT_FOUND, Self::NotFound(_) => StatusCode::NOT_FOUND,
Self::IndexNotFound(_) => StatusCode::NOT_FOUND, Self::IndexNotFound(_) => StatusCode::NOT_FOUND,
Self::DocumentNotFound(_) => StatusCode::NOT_FOUND, Self::DocumentNotFound(_) => StatusCode::NOT_FOUND,
Self::UpdateNotFound(_) => StatusCode::NOT_FOUND,
Self::MissingHeader(_) => StatusCode::UNAUTHORIZED, Self::MissingHeader(_) => StatusCode::UNAUTHORIZED,
Self::BadParameter(_, _) => StatusCode::BAD_REQUEST, Self::BadParameter(_, _) => StatusCode::BAD_REQUEST,
Self::OpenIndex(_) => StatusCode::BAD_REQUEST, Self::OpenIndex(_) => StatusCode::BAD_REQUEST,
Self::CreateIndex(_) => StatusCode::BAD_REQUEST, Self::CreateIndex(_) => StatusCode::BAD_REQUEST,
Self::CreateTransaction => StatusCode::INTERNAL_SERVER_ERROR,
Self::CommitTransaction => StatusCode::INTERNAL_SERVER_ERROR,
Self::Schema => StatusCode::INTERNAL_SERVER_ERROR,
Self::InferPrimaryKey => StatusCode::BAD_REQUEST,
Self::InvalidIndexUid => StatusCode::BAD_REQUEST, Self::InvalidIndexUid => StatusCode::BAD_REQUEST,
Self::Maintenance => StatusCode::SERVICE_UNAVAILABLE, Self::Maintenance => StatusCode::SERVICE_UNAVAILABLE,
Self::FilterParsing(_) => StatusCode::BAD_REQUEST, Self::FilterParsing(_) => StatusCode::BAD_REQUEST,

View File

@ -4,7 +4,7 @@ use log::info;
use main_error::MainError; use main_error::MainError;
use structopt::StructOpt; use structopt::StructOpt;
use actix_web::middleware::Logger; use actix_web::middleware::Logger;
use actix_web::*; use actix_web::{web, HttpServer, App};
use meilisearch_http::data::Data; use meilisearch_http::data::Data;
use meilisearch_http::option::Opt; use meilisearch_http::option::Opt;
use meilisearch_http::routes; use meilisearch_http::routes;
@ -61,6 +61,8 @@ async fn main() -> Result<(), MainError> {
.service(routes::index::create_index) .service(routes::index::create_index)
.service(routes::index::update_index) .service(routes::index::update_index)
.service(routes::index::delete_index) .service(routes::index::delete_index)
.service(routes::index::get_update_status)
.service(routes::index::get_all_updates_status)
.service(routes::search::search_with_url_query) .service(routes::search::search_with_url_query)
.service(routes::search::search_multi_index) .service(routes::search::search_multi_index)
.service(routes::document::get_document) .service(routes::document::get_document)
@ -70,8 +72,6 @@ async fn main() -> Result<(), MainError> {
.service(routes::document::update_documents) .service(routes::document::update_documents)
.service(routes::document::delete_documents) .service(routes::document::delete_documents)
.service(routes::document::clear_all_documents) .service(routes::document::clear_all_documents)
.service(routes::update::get_update_status)
.service(routes::update::get_all_updates_status)
.service(routes::key::list) .service(routes::key::list)
.service(routes::stats::index_stats) .service(routes::stats::index_stats)
.service(routes::stats::get_stats) .service(routes::stats::get_stats)

View File

@ -2,7 +2,8 @@ use std::collections::BTreeSet;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
use actix_web::*; use actix_web::{web, get, post, put, delete, HttpResponse};
use actix_web as aweb;
use crate::error::ResponseError; use crate::error::ResponseError;
use crate::Data; use crate::Data;
@ -14,13 +15,13 @@ type Document = IndexMap<String, Value>;
pub async fn get_document( pub async fn get_document(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<(String, String)>, path: web::Path<(String, String)>,
) -> Result<web::Json<Document>> { ) -> aweb::Result<web::Json<Document>> {
let index = data.db.open_index(&path.0) let index = data.db.open_index(&path.0)
.ok_or(ResponseError::IndexNotFound(path.0.clone()))?; .ok_or(ResponseError::IndexNotFound(path.0.clone()))?;
let document_id = meilisearch_core::serde::compute_document_id(path.1.clone()); let document_id = meilisearch_core::serde::compute_document_id(path.1.clone());
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let response = index.document::<Document, String>(&reader, None, document_id) let response = index.document::<Document, String>(&reader, None, document_id)
.map_err(|_| ResponseError::DocumentNotFound(path.1.clone()))? .map_err(|_| ResponseError::DocumentNotFound(path.1.clone()))?
@ -33,13 +34,13 @@ pub async fn get_document(
pub async fn delete_document( pub async fn delete_document(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<(String, String)>, path: web::Path<(String, String)>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let index = data.db.open_index(&path.0) let index = data.db.open_index(&path.0)
.ok_or(ResponseError::IndexNotFound(path.0.clone()))?; .ok_or(ResponseError::IndexNotFound(path.0.clone()))?;
let document_id = meilisearch_core::serde::compute_document_id(path.1.clone()); let document_id = meilisearch_core::serde::compute_document_id(path.1.clone());
let mut update_writer = data.db.update_write_txn() let mut update_writer = data.db.update_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let mut documents_deletion = index.documents_deletion(); let mut documents_deletion = index.documents_deletion();
documents_deletion.delete_document_by_id(document_id); documents_deletion.delete_document_by_id(document_id);
@ -48,7 +49,7 @@ pub async fn delete_document(
.map_err(|err| ResponseError::Internal(err.to_string()))?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
update_writer.commit() update_writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id)))
} }
@ -67,7 +68,7 @@ pub async fn get_all_documents(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
params: web::Query<BrowseQuery>, params: web::Query<BrowseQuery>,
) -> Result<web::Json<Vec<Document>>> { ) -> aweb::Result<web::Json<Vec<Document>>> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
@ -76,7 +77,7 @@ pub async fn get_all_documents(
let limit = params.limit.unwrap_or(20); let limit = params.limit.unwrap_or(20);
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let documents_ids: Result<BTreeSet<_>, _> = index let documents_ids: Result<BTreeSet<_>, _> = index
.documents_fields_counts .documents_fields_counts
@ -123,19 +124,19 @@ async fn update_multiple_documents(
params: web::Query<UpdateDocumentsQuery>, params: web::Query<UpdateDocumentsQuery>,
body: web::Json<Vec<Document>>, body: web::Json<Vec<Document>>,
is_partial: bool is_partial: bool
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let mut schema = index let mut schema = index
.main .main
.schema(&reader) .schema(&reader)
.map_err(|_| ResponseError::Schema)? .map_err(|err| ResponseError::Internal(err.to_string()))?
.ok_or(ResponseError::Schema)?; .ok_or(ResponseError::Internal("Impossible to retrieve the schema".to_string()))?;
if schema.primary_key().is_none() { if schema.primary_key().is_none() {
let id = match params.primary_key.clone() { let id = match params.primary_key.clone() {
@ -143,19 +144,19 @@ async fn update_multiple_documents(
None => { None => {
body.first() body.first()
.and_then(|docs| find_primary_key(docs)) .and_then(|docs| find_primary_key(docs))
.ok_or(ResponseError::InferPrimaryKey)? .ok_or(ResponseError::BadRequest("Impossible to infer the primary key".to_string()))?
} }
}; };
let mut writer = data.db.main_write_txn() let mut writer = data.db.main_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
schema.set_primary_key(&id) schema.set_primary_key(&id)
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
index.main.put_schema(&mut writer, &schema) index.main.put_schema(&mut writer, &schema)
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
} }
let mut document_addition = if is_partial { let mut document_addition = if is_partial {
@ -169,11 +170,11 @@ async fn update_multiple_documents(
} }
let mut update_writer = data.db.update_write_txn() let mut update_writer = data.db.update_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let update_id = document_addition.finalize(&mut update_writer) let update_id = document_addition.finalize(&mut update_writer)
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
update_writer.commit() update_writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id)))
} }
@ -184,7 +185,7 @@ pub async fn add_documents(
path: web::Path<String>, path: web::Path<String>,
params: web::Query<UpdateDocumentsQuery>, params: web::Query<UpdateDocumentsQuery>,
body: web::Json<Vec<Document>> body: web::Json<Vec<Document>>
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
update_multiple_documents(data, path, params, body, false).await update_multiple_documents(data, path, params, body, false).await
} }
@ -194,7 +195,7 @@ pub async fn update_documents(
path: web::Path<String>, path: web::Path<String>,
params: web::Query<UpdateDocumentsQuery>, params: web::Query<UpdateDocumentsQuery>,
body: web::Json<Vec<Document>> body: web::Json<Vec<Document>>
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
update_multiple_documents(data, path, params, body, true).await update_multiple_documents(data, path, params, body, true).await
} }
@ -203,13 +204,13 @@ pub async fn delete_documents(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
body: web::Json<Vec<Value>> body: web::Json<Vec<Value>>
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let mut writer = data.db.update_write_txn() let mut writer = data.db.update_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let mut documents_deletion = index.documents_deletion(); let mut documents_deletion = index.documents_deletion();
@ -224,7 +225,7 @@ pub async fn delete_documents(
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id)))
} }
@ -233,19 +234,19 @@ pub async fn delete_documents(
pub async fn clear_all_documents( pub async fn clear_all_documents(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let mut writer = data.db.update_write_txn() let mut writer = data.db.update_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let update_id = index.clear_all(&mut writer) let update_id = index.clear_all(&mut writer)
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id)))
} }

View File

@ -1,5 +1,6 @@
use crate::error::ResponseError; use crate::error::ResponseError;
use actix_web::*; use actix_web::{web, get, put, HttpResponse};
use actix_web as aweb;
use crate::Data; use crate::Data;
use heed::types::{Str, Unit}; use heed::types::{Str, Unit};
use serde::Deserialize; use serde::Deserialize;
@ -9,14 +10,14 @@ const UNHEALTHY_KEY: &str = "_is_unhealthy";
#[get("/health")] #[get("/health")]
pub async fn get_health( pub async fn get_health(
data: web::Data<Data>, data: web::Data<Data>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let common_store = data.db.common_store(); let common_store = data.db.common_store();
if let Ok(Some(_)) = common_store.get::<_, Str, Unit>(&reader, UNHEALTHY_KEY) { if let Ok(Some(_)) = common_store.get::<_, Str, Unit>(&reader, UNHEALTHY_KEY) {
return Err(ResponseError::Maintenance)?; return Err(ResponseError::Maintenance.into());
} }
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
@ -24,28 +25,28 @@ pub async fn get_health(
pub async fn set_healthy( pub async fn set_healthy(
data: web::Data<Data>, data: web::Data<Data>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let mut writer = data.db.main_write_txn() let mut writer = data.db.main_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let common_store = data.db.common_store(); let common_store = data.db.common_store();
common_store.delete::<_, Str>(&mut writer, UNHEALTHY_KEY) common_store.delete::<_, Str>(&mut writer, UNHEALTHY_KEY)
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} }
pub async fn set_unhealthy( pub async fn set_unhealthy(
data: web::Data<Data>, data: web::Data<Data>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
let mut writer = data.db.main_write_txn() let mut writer = data.db.main_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let common_store = data.db.common_store(); let common_store = data.db.common_store();
common_store.put::<_, Str, Unit>(&mut writer, UNHEALTHY_KEY, &()) common_store.put::<_, Str, Unit>(&mut writer, UNHEALTHY_KEY, &())
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} }
@ -59,7 +60,7 @@ pub struct HealtBody {
pub async fn change_healthyness( pub async fn change_healthyness(
data: web::Data<Data>, data: web::Data<Data>,
body: web::Json<HealtBody>, body: web::Json<HealtBody>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
if body.health { if body.health {
set_healthy(data).await set_healthy(data).await
} else { } else {

View File

@ -2,7 +2,9 @@ use chrono::{DateTime, Utc};
use log::error; use log::error;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use actix_web::*; use actix_web::{web, get, post, delete, HttpResponse};
use actix_web as aweb;
use meilisearch_core::UpdateStatus;
use crate::error::ResponseError; use crate::error::ResponseError;
use crate::Data; use crate::Data;
@ -29,10 +31,10 @@ pub struct IndexResponse {
#[get("/indexes")] #[get("/indexes")]
pub async fn list_indexes( pub async fn list_indexes(
data: web::Data<Data>, data: web::Data<Data>,
) -> Result<web::Json<Vec<IndexResponse>>> { ) -> aweb::Result<web::Json<Vec<IndexResponse>>> {
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let mut response_body = Vec::new(); let mut response_body = Vec::new();
@ -82,13 +84,13 @@ pub async fn list_indexes(
pub async fn get_index( pub async fn get_index(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
) -> Result<web::Json<IndexResponse>> { ) -> aweb::Result<web::Json<IndexResponse>> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let name = index.main.name(&reader) let name = index.main.name(&reader)
.map_err(|e| ResponseError::Internal(e.to_string()))? .map_err(|e| ResponseError::Internal(e.to_string()))?
@ -129,10 +131,10 @@ pub struct IndexCreateRequest {
pub async fn create_index( pub async fn create_index(
data: web::Data<Data>, data: web::Data<Data>,
body: web::Json<IndexCreateRequest> body: web::Json<IndexCreateRequest>
) -> Result<web::Json<IndexResponse>> { ) -> aweb::Result<web::Json<IndexResponse>> {
if let (None, None) = (body.name.clone(), body.uid.clone()) { if let (None, None) = (body.name.clone(), body.uid.clone()) {
return Err(ResponseError::BadRequest("Index creation must have an uid".to_string()))?; return Err(ResponseError::BadRequest("Index creation must have an uid".to_string()).into());
} }
let uid = match body.uid.clone() { let uid = match body.uid.clone() {
@ -143,7 +145,7 @@ pub async fn create_index(
{ {
uid uid
} else { } else {
return Err(ResponseError::InvalidIndexUid)?; return Err(ResponseError::InvalidIndexUid.into());
} }
} }
None => loop { None => loop {
@ -158,7 +160,7 @@ pub async fn create_index(
.map_err(|e| ResponseError::CreateIndex(e.to_string()))?; .map_err(|e| ResponseError::CreateIndex(e.to_string()))?;
let mut writer = data.db.main_write_txn() let mut writer = data.db.main_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let name = body.name.clone().unwrap_or(uid.clone()); let name = body.name.clone().unwrap_or(uid.clone());
created_index.main.put_name(&mut writer, &name) created_index.main.put_name(&mut writer, &name)
@ -187,7 +189,7 @@ pub async fn create_index(
} }
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(web::Json(IndexResponse { Ok(web::Json(IndexResponse {
name, name,
@ -220,13 +222,13 @@ pub async fn update_index(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
body: web::Json<IndexCreateRequest> body: web::Json<IndexCreateRequest>
) -> Result<web::Json<IndexResponse>> { ) -> aweb::Result<web::Json<IndexResponse>> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let mut writer = data.db.main_write_txn() let mut writer = data.db.main_write_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
if let Some(name) = body.name.clone() { if let Some(name) = body.name.clone() {
index.main.put_name(&mut writer, &name) index.main.put_name(&mut writer, &name)
@ -238,7 +240,7 @@ pub async fn update_index(
.map_err(|e| ResponseError::Internal(e.to_string()))? { .map_err(|e| ResponseError::Internal(e.to_string()))? {
match schema.primary_key() { match schema.primary_key() {
Some(_) => { Some(_) => {
return Err(ResponseError::BadRequest("The primary key cannot be updated".to_string()))?; return Err(ResponseError::BadRequest("The primary key cannot be updated".to_string()).into());
} }
None => { None => {
schema schema
@ -254,10 +256,10 @@ pub async fn update_index(
index.main.put_updated_at(&mut writer) index.main.put_updated_at(&mut writer)
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
writer.commit() writer.commit()
.map_err(|_| ResponseError::CommitTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let name = index.main.name(&reader) let name = index.main.name(&reader)
.map_err(|e| ResponseError::Internal(e.to_string()))? .map_err(|e| ResponseError::Internal(e.to_string()))?
@ -290,10 +292,50 @@ pub async fn update_index(
pub async fn delete_index( pub async fn delete_index(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
) -> Result<HttpResponse> { ) -> aweb::Result<HttpResponse> {
data.db.delete_index(&path.to_string()) data.db.delete_index(&path.to_string())
.map_err(|e| ResponseError::Internal(e.to_string()))?; .map_err(|e| ResponseError::Internal(e.to_string()))?;
HttpResponse::NoContent().await HttpResponse::NoContent().await
} }
#[get("/indexes/{index_uid}/updates/{update_id}")]
pub async fn get_update_status(
data: web::Data<Data>,
path: web::Path<(String, u64)>,
) -> aweb::Result<web::Json<UpdateStatus>> {
let index = data.db.open_index(path.0.clone())
.ok_or(ResponseError::IndexNotFound(path.0.clone()))?;
let reader = data.db.update_read_txn()
.map_err(|err| ResponseError::Internal(err.to_string()))?;
let status = index.update_status(&reader, path.1)
.map_err(|e| ResponseError::Internal(e.to_string()))?;
match status {
Some(status) => Ok(web::Json(status)),
None => Err(ResponseError::NotFound(format!("Update {} not found", path.1)).into())
}
}
#[get("/indexes/{index_uid}/updates")]
pub async fn get_all_updates_status(
data: web::Data<Data>,
path: web::Path<String>,
) -> aweb::Result<web::Json<Vec<UpdateStatus>>> {
let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?;
let reader = data.db.update_read_txn()
.map_err(|err| ResponseError::Internal(err.to_string()))?;
let response = index.all_updates_status(&reader)
.map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(web::Json(response))
}

View File

@ -1,5 +1,5 @@
use crate::Data; use crate::Data;
use actix_web::*; use actix_web::{web, get};
use serde::Serialize; use serde::Serialize;

View File

@ -1,4 +1,4 @@
use actix_web::*; use actix_web::{get, HttpResponse};
use serde::Serialize; use serde::Serialize;
use log::error; use log::error;
use meilisearch_core::ProcessedUpdateResult; use meilisearch_core::ProcessedUpdateResult;
@ -10,24 +10,21 @@ pub mod health;
pub mod index; pub mod index;
pub mod key; pub mod key;
pub mod search; pub mod search;
// pub mod setting;
pub mod stats; pub mod stats;
// pub mod setting;
// pub mod stop_words; // pub mod stop_words;
// pub mod synonym; // pub mod synonym;
pub mod update;
#[derive(Default, Serialize)] #[derive(Default, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct IndexUpdateResponse { pub struct IndexUpdateResponse {
pub update_id: u64, pub update_id: u64,
pub see_more: String,
} }
impl IndexUpdateResponse { impl IndexUpdateResponse {
pub fn with_id(update_id: u64) -> Self { pub fn with_id(update_id: u64) -> Self {
Self { Self {
update_id, update_id,
see_more: "https://docs.meilisearch.com/guides/advanced_guides/asynchronous_updates.html".to_string()
} }
} }
} }

View File

@ -6,7 +6,8 @@ use log::warn;
use meilisearch_core::Index; use meilisearch_core::Index;
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use actix_web::*; use actix_web::{web, get, post};
use actix_web as aweb;
use crate::error::ResponseError; use crate::error::ResponseError;
use crate::helpers::meilisearch::{Error, IndexSearchExt, SearchHit, SearchResult}; use crate::helpers::meilisearch::{Error, IndexSearchExt, SearchHit, SearchResult};
@ -32,19 +33,19 @@ pub async fn search_with_url_query(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
params: web::Query<SearchQuery>, params: web::Query<SearchQuery>,
) -> Result<web::Json<SearchResult>> { ) -> aweb::Result<web::Json<SearchResult>> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let schema = index let schema = index
.main .main
.schema(&reader) .schema(&reader)
.map_err(|_| ResponseError::Schema)? .map_err(|err| ResponseError::Internal(err.to_string()))?
.ok_or(ResponseError::Schema)?; .ok_or(ResponseError::Internal("Impossible to retrieve the schema".to_string()))?;
let mut search_builder = index.new_search(params.q.clone()); let mut search_builder = index.new_search(params.q.clone());
@ -142,8 +143,8 @@ pub async fn search_with_url_query(
let response = match search_builder.search(&reader) { let response = match search_builder.search(&reader) {
Ok(response) => response, Ok(response) => response,
Err(Error::Internal(message)) => return Err(ResponseError::Internal(message))?, Err(Error::Internal(message)) => return Err(ResponseError::Internal(message).into()),
Err(others) => return Err(ResponseError::BadRequest(others.to_string()))?, Err(others) => return Err(ResponseError::BadRequest(others.to_string()).into()),
}; };
Ok(web::Json(response)) Ok(web::Json(response))
@ -179,7 +180,7 @@ pub struct SearchMultiBodyResponse {
pub async fn search_multi_index( pub async fn search_multi_index(
data: web::Data<Data>, data: web::Data<Data>,
body: web::Json<SearchMultiBody>, body: web::Json<SearchMultiBody>,
) -> Result<web::Json<SearchMultiBodyResponse>> { ) -> aweb::Result<web::Json<SearchMultiBodyResponse>> {
let mut index_list = body.clone().indexes; let mut index_list = body.clone().indexes;

View File

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use actix_web::*; use actix_web as aweb;
use actix_web::{web, get};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use log::error; use log::error;
use pretty_bytes::converter::convert; use pretty_bytes::converter::convert;
@ -23,12 +24,12 @@ pub struct IndexStatsResponse {
pub async fn index_stats( pub async fn index_stats(
data: web::Data<Data>, data: web::Data<Data>,
path: web::Path<String>, path: web::Path<String>,
) -> Result<web::Json<IndexStatsResponse>> { ) -> aweb::Result<web::Json<IndexStatsResponse>> {
let index = data.db.open_index(path.clone()) let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?; .ok_or(ResponseError::IndexNotFound(path.clone()))?;
let reader = data.db.main_read_txn() let reader = data.db.main_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let number_of_documents = index.main.number_of_documents(&reader) let number_of_documents = index.main.number_of_documents(&reader)
.map_err(|err| ResponseError::Internal(err.to_string()))?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
@ -38,7 +39,7 @@ pub async fn index_stats(
.unwrap_or_default(); .unwrap_or_default();
let update_reader = data.db.update_read_txn() let update_reader = data.db.update_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let is_indexing = data let is_indexing = data
.is_indexing(&update_reader, &path) .is_indexing(&update_reader, &path)
@ -63,14 +64,14 @@ pub struct StatsResult {
#[get("/stats")] #[get("/stats")]
pub async fn get_stats( pub async fn get_stats(
data: web::Data<Data>, data: web::Data<Data>,
) -> Result<web::Json<StatsResult>> { ) -> aweb::Result<web::Json<StatsResult>> {
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()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let update_reader = data.db.update_read_txn() let update_reader = data.db.update_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?; .map_err(|err| ResponseError::Internal(err.to_string()))?;
let indexes_set = data.db.indexes_uids(); let indexes_set = data.db.indexes_uids();
for index_uid in indexes_set { for index_uid in indexes_set {

View File

@ -1,44 +0,0 @@
use actix_web::*;
use meilisearch_core::UpdateStatus;
use crate::error::ResponseError;
use crate::Data;
#[get("/indexes/{index_uid}/updates/{update_id}")]
pub async fn get_update_status(
data: web::Data<Data>,
path: web::Path<(String, u64)>,
) -> Result<web::Json<UpdateStatus>> {
let index = data.db.open_index(path.0.clone())
.ok_or(ResponseError::IndexNotFound(path.0.clone()))?;
let reader = data.db.update_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?;
let status = index.update_status(&reader, path.1)
.map_err(|e| ResponseError::Internal(e.to_string()))?;
match status {
Some(status) => Ok(web::Json(status)),
None => Err(ResponseError::UpdateNotFound(path.1))?
}
}
#[get("/indexes/{index_uid}/updates")]
pub async fn get_all_updates_status(
data: web::Data<Data>,
path: web::Path<String>,
) -> Result<web::Json<Vec<UpdateStatus>>> {
let index = data.db.open_index(path.clone())
.ok_or(ResponseError::IndexNotFound(path.clone()))?;
let reader = data.db.update_read_txn()
.map_err(|_| ResponseError::CreateTransaction)?;
let response = index.all_updates_status(&reader)
.map_err(|err| ResponseError::Internal(err.to_string()))?;
Ok(web::Json(response))
}