feat: upgrade to actix-web 2.0 (#80)

* chore: update actix-web to 2.0

* fix: use default CORS middleware
This commit is contained in:
Stepan Kuzmin 2020-04-26 17:57:13 +03:00 committed by GitHub
parent 47b4c1cb8b
commit ad3076812d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 685 additions and 909 deletions

1383
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -13,9 +13,10 @@ name = "martin"
path = "src/bin/main.rs"
[dependencies]
actix = "0.8"
actix-rt = "0.2"
actix-web = "1.0"
actix = "0.9"
actix-rt = "1.0"
actix-web = "2.0"
actix-cors = "0.2"
docopt = "1"
env_logger = "0.7"
futures = "0.1"
@ -36,4 +37,4 @@ criterion = "0.3"
[[bench]]
name = "server"
harness = false
harness = false

View File

@ -8,7 +8,7 @@ use martin::server::router;
fn criterion_benchmark(c: &mut Criterion) {
let state = test::run_on(|| mock_state(mock_table_sources(), mock_function_sources()));
let mut app = test::init_service(App::new().data(state).configure(router));
let mut app = test::init_service(App::new().app_data(state).configure(router));
c.bench_function("/public.table_source/0/0/0.pbf", |b| {
b.iter(|| {

View File

@ -1,4 +1,3 @@
use num_cpus;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io;

View File

@ -4,10 +4,10 @@ use std::collections::HashMap;
use std::rc::Rc;
use actix::{Actor, Addr, SyncArbiter, SystemRunner};
use actix_cors::Cors;
use actix_web::{
error, http, middleware, web, App, Either, Error, HttpRequest, HttpResponse, HttpServer, Result,
error, http, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result,
};
use futures::Future;
use crate::config::Config;
use crate::coordinator_actor::CoordinatorActor;
@ -42,35 +42,30 @@ struct TileRequest {
format: String,
}
type SourcesResult = Either<HttpResponse, Box<dyn Future<Item = HttpResponse, Error = Error>>>;
fn get_table_sources(state: web::Data<AppState>) -> SourcesResult {
async fn get_table_sources(state: web::Data<AppState>) -> Result<HttpResponse, Error> {
if !state.watch_mode {
let table_sources = state.table_sources.borrow().clone();
let response = HttpResponse::Ok().json(table_sources);
return Either::A(response);
return Ok(response);
}
info!("Scanning database for table sources");
let response = state
let table_sources = state
.db
.send(messages::GetTableSources {})
.from_err()
.and_then(move |table_sources| match table_sources {
Ok(table_sources) => {
state.coordinator.do_send(messages::RefreshTableSources {
table_sources: Some(table_sources.clone()),
});
.await
.map_err(|_| HttpResponse::InternalServerError())?
.map_err(|_| HttpResponse::InternalServerError())?;
Ok(HttpResponse::Ok().json(table_sources))
}
Err(_) => Ok(HttpResponse::InternalServerError().into()),
});
state.coordinator.do_send(messages::RefreshTableSources {
table_sources: Some(table_sources.clone()),
});
Either::B(Box::new(response))
Ok(HttpResponse::Ok().json(table_sources))
}
fn get_table_source(
async fn get_table_source(
req: HttpRequest,
path: web::Path<SourceRequest>,
state: web::Data<AppState>,
@ -121,10 +116,10 @@ fn get_table_source(
Ok(HttpResponse::Ok().json(tilejson))
}
fn get_table_source_tile(
async fn get_table_source_tile(
path: web::Path<TileRequest>,
state: web::Data<AppState>,
) -> Result<Box<dyn Future<Item = HttpResponse, Error = Error>>> {
) -> Result<HttpResponse, Error> {
let table_sources = state
.table_sources
.borrow()
@ -147,52 +142,47 @@ fn get_table_source_tile(
source: source.clone(),
};
let response = state
let tile = state
.db
.send(message)
.from_err()
.and_then(|result| match result {
Ok(tile) => match tile.len() {
0 => Ok(HttpResponse::NoContent()
.content_type("application/x-protobuf")
.body(tile)),
_ => Ok(HttpResponse::Ok()
.content_type("application/x-protobuf")
.body(tile)),
},
Err(_) => Ok(HttpResponse::InternalServerError().into()),
});
.await
.map_err(|_| HttpResponse::InternalServerError())?
.map_err(|_| HttpResponse::InternalServerError())?;
Ok(Box::new(response))
match tile.len() {
0 => Ok(HttpResponse::NoContent()
.content_type("application/x-protobuf")
.body(tile)),
_ => Ok(HttpResponse::Ok()
.content_type("application/x-protobuf")
.body(tile)),
}
}
fn get_function_sources(state: web::Data<AppState>) -> SourcesResult {
async fn get_function_sources(state: web::Data<AppState>) -> Result<HttpResponse, Error> {
if !state.watch_mode {
let function_sources = state.function_sources.borrow().clone();
let response = HttpResponse::Ok().json(function_sources);
return Either::A(response);
return Ok(response);
}
info!("Scanning database for function sources");
let response = state
let function_sources = state
.db
.send(messages::GetFunctionSources {})
.from_err()
.and_then(move |function_sources| match function_sources {
Ok(function_sources) => {
state.coordinator.do_send(messages::RefreshFunctionSources {
function_sources: Some(function_sources.clone()),
});
.await
.map_err(|_| HttpResponse::InternalServerError())?
.map_err(|_| HttpResponse::InternalServerError())?;
Ok(HttpResponse::Ok().json(function_sources))
}
Err(_) => Ok(HttpResponse::InternalServerError().into()),
});
state.coordinator.do_send(messages::RefreshFunctionSources {
function_sources: Some(function_sources.clone()),
});
Either::B(Box::new(response))
Ok(HttpResponse::Ok().json(function_sources))
}
fn get_function_source(
async fn get_function_source(
req: HttpRequest,
path: web::Path<SourceRequest>,
state: web::Data<AppState>,
@ -243,11 +233,11 @@ fn get_function_source(
Ok(HttpResponse::Ok().json(tilejson))
}
fn get_function_source_tile(
async fn get_function_source_tile(
path: web::Path<TileRequest>,
query: web::Query<HashMap<String, String>>,
state: web::Data<AppState>,
) -> Result<Box<dyn Future<Item = HttpResponse, Error = Error>>> {
) -> Result<HttpResponse, Error> {
let function_sources = state
.function_sources
.borrow()
@ -270,23 +260,21 @@ fn get_function_source_tile(
source: source.clone(),
};
let response = state
let tile = state
.db
.send(message)
.from_err()
.and_then(|result| match result {
Ok(tile) => match tile.len() {
0 => Ok(HttpResponse::NoContent()
.content_type("application/x-protobuf")
.body(tile)),
_ => Ok(HttpResponse::Ok()
.content_type("application/x-protobuf")
.body(tile)),
},
Err(_) => Ok(HttpResponse::InternalServerError().into()),
});
.await
.map_err(|_| HttpResponse::InternalServerError())?
.map_err(|_| HttpResponse::InternalServerError())?;
Ok(Box::new(response))
match tile.len() {
0 => Ok(HttpResponse::NoContent()
.content_type("application/x-protobuf")
.body(tile)),
_ => Ok(HttpResponse::Ok()
.content_type("application/x-protobuf")
.body(tile)),
}
}
pub fn router(cfg: &mut web::ServiceConfig) {
@ -343,8 +331,7 @@ pub fn new(pool: PostgresPool, config: Config, watch_mode: bool) -> SystemRunner
HttpServer::new(move || {
let state = create_state(db.clone(), coordinator.clone(), config.clone(), watch_mode);
let cors_middleware = middleware::DefaultHeaders::new()
.header(http::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*");
let cors_middleware = Cors::default();
App::new()
.data(state)
@ -359,7 +346,7 @@ pub fn new(pool: PostgresPool, config: Config, watch_mode: bool) -> SystemRunner
.keep_alive(keep_alive)
.shutdown_timeout(0)
.workers(worker_processes)
.start();
.run();
sys
}

View File

@ -1,4 +1,3 @@
use serde_json;
use std::collections::HashMap;
use crate::source::{Query, XYZ};

View File

@ -1,6 +1,5 @@
extern crate log;
use actix_web::dev::Service;
use actix_web::{http, test, App};
use martin::dev::{mock_function_sources, mock_state, mock_table_sources};
@ -8,100 +7,96 @@ use martin::function_source::FunctionSources;
use martin::server::router;
use martin::table_source::TableSources;
#[test]
fn test_get_table_sources_ok() {
let state = test::run_on(|| mock_state(mock_table_sources(), None));
let mut app = test::init_service(App::new().data(state).configure(router));
#[actix_rt::test]
async fn test_get_table_sources_ok() {
let state = mock_state(mock_table_sources(), None);
let mut app = test::init_service(App::new().data(state).configure(router)).await;
let req = test::TestRequest::get().uri("/index.json").to_request();
let response = test::block_on(app.call(req)).unwrap();
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
let body = test::read_body(response);
let body = test::read_body(response).await;
let table_sources: TableSources = serde_json::from_slice(&body).unwrap();
assert!(table_sources.contains_key("public.table_source"));
}
#[test]
fn test_get_table_source_ok() {
let state = test::run_on(|| mock_state(mock_table_sources(), None));
let mut app = test::init_service(App::new().data(state).configure(router));
#[actix_rt::test]
async fn test_get_table_source_ok() {
let state = mock_state(mock_table_sources(), None);
let mut app = test::init_service(App::new().data(state).configure(router)).await;
let req = test::TestRequest::get()
.uri("/public.non_existant.json")
.to_request();
let response = test::block_on(app.call(req)).unwrap();
let response = test::call_service(&mut app, req).await;
assert_eq!(response.status(), http::StatusCode::NOT_FOUND);
let req = test::TestRequest::get()
.uri("/public.table_source.json")
.to_request();
let response = test::block_on(app.call(req)).unwrap();
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
}
#[test]
fn test_get_table_source_tile_ok() {
let state = test::run_on(|| mock_state(mock_table_sources(), None));
let mut app = test::init_service(App::new().data(state).configure(router));
#[actix_rt::test]
async fn test_get_table_source_tile_ok() {
let state = mock_state(mock_table_sources(), None);
let mut app = test::init_service(App::new().data(state).configure(router)).await;
let req = test::TestRequest::get()
.uri("/public.table_source/0/0/0.pbf")
.to_request();
let future = test::run_on(|| app.call(req));
let response = test::block_on(future).unwrap();
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
}
#[test]
fn test_get_function_sources_ok() {
let state = test::run_on(|| mock_state(None, mock_function_sources()));
let mut app = test::init_service(App::new().data(state).configure(router));
#[actix_rt::test]
async fn test_get_function_sources_ok() {
let state = mock_state(None, mock_function_sources());
let mut app = test::init_service(App::new().data(state).configure(router)).await;
let req = test::TestRequest::get().uri("/rpc/index.json").to_request();
let response = test::block_on(app.call(req)).unwrap();
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
let body = test::read_body(response);
let body = test::read_body(response).await;
let function_sources: FunctionSources = serde_json::from_slice(&body).unwrap();
assert!(function_sources.contains_key("public.function_source"));
}
#[test]
fn test_get_function_source_ok() {
let state = test::run_on(|| mock_state(None, mock_function_sources()));
let mut app = test::init_service(App::new().data(state).configure(router));
#[actix_rt::test]
async fn test_get_function_source_ok() {
let state = mock_state(None, mock_function_sources());
let mut app = test::init_service(App::new().data(state).configure(router)).await;
let req = test::TestRequest::get()
.uri("/rpc/public.non_existant.json")
.to_request();
let response = test::block_on(app.call(req)).unwrap();
let response = test::call_service(&mut app, req).await;
assert_eq!(response.status(), http::StatusCode::NOT_FOUND);
let req = test::TestRequest::get()
.uri("/rpc/public.function_source.json")
.to_request();
let response = test::block_on(app.call(req)).unwrap();
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
}
#[test]
fn test_get_function_source_tile_ok() {
let state = test::run_on(|| mock_state(None, mock_function_sources()));
let mut app = test::init_service(App::new().data(state).configure(router));
#[actix_rt::test]
async fn test_get_function_source_tile_ok() {
let state = mock_state(None, mock_function_sources());
let mut app = test::init_service(App::new().data(state).configure(router)).await;
let req = test::TestRequest::get()
.uri("/rpc/public.function_source/0/0/0.pbf")
.to_request();
let future = test::run_on(|| app.call(req));
let response = test::block_on(future).unwrap();
let response = test::call_service(&mut app, req).await;
assert!(response.status().is_success());
}