2020-12-22 21:02:41 +08:00
use std ::env ;
2020-12-12 20:32:06 +08:00
use actix_cors ::Cors ;
2021-02-26 16:10:04 +08:00
use actix_web ::{ middleware , HttpServer , web , web ::ServiceConfig } ;
2020-12-12 20:32:06 +08:00
use main_error ::MainError ;
2021-02-26 16:10:04 +08:00
use meilisearch ::{ Data , Opt } ;
2020-12-12 20:32:06 +08:00
use structopt ::StructOpt ;
2021-02-26 16:10:04 +08:00
use actix_web ::App ;
use meilisearch ::error ::payload_error_handler ;
use actix_web ::middleware ::TrailingSlash ;
2020-12-12 20:32:06 +08:00
2020-12-22 21:02:41 +08:00
//mod analytics;
2020-12-12 20:32:06 +08:00
#[ cfg(target_os = " linux " ) ]
#[ global_allocator ]
static ALLOC : jemallocator ::Jemalloc = jemallocator ::Jemalloc ;
#[ actix_web::main ]
async fn main ( ) -> Result < ( ) , MainError > {
let opt = Opt ::from_args ( ) ;
#[ cfg(all(not(debug_assertions), feature = " sentry " )) ]
let _sentry = sentry ::init ( (
if ! opt . no_sentry {
Some ( opt . sentry_dsn . clone ( ) )
} else {
None
} ,
sentry ::ClientOptions {
release : sentry ::release_name! ( ) ,
.. Default ::default ( )
} ,
) ) ;
match opt . env . as_ref ( ) {
" production " = > {
if opt . master_key . is_none ( ) {
return Err (
" In production mode, the environment variable MEILI_MASTER_KEY is mandatory "
. into ( ) ,
) ;
}
#[ cfg(all(not(debug_assertions), feature = " sentry " )) ]
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`.
sentry ::integrations ::env_logger ::init ( None , Default ::default ( ) ) ;
}
}
" development " = > {
env_logger ::Builder ::from_env ( env_logger ::Env ::default ( ) . default_filter_or ( " info " ) ) . init ( ) ;
}
_ = > unreachable! ( ) ,
}
2020-12-22 21:02:41 +08:00
//if let Some(path) = &opt.import_snapshot {
//snapshot::load_snapshot(&opt.db_path, path, opt.ignore_snapshot_if_db_exists, opt.ignore_missing_snapshot)?;
//}
2020-12-12 20:32:06 +08:00
let data = Data ::new ( opt . clone ( ) ) ? ;
2020-12-22 21:02:41 +08:00
//if !opt.no_analytics {
//let analytics_data = data.clone();
//let analytics_opt = opt.clone();
//thread::spawn(move || analytics::analytics_sender(analytics_data, analytics_opt));
//}
2020-12-12 20:32:06 +08:00
2020-12-22 21:02:41 +08:00
//if let Some(path) = &opt.import_dump {
//dump::import_dump(&data, path, opt.dump_batch_size)?;
//}
2020-12-12 20:32:06 +08:00
2020-12-22 21:02:41 +08:00
//if opt.schedule_snapshot {
//snapshot::schedule_snapshot(data.clone(), &opt.snapshot_dir, opt.snapshot_interval_sec.unwrap_or(86400))?;
//}
2020-12-12 20:32:06 +08:00
print_launch_resume ( & opt , & data ) ;
let enable_frontend = opt . env ! = " production " ;
2021-02-26 16:10:04 +08:00
run_http ( data , opt , enable_frontend ) . await ? ;
Ok ( ( ) )
}
async fn run_http ( data : Data , opt : Opt , enable_frontend : bool ) -> Result < ( ) , Box < dyn std ::error ::Error > > {
2020-12-12 20:32:06 +08:00
let http_server = HttpServer ::new ( move | | {
2021-02-26 16:10:04 +08:00
let app = App ::new ( )
. configure ( | c | configure_data ( c , & data ) )
. configure ( meilisearch ::routes ::document ::services )
. configure ( meilisearch ::routes ::index ::services )
. configure ( meilisearch ::routes ::search ::services )
. configure ( meilisearch ::routes ::settings ::services )
. configure ( meilisearch ::routes ::stop_words ::services )
. configure ( meilisearch ::routes ::synonym ::services )
. configure ( meilisearch ::routes ::health ::services )
. configure ( meilisearch ::routes ::stats ::services )
. configure ( meilisearch ::routes ::key ::services ) ;
//.configure(routes::dump::services);
let app = if enable_frontend {
app
. service ( meilisearch ::routes ::load_html )
. service ( meilisearch ::routes ::load_css )
} else {
app
} ;
app . wrap (
2020-12-12 20:32:06 +08:00
Cors ::default ( )
. send_wildcard ( )
. allowed_headers ( vec! [ " content-type " , " x-meili-api-key " ] )
. max_age ( 86_400 ) // 24h
)
. wrap ( middleware ::Logger ::default ( ) )
. wrap ( middleware ::Compress ::default ( ) )
2021-02-26 16:10:04 +08:00
. wrap ( middleware ::NormalizePath ::new ( TrailingSlash ::Trim ) )
2020-12-12 20:32:06 +08: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 ? ;
}
Ok ( ( ) )
}
2021-02-26 16:10:04 +08:00
fn configure_data ( config : & mut ServiceConfig , data : & Data ) {
config
. data ( data . clone ( ) )
. app_data (
web ::JsonConfig ::default ( )
. limit ( data . http_payload_size_limit ( ) )
. content_type ( | _mime | true ) // Accept all mime types
. error_handler ( | err , _req | payload_error_handler ( err ) . into ( ) ) ,
)
. app_data (
web ::QueryConfig ::default ( )
. error_handler ( | err , _req | payload_error_handler ( err ) . into ( ) )
) ;
}
2020-12-12 20:32:06 +08: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
" #;
eprintln! ( " {} " , ascii_name ) ;
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 {:?} " ,
env! ( " VERGEN_BUILD_TIMESTAMP " ) . to_string ( )
) ;
eprintln! (
" Package version: \t {:?} " ,
env! ( " CARGO_PKG_VERSION " ) . to_string ( )
) ;
#[ cfg(all(not(debug_assertions), feature = " sentry " )) ]
eprintln! (
" Sentry DSN: \t \t {:?} " ,
if ! opt . no_sentry {
& opt . sentry_dsn
} else {
" Disabled "
}
) ;
eprintln! (
" Amplitude Analytics: \t {:?} " ,
if ! opt . no_analytics {
" Enabled "
} else {
" Disabled "
}
) ;
eprintln! ( ) ;
2020-12-23 00:53:13 +08:00
if data . api_keys ( ) . master . is_some ( ) {
2020-12-12 20:32:06 +08:00
eprintln! ( " A Master Key has been set. Requests to MeiliSearch won't be authorized unless you provide an authentication key. " ) ;
} else {
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 " );
}
eprintln! ( ) ;
eprintln! ( " Documentation: \t \t https://docs.meilisearch.com " ) ;
eprintln! ( " Source code: \t \t https://github.com/meilisearch/meilisearch " ) ;
eprintln! ( " Contact: \t \t https://docs.meilisearch.com/resources/contact.html or bonjour@meilisearch.com " ) ;
eprintln! ( ) ;
}