2020-04-08 14:13:45 +02:00
use std ::{ env , thread } ;
2019-11-21 19:15:33 +01:00
2020-04-10 19:40:43 +02:00
use actix_cors ::Cors ;
2020-04-15 10:51:15 +02:00
use actix_web ::{ middleware , HttpServer } ;
2019-10-31 15:09:23 +01:00
use main_error ::MainError ;
2020-05-19 12:22:51 +02:00
use meilisearch_http ::helpers ::NormalizePath ;
2020-06-30 14:42:16 +02:00
use meilisearch_http ::{ create_app , index_update_callback , Data , Opt } ;
2020-04-10 19:05:05 +02:00
use structopt ::StructOpt ;
2020-09-29 12:18:09 +02:00
use meilisearch_http ::{ snapshot , dump } ;
2019-10-31 15:09:23 +01:00
2019-11-21 19:15:33 +01:00
mod analytics ;
2019-11-25 14:51:47 +01:00
#[ cfg(target_os = " linux " ) ]
2019-10-31 15:09:23 +01:00
#[ global_allocator ]
static ALLOC : jemallocator ::Jemalloc = jemallocator ::Jemalloc ;
2020-09-12 04:29:17 +02:00
#[ actix_web::main ]
2020-04-07 17:47:35 +02:00
async fn main ( ) -> Result < ( ) , MainError > {
2019-11-19 17:09:06 +01:00
let opt = Opt ::from_args ( ) ;
2019-11-15 17:33:06 +01:00
2020-05-14 10:42:01 +02:00
#[ cfg(all(not(debug_assertions), feature = " sentry " )) ]
2020-05-07 16:34:20 +02:00
let _sentry = sentry ::init ( (
2020-06-30 14:42:16 +02:00
if ! opt . no_sentry {
Some ( opt . sentry_dsn . clone ( ) )
} else {
None
} ,
2020-05-10 10:52:44 +02:00
sentry ::ClientOptions {
release : sentry ::release_name! ( ) ,
.. Default ::default ( )
} ,
2020-05-07 16:34:20 +02:00
) ) ;
2020-02-06 15:42:35 +01:00
match opt . env . as_ref ( ) {
" production " = > {
if opt . master_key . is_none ( ) {
2020-02-26 18:49:17 +01:00
return Err (
" In production mode, the environment variable MEILI_MASTER_KEY is mandatory "
. into ( ) ,
) ;
2020-02-06 15:42:35 +01:00
}
2020-05-07 16:58:48 +02:00
2020-05-14 10:42:01 +02:00
#[ cfg(all(not(debug_assertions), feature = " sentry " )) ]
2020-06-30 14:42:16 +02:00
if ! opt . no_sentry & & _sentry . is_enabled ( ) {
sentry ::integrations ::panic ::register_panic_handler ( ) ; // TODO: This shouldn't be needed when upgrading to sentry 0.19.0. These integrations are turned on by default when using `sentry::init`.
2020-05-07 16:34:20 +02:00
sentry ::integrations ::env_logger ::init ( None , Default ::default ( ) ) ;
}
2020-04-10 19:05:05 +02:00
}
2020-02-06 15:42:35 +01:00
" development " = > {
2020-12-09 10:25:17 +01:00
env_logger ::Builder ::from_env ( env_logger ::Env ::default ( ) . default_filter_or ( " info " ) ) . init ( ) ;
2020-02-26 18:49:17 +01:00
}
2020-02-06 15:42:35 +01:00
_ = > unreachable! ( ) ,
}
2020-10-15 12:06:11 +02:00
if let Some ( path ) = & opt . import_snapshot {
2020-07-02 16:20:45 +02:00
snapshot ::load_snapshot ( & opt . db_path , path , opt . ignore_snapshot_if_db_exists , opt . ignore_missing_snapshot ) ? ;
}
2020-06-24 16:06:04 +02:00
let data = Data ::new ( opt . clone ( ) ) ? ;
2020-05-26 19:03:13 +02:00
2020-02-06 15:42:35 +01:00
if ! opt . no_analytics {
2020-05-26 19:03:13 +02:00
let analytics_data = data . clone ( ) ;
let analytics_opt = opt . clone ( ) ;
2020-06-30 14:42:16 +02:00
thread ::spawn ( move | | analytics ::analytics_sender ( analytics_data , analytics_opt ) ) ;
2019-11-21 19:15:33 +01:00
}
2019-11-15 17:33:06 +01:00
let data_cloned = data . clone ( ) ;
data . db . set_update_callback ( Box ::new ( move | name , status | {
2020-04-08 14:13:45 +02:00
index_update_callback ( name , & data_cloned , status ) ;
2019-11-15 17:33:06 +01:00
} ) ) ;
2020-07-28 14:41:49 +02:00
2020-09-29 12:18:09 +02:00
if let Some ( path ) = & opt . import_dump {
dump ::import_dump ( & data , path , opt . dump_batch_size ) ? ;
2020-07-28 14:41:49 +02:00
}
2020-10-15 12:06:11 +02:00
if opt . schedule_snapshot {
snapshot ::schedule_snapshot ( data . clone ( ) , & opt . snapshot_dir , opt . snapshot_interval_sec . unwrap_or ( 86400 ) ) ? ;
2020-07-02 16:20:45 +02:00
}
2020-02-06 15:42:35 +01:00
print_launch_resume ( & opt , & data ) ;
2020-11-23 13:13:10 +01:00
let enable_frontend = opt . env ! = " production " ;
2020-05-10 10:52:44 +02:00
let http_server = HttpServer ::new ( move | | {
2021-01-12 16:46:53 +01:00
let cors = Cors ::default ( )
2020-04-14 18:00:35 +02:00
. send_wildcard ( )
2020-06-30 14:42:16 +02:00
. allowed_headers ( vec! [ " content-type " , " x-meili-api-key " ] )
2021-01-12 16:46:53 +01:00
. allow_any_origin ( )
. allow_any_method ( )
. max_age ( 86_400 ) ; // 24h
create_app ( & data , enable_frontend )
. wrap ( cors )
2020-04-10 19:40:43 +02:00
. wrap ( middleware ::Logger ::default ( ) )
. wrap ( middleware ::Compress ::default ( ) )
2020-05-19 12:22:51 +02:00
. wrap ( NormalizePath )
2020-05-10 10:52:44 +02:00
} ) ;
if let Some ( config ) = opt . get_ssl_config ( ) ? {
http_server
. bind_rustls ( opt . http_addr , config ) ?
. run ( )
. await ? ;
} else {
http_server . bind ( opt . http_addr ) ? . run ( ) . await ? ;
}
2019-10-31 15:09:23 +01:00
Ok ( ( ) )
2019-10-31 15:00:36 +01:00
}
2020-02-06 15:42:35 +01:00
pub fn print_launch_resume ( opt : & Opt , data : & Data ) {
let ascii_name = r #"
888 b d888 d8b 888 d8b . d8888b . 888
8888 b d8888 Y8P 888 Y8P d88P Y88b 888
88888 b . d88888 888 Y88b . 888
888 Y88888P888 . d88b . 888 888 888 " Y888b. .d88b. 8888b. 888d888 .d8888b 88888b.
888 Y888P 888 d8P Y8b 888 888 888 " Y88b. d8P Y8b " 88 b 888 P " d88P " 888 " 88b
888 Y8P 888 88888888 888 888 888 " 888 88888888 .d888888 888 888 888 888
888 " 888 Y8b. 888 888 888 Y88b d88P Y8b. 888 888 888 Y88b. 888 888
888 888 " Y8888 888 888 888 " Y8888P " " Y8888 " Y888888 888 " Y8888P 888 888
" #;
2020-05-14 10:04:18 +02:00
eprintln! ( " {} " , ascii_name ) ;
2020-02-06 15:42:35 +01:00
2020-05-14 10:04:18 +02:00
eprintln! ( " Database path: \t \t {:?} " , opt . db_path ) ;
eprintln! ( " Server listening on: \t {:?} " , opt . http_addr ) ;
eprintln! ( " Environment: \t \t {:?} " , opt . env ) ;
eprintln! ( " Commit SHA: \t \t {:?} " , env! ( " VERGEN_SHA " ) . to_string ( ) ) ;
eprintln! (
" Build date: \t \t {:?} " ,
2020-02-26 18:49:17 +01:00
env! ( " VERGEN_BUILD_TIMESTAMP " ) . to_string ( )
) ;
2020-05-14 10:04:18 +02:00
eprintln! (
" Package version: \t {:?} " ,
2020-02-26 18:49:17 +01:00
env! ( " CARGO_PKG_VERSION " ) . to_string ( )
) ;
2020-02-06 15:42:35 +01:00
2020-06-30 14:42:16 +02:00
#[ cfg(all(not(debug_assertions), feature = " sentry " )) ]
eprintln! (
" Sentry DSN: \t \t {:?} " ,
if ! opt . no_sentry {
& opt . sentry_dsn
} else {
" Disabled "
}
) ;
2020-07-01 17:54:48 +02:00
eprintln! (
" Amplitude Analytics: \t {:?} " ,
if ! opt . no_analytics {
" Enabled "
} else {
" Disabled "
}
) ;
2020-05-14 10:04:18 +02:00
eprintln! ( ) ;
2020-05-19 10:24:03 +02:00
if data . api_keys . master . is_some ( ) {
eprintln! ( " A Master Key has been set. Requests to MeiliSearch won't be authorized unless you provide an authentication key. " ) ;
2020-02-06 15:42:35 +01:00
} else {
2020-05-14 10:04:18 +02:00
eprintln! ( " No master key found; The server will accept unidentified requests. \
If you need some protection in development mode , please export a key : export MEILI_MASTER_KEY = xxx " );
2020-02-06 15:42:35 +01:00
}
2020-05-14 10:04:18 +02:00
eprintln! ( ) ;
2020-05-29 15:46:00 +02:00
eprintln! ( " Documentation: \t \t https://docs.meilisearch.com " ) ;
eprintln! ( " Source code: \t \t https://github.com/meilisearch/meilisearch " ) ;
2020-05-14 10:04:18 +02:00
eprintln! ( " Contact: \t \t https://docs.meilisearch.com/resources/contact.html or bonjour@meilisearch.com " ) ;
eprintln! ( ) ;
2020-02-06 15:42:35 +01:00
}