1
0
mirror of https://github.com/actix/examples synced 2024-11-23 14:31:07 +01:00

upgrade to 2.0 alpha.3

This commit is contained in:
Nikolay Kim 2019-12-07 23:59:24 +06:00
parent e7f7175b7b
commit 3127352797
100 changed files with 1075 additions and 1107 deletions

View File

@ -1,8 +1,6 @@
[workspace]
members = [
"./",
"actix_redis",
"actix_todo",
# "actix_redis",
"async_db",
"async_ex1",
"async_ex2",
@ -21,24 +19,28 @@ members = [
"juniper",
"middleware",
"multipart",
"protobuf",
"openssl",
# "protobuf",
"r2d2",
"redis-session",
# "redis-session",
"rustls",
"server-sent-events",
"simple-auth-server",
"state",
"static_index",
"template_askama",
"template_tera",
"template_yarte",
"template_handlebars",
"tls",
"udp-echo",
"template_tera",
# "template_yarte",
"todo",
# "udp-echo",
"unix-socket",
"web-cors/backend",
"websocket",
"websocket-chat",
"websocket-chat-broker",
"websocket-tcp-chat",
# "web-cors/backend",
# "websocket",
# "websocket-chat",
# "websocket-chat-broker",
# "websocket-tcp-chat",
]
[patch.crates-io]
actix-http = { git = "https://github.com/actix/actix-web.git" }

View File

@ -1,168 +0,0 @@
use actix_files::NamedFile;
use actix_session::Session;
use actix_web::middleware::errhandlers::ErrorHandlerResponse;
use actix_web::{dev, error, http, web, Error, HttpResponse, Responder, Result};
use futures::future::{err, Either, Future, IntoFuture};
use tera::{Context, Tera};
use crate::db;
use crate::session::{self, FlashMessage};
pub fn index(
pool: web::Data<db::PgPool>,
tmpl: web::Data<Tera>,
session: Session,
) -> impl Future<Item = HttpResponse, Error = Error> {
web::block(move || db::get_all_tasks(&pool))
.from_err()
.then(move |res| match res {
Ok(tasks) => {
let mut context = Context::new();
context.insert("tasks", &tasks);
//Session is set during operations on other endpoints
//that can redirect to index
if let Some(flash) = session::get_flash(&session)? {
context.insert("msg", &(flash.kind, flash.message));
session::clear_flash(&session);
}
let rendered =
tmpl.render("index.html.tera", &context).map_err(|e| {
error::ErrorInternalServerError(e.description().to_owned())
})?;
Ok(HttpResponse::Ok().body(rendered))
}
Err(e) => Err(e),
})
}
#[derive(Deserialize)]
pub struct CreateForm {
description: String,
}
pub fn create(
params: web::Form<CreateForm>,
pool: web::Data<db::PgPool>,
session: Session,
) -> impl Future<Item = HttpResponse, Error = Error> {
if params.description.is_empty() {
Either::A(
session::set_flash(
&session,
FlashMessage::error("Description cannot be empty"),
)
.map(|_| redirect_to("/"))
.into_future(),
)
} else {
Either::B(
web::block(move || db::create_task(params.into_inner().description, &pool))
.from_err()
.then(move |res| match res {
Ok(_) => {
session::set_flash(
&session,
FlashMessage::success("Task successfully added"),
)?;
Ok(redirect_to("/"))
}
Err(e) => Err(e),
}),
)
}
}
#[derive(Deserialize)]
pub struct UpdateParams {
id: i32,
}
#[derive(Deserialize)]
pub struct UpdateForm {
_method: String,
}
pub fn update(
db: web::Data<db::PgPool>,
params: web::Path<UpdateParams>,
form: web::Form<UpdateForm>,
session: Session,
) -> impl Future<Item = HttpResponse, Error = Error> {
match form._method.as_ref() {
"put" => Either::A(Either::A(toggle(db, params))),
"delete" => Either::A(Either::B(delete(db, params, session))),
unsupported_method => {
let msg = format!("Unsupported HTTP method: {}", unsupported_method);
Either::B(err(error::ErrorBadRequest(msg)))
}
}
}
fn toggle(
pool: web::Data<db::PgPool>,
params: web::Path<UpdateParams>,
) -> impl Future<Item = HttpResponse, Error = Error> {
web::block(move || db::toggle_task(params.id, &pool))
.from_err()
.then(move |res| match res {
Ok(_) => Ok(redirect_to("/")),
Err(e) => Err(e),
})
}
fn delete(
pool: web::Data<db::PgPool>,
params: web::Path<UpdateParams>,
session: Session,
) -> impl Future<Item = HttpResponse, Error = Error> {
web::block(move || db::delete_task(params.id, &pool))
.from_err()
.then(move |res| match res {
Ok(_) => {
session::set_flash(
&session,
FlashMessage::success("Task was deleted."),
)?;
Ok(redirect_to("/"))
}
Err(e) => Err(e),
})
}
fn redirect_to(location: &str) -> HttpResponse {
HttpResponse::Found()
.header(http::header::LOCATION, location)
.finish()
}
pub fn bad_request<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/400.html")?
.set_status_code(res.status())
.respond_to(res.request())?;
Ok(ErrorHandlerResponse::Response(
res.into_response(new_resp.into_body()),
))
}
pub fn not_found<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/404.html")?
.set_status_code(res.status())
.respond_to(res.request())?;
Ok(ErrorHandlerResponse::Response(
res.into_response(new_resp.into_body()),
))
}
pub fn internal_server_error<B>(
res: dev::ServiceResponse<B>,
) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/500.html")?
.set_status_code(res.status())
.respond_to(res.request())?;
Ok(ErrorHandlerResponse::Response(
res.into_response(new_resp.into_body()),
))
}

View File

@ -1,18 +1,18 @@
[package]
name = "async_db"
version = "0.1.0"
version = "2.0.0"
authors = ["Darin Gordon <dkcdkg@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-rt = "0.2.2"
actix-web = "1.0.0"
actix-rt = "1.0.0-alpha.3"
actix-web = "2.0.0-alpha.3"
dotenv = "0.10"
env_logger = "0.5"
env_logger = "0.6"
failure = "0.1.1"
futures = "0.1"
futures = "0.3.1"
num_cpus = "1.10.0"
r2d2 = "0.8.2"
r2d2_sqlite = "0.8.0"

View File

@ -1,6 +1,6 @@
use actix_web::{web, Error as AWError};
use failure::Error;
use futures::Future;
use futures::{Future, TryFutureExt};
use r2d2;
use r2d2_sqlite;
use rusqlite::NO_PARAMS;
@ -26,7 +26,7 @@ pub enum Queries {
pub fn execute(
pool: &Pool,
query: Queries,
) -> impl Future<Item = Vec<WeatherAgg>, Error = AWError> {
) -> impl Future<Output = Result<Vec<WeatherAgg>, AWError>> {
let pool = pool.clone();
web::block(move || match query {
Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?),
@ -34,7 +34,7 @@ pub fn execute(
Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?),
Queries::GetTopTenColdestMonths => get_coldest_months(pool.get()?),
})
.from_err()
.map_err(AWError::from)
}
fn get_hottest_years(conn: Connection) -> Result<Vec<WeatherAgg>, Error> {

View File

@ -14,64 +14,42 @@ This project illustrates two examples:
use std::io;
use actix_web::{middleware, web, App, Error as AWError, HttpResponse, HttpServer};
use futures::future::{join_all, ok as fut_ok, Future};
use r2d2_sqlite;
use r2d2_sqlite::SqliteConnectionManager;
use futures::future::join_all;
use r2d2_sqlite::{self, SqliteConnectionManager};
mod db;
use db::{Pool, Queries, WeatherAgg};
use db::{Pool, Queries};
/// Version 1: Calls 4 queries in sequential order, as an asynchronous handler
fn asyncio_weather(
db: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = AWError> {
let mut result: Vec<Vec<WeatherAgg>> = vec![];
async fn asyncio_weather(db: web::Data<Pool>) -> Result<HttpResponse, AWError> {
let result = vec![
db::execute(&db, Queries::GetTopTenHottestYears).await?,
db::execute(&db, Queries::GetTopTenColdestYears).await?,
db::execute(&db, Queries::GetTopTenHottestMonths).await?,
db::execute(&db, Queries::GetTopTenColdestMonths).await?,
];
db::execute(&db, Queries::GetTopTenHottestYears)
.from_err()
.and_then(move |res| {
result.push(res);
db::execute(&db, Queries::GetTopTenColdestYears)
.from_err()
.and_then(move |res| {
result.push(res);
db::execute(&db, Queries::GetTopTenHottestMonths)
.from_err()
.and_then(move |res| {
result.push(res);
db::execute(&db, Queries::GetTopTenColdestMonths)
.from_err()
.and_then(move |res| {
result.push(res);
fut_ok(result)
})
})
})
})
.and_then(|res| Ok(HttpResponse::Ok().json(res)))
Ok(HttpResponse::Ok().json(result))
}
/// Version 2: Calls 4 queries in parallel, as an asynchronous handler
/// Returning Error types turn into None values in the response
fn parallel_weather(
db: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = AWError> {
async fn parallel_weather(db: web::Data<Pool>) -> Result<HttpResponse, AWError> {
let fut_result = vec![
Box::new(db::execute(&db, Queries::GetTopTenHottestYears)),
Box::new(db::execute(&db, Queries::GetTopTenColdestYears)),
Box::new(db::execute(&db, Queries::GetTopTenHottestMonths)),
Box::new(db::execute(&db, Queries::GetTopTenColdestMonths)),
Box::pin(db::execute(&db, Queries::GetTopTenHottestYears)),
Box::pin(db::execute(&db, Queries::GetTopTenColdestYears)),
Box::pin(db::execute(&db, Queries::GetTopTenHottestMonths)),
Box::pin(db::execute(&db, Queries::GetTopTenColdestMonths)),
];
let result: Result<Vec<_>, _> = join_all(fut_result).await.into_iter().collect();
join_all(fut_result)
.map_err(AWError::from)
.map(|result| HttpResponse::Ok().json(result))
Ok(HttpResponse::Ok().json(result.map_err(AWError::from)?))
}
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix_rt::System::new("parallel_db_example");
// Start N db executor actors (N = number of cores avail)
let manager = SqliteConnectionManager::file("weather.db");
@ -80,20 +58,18 @@ fn main() -> io::Result<()> {
// Start http server
HttpServer::new(move || {
App::new()
// store db pool as Data object
.data(pool.clone())
.wrap(middleware::Logger::default())
.service(
web::resource("/asyncio_weather")
.route(web::get().to_async(asyncio_weather)),
web::resource("/asyncio_weather").route(web::get().to(asyncio_weather)),
)
.service(
web::resource("/parallel_weather")
.route(web::get().to_async(parallel_weather)),
.route(web::get().to(parallel_weather)),
)
})
.bind("127.0.0.1:8080")?
.start();
println!("Started http server: 127.0.0.1:8080");
sys.run()
.start()
.await
}

View File

@ -1,18 +1,18 @@
[package]
name = "awc_examples"
version = "0.1.0"
version = "2.0.0"
authors = ["dowwie <dkcdkg@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-rt = "0.2.2"
actix-web = { version="1.0.0", features=["ssl"] }
actix-rt = "1.0.0-alpha.3"
actix-web = { version="2.0.0-alpha.3", features=["openssl"] }
futures = "0.1"
futures = "0.3.1"
serde = "1.0.43"
serde_derive = "1.0.43"
serde_json = "1.0.16"
validator = "0.6.3"
validator_derive = "0.6.5"
env_logger = "0.5.9"
env_logger = "0.6"

View File

@ -26,7 +26,7 @@ use actix_web::{
web::{self, BytesMut},
App, Error, HttpResponse, HttpServer,
};
use futures::{Future, Stream};
use futures::StreamExt;
use validator::Validate;
#[derive(Debug, Validate, Deserialize, Serialize)]
@ -50,56 +50,51 @@ struct HttpBinResponse {
}
/// validate data, post json to httpbin, get it back in the response body, return deserialized
fn step_x(
data: SomeData,
client: &Client,
) -> impl Future<Item = SomeData, Error = Error> {
let validation = futures::future::result(data.validate()).map_err(ErrorBadRequest);
let post_response = client
async fn step_x(data: SomeData, client: &Client) -> Result<SomeData, Error> {
// validate data
data.validate().map_err(ErrorBadRequest)?;
let mut res = client
.post("https://httpbin.org/post")
.send_json(&data)
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(|resp| {
resp.from_err()
.fold(BytesMut::new(), |mut acc, chunk| {
acc.extend_from_slice(&chunk);
Ok::<_, Error>(acc)
})
.map(|body| {
let body: HttpBinResponse = serde_json::from_slice(&body).unwrap();
body.json
})
});
.await
.map_err(Error::from)?; // <- convert SendRequestError to an Error
validation.and_then(|_| post_response)
let mut body = BytesMut::new();
while let Some(chunk) = res.next().await {
body.extend_from_slice(&chunk?);
}
fn create_something(
let body: HttpBinResponse = serde_json::from_slice(&body).unwrap();
Ok(body.json)
}
async fn create_something(
some_data: web::Json<SomeData>,
client: web::Data<Client>,
) -> impl Future<Item = HttpResponse, Error = Error> {
step_x(some_data.into_inner(), &client).and_then(move |some_data_2| {
step_x(some_data_2, &client).and_then(move |some_data_3| {
step_x(some_data_3, &client).and_then(|d| {
) -> Result<HttpResponse, Error> {
let some_data_2 = step_x(some_data.into_inner(), &client).await?;
let some_data_3 = step_x(some_data_2, &client).await?;
let d = step_x(some_data_3, &client).await?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(serde_json::to_string(&d).unwrap()))
})
})
})
}
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let endpoint = "127.0.0.1:8080";
println!("Starting server at: {:?}", endpoint);
HttpServer::new(|| {
App::new().data(Client::default()).service(
web::resource("/something").route(web::post().to_async(create_something)),
)
App::new()
.data(Client::default())
.service(web::resource("/something").route(web::post().to(create_something)))
})
.bind(endpoint)?
.run()
.start()
.await
}

View File

@ -6,13 +6,13 @@ edition = "2018"
workspace = ".."
[dependencies]
actix-rt = "0.2.2"
actix-web = { version="1.0.0", features=["ssl"] }
actix-multipart = "0.1.1"
actix-service = "0.4.1"
bytes = "0.4.12"
actix-rt = "1.0.0-alpha.3"
actix-web = { version="2.0.0-alpha.3", features=["openssl"] }
actix-multipart = "0.2.0-alpha.2"
actix-service = "1.0.0-alpha.3"
bytes = "0.5.2"
env_logger = "0.6.1"
futures = "0.1"
futures = "0.3.1"
serde = { version = "^1.0", features = ["derive"] }
serde_derive = "1.0.90"
serde_json = "1.0.39"

View File

@ -8,27 +8,27 @@ pub fn config_app(cfg: &mut web::ServiceConfig) {
web::scope("/products")
.service(
web::resource("")
.route(web::get().to_async(products::get_products))
.route(web::post().to_async(products::add_product)),
.route(web::get().to(products::get_products))
.route(web::post().to(products::add_product)),
)
.service(
web::scope("/{product_id}")
.service(
web::resource("")
.route(web::get().to_async(products::get_product_detail))
.route(web::delete().to_async(products::remove_product)),
.route(web::get().to(products::get_product_detail))
.route(web::delete().to(products::remove_product)),
)
.service(
web::scope("/parts")
.service(
web::resource("")
.route(web::get().to_async(parts::get_parts))
.route(web::post().to_async(parts::add_part)),
.route(web::get().to(parts::get_parts))
.route(web::post().to(parts::add_part)),
)
.service(
web::resource("/{part_id}")
.route(web::get().to_async(parts::get_part_detail))
.route(web::delete().to_async(parts::remove_part)),
.route(web::get().to(parts::get_part_detail))
.route(web::delete().to(parts::remove_part)),
),
),
),

View File

@ -2,7 +2,8 @@ use actix_web::{middleware, App, HttpServer};
use async_ex2::appconfig::config_app;
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
env_logger::init();
@ -12,5 +13,6 @@ fn main() -> std::io::Result<()> {
.wrap(middleware::Logger::default())
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,28 +1,19 @@
use actix_web::{web, Error, HttpResponse};
use futures::{future::ok as fut_ok, Future};
use crate::common::{Part, Product};
pub fn get_parts(
query: web::Query<Option<Part>>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
pub async fn get_parts(query: web::Query<Option<Part>>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
pub fn add_part(
new_part: web::Json<Product>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
pub async fn add_part(new_part: web::Json<Product>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
pub fn get_part_detail(
id: web::Path<String>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
pub async fn get_part_detail(id: web::Path<String>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
pub fn remove_part(
id: web::Path<String>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
pub async fn remove_part(id: web::Path<String>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}

View File

@ -1,45 +1,39 @@
use actix_web::{web, Error, HttpResponse};
use futures::{future::ok as fut_ok, Future};
use crate::common::{Part, Product};
pub fn get_products(
pub async fn get_products(
query: web::Query<Option<Part>>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
pub fn add_product(
pub async fn add_product(
new_product: web::Json<Product>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
pub fn get_product_detail(
id: web::Path<String>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
pub async fn get_product_detail(id: web::Path<String>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
pub fn remove_product(
id: web::Path<String>,
) -> impl Future<Item = HttpResponse, Error = Error> {
fut_ok(HttpResponse::Ok().finish())
pub async fn remove_product(id: web::Path<String>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::appconfig::config_app;
use actix_service::Service;
use actix_web::{
http::{header, StatusCode},
test, web, App, HttpRequest, HttpResponse,
test, App,
};
#[test]
fn test_add_product() {
let mut app = test::init_service(App::new().configure(config_app));
#[actix_rt::test]
async fn test_add_product() {
let mut app = test::init_service(App::new().configure(config_app)).await;
let payload = r#"{"id":12345,"product_type":"fancy","name":"test"}"#.as_bytes();
@ -49,7 +43,7 @@ mod tests {
.set_payload(payload)
.to_request();
let resp = test::block_on(app.call(req)).unwrap();
let resp = app.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}

View File

@ -1,16 +1,17 @@
[package]
name = "basics"
version = "1.0.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-rt = "0.2.2"
actix-web = "1.0.0"
actix-files = "0.1.1"
actix-session = "0.2.0"
actix-rt = "1.0.0-alpha.3"
actix-web = "2.0.0-alpha.3"
actix-files = "0.2.0-alpha.3"
actix-session = "0.3.0-alpha.3"
actix-utils = "1.0.0-alpha.3"
futures = "0.1.25"
futures = "0.3.1"
env_logger = "0.5"
bytes = "0.4"
bytes = "0.5"

View File

@ -5,24 +5,23 @@ use std::{env, io};
use actix_files as fs;
use actix_session::{CookieSession, Session};
use actix_utils::mpsc;
use actix_web::http::{header, Method, StatusCode};
use actix_web::{
error, guard, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer,
Result,
};
use bytes::Bytes;
use futures::unsync::mpsc;
use futures::{future::ok, Future, Stream};
/// favicon handler
#[get("/favicon")]
fn favicon() -> Result<fs::NamedFile> {
async fn favicon() -> Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/favicon.ico")?)
}
/// simple index handler
#[get("/welcome")]
fn welcome(session: Session, req: HttpRequest) -> Result<HttpResponse> {
async fn welcome(session: Session, req: HttpRequest) -> Result<HttpResponse> {
println!("{:?}", req);
// session
@ -42,32 +41,22 @@ fn welcome(session: Session, req: HttpRequest) -> Result<HttpResponse> {
}
/// 404 handler
fn p404() -> Result<fs::NamedFile> {
async fn p404() -> Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/404.html")?.set_status_code(StatusCode::NOT_FOUND))
}
/// async handler
fn index_async(req: HttpRequest) -> impl Future<Item = HttpResponse, Error = Error> {
println!("{:?}", req);
ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello {}!", req.match_info().get("name").unwrap())))
}
/// async body
fn index_async_body(path: web::Path<String>) -> HttpResponse {
/// response body
async fn response_body(path: web::Path<String>) -> HttpResponse {
let text = format!("Hello {}!", *path);
let (tx, rx_body) = mpsc::unbounded();
let _ = tx.unbounded_send(Bytes::from(text.as_bytes()));
let (tx, rx_body) = mpsc::channel();
let _ = tx.send(Ok::<_, Error>(Bytes::from(text)));
HttpResponse::Ok()
.streaming(rx_body.map_err(|_| error::ErrorBadRequest("bad request")))
HttpResponse::Ok().streaming(rx_body)
}
/// handler with path parameters like `/user/{name}/`
fn with_param(req: HttpRequest, path: web::Path<(String,)>) -> HttpResponse {
async fn with_param(req: HttpRequest, path: web::Path<(String,)>) -> HttpResponse {
println!("{:?}", req);
HttpResponse::Ok()
@ -75,10 +64,10 @@ fn with_param(req: HttpRequest, path: web::Path<(String,)>) -> HttpResponse {
.body(format!("Hello {}!", path.0))
}
fn main() -> io::Result<()> {
env::set_var("RUST_LOG", "actix_web=debug");
#[actix_rt::main]
async fn main() -> io::Result<()> {
env::set_var("RUST_LOG", "actix_web=debug;actix_server=info");
env_logger::init();
let sys = actix_rt::System::new("basic-example");
HttpServer::new(|| {
App::new()
@ -92,14 +81,9 @@ fn main() -> io::Result<()> {
.service(welcome)
// with path parameters
.service(web::resource("/user/{name}").route(web::get().to(with_param)))
// async handler
// async response body
.service(
web::resource("/async/{name}").route(web::get().to_async(index_async)),
)
// async handler
.service(
web::resource("/async-body/{name}")
.route(web::get().to(index_async_body)),
web::resource("/async-body/{name}").route(web::get().to(response_body)),
)
.service(
web::resource("/test").to(|req: HttpRequest| match *req.method() {
@ -109,10 +93,12 @@ fn main() -> io::Result<()> {
}),
)
.service(web::resource("/error").to(|| {
async {
error::InternalError::new(
io::Error::new(io::ErrorKind::Other, "test"),
StatusCode::INTERNAL_SERVER_ERROR,
)
}
}))
// static files
.service(fs::Files::new("/static", "static").show_files_listing())
@ -137,8 +123,6 @@ fn main() -> io::Result<()> {
)
})
.bind("127.0.0.1:8080")?
.start();
println!("Starting http server: 127.0.0.1:8080");
sys.run()
.start()
.await
}

View File

@ -1,11 +1,12 @@
[package]
name = "cookie-auth"
version = "0.1.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-web = "1.0.0"
actix-identity = "0.1.0"
actix-web = "2.0.0-alpha.3"
actix-identity = "0.2.0-alpha.1"
actix-rt = "1.0.0-alpha.3"
env_logger = "0.6"

View File

@ -2,24 +2,25 @@ use actix_identity::Identity;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{middleware, web, App, HttpResponse, HttpServer};
fn index(id: Identity) -> String {
async fn index(id: Identity) -> String {
format!(
"Hello {}",
id.identity().unwrap_or_else(|| "Anonymous".to_owned())
)
}
fn login(id: Identity) -> HttpResponse {
async fn login(id: Identity) -> HttpResponse {
id.remember("user1".to_owned());
HttpResponse::Found().header("location", "/").finish()
}
fn logout(id: Identity) -> HttpResponse {
async fn logout(id: Identity) -> HttpResponse {
id.forget();
HttpResponse::Found().header("location", "/").finish()
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -37,5 +38,6 @@ fn main() -> std::io::Result<()> {
.service(web::resource("/").route(web::get().to(index)))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,15 +1,15 @@
[package]
name = "cookie-session"
version = "0.1.0"
version = "1.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
actix-session = "0.2.0"
actix-rt = "0.2.5"
actix-web = "2.0.0-alpha.3"
actix-session = "0.3.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
futures = "0.1"
futures = "0.3.1"
time = "0.1"
env_logger = "0.6"

View File

@ -9,7 +9,7 @@ use actix_session::{CookieSession, Session};
use actix_web::{middleware::Logger, web, App, HttpRequest, HttpServer, Result};
/// simple index handler with session
fn index(session: Session, req: HttpRequest) -> Result<&'static str> {
async fn index(session: Session, req: HttpRequest) -> Result<&'static str> {
println!("{:?}", req);
// RequestSession trait is used for session access
@ -25,10 +25,11 @@ fn index(session: Session, req: HttpRequest) -> Result<&'static str> {
Ok("welcome!")
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix_rt::System::new("cookie-session");
println!("Starting http server: 127.0.0.1:8080");
HttpServer::new(|| {
App::new()
@ -39,8 +40,6 @@ fn main() -> std::io::Result<()> {
.service(web::resource("/").to(index))
})
.bind("127.0.0.1:8080")?
.start();
println!("Starting http server: 127.0.0.1:8080");
sys.run()
.start()
.await
}

View File

@ -1,16 +1,17 @@
[package]
name = "diesel-example"
version = "0.1.0"
version = "1.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
actix-rt = "1.0.0-alpha.3"
actix-web = "2.0.0-alpha.3"
bytes = "0.4"
env_logger = "0.6"
futures = "0.1"
futures = "0.3.1"
uuid = { version = "0.5", features = ["serde", "v4"] }
serde = "1.0"
serde_json = "1.0"

View File

@ -14,8 +14,7 @@ use bytes::BytesMut;
use diesel::prelude::*;
use diesel::r2d2::{self, ConnectionManager};
use dotenv;
use futures::future::{err, Either};
use futures::{Future, Stream};
use futures::StreamExt;
mod models;
mod schema;
@ -43,15 +42,15 @@ fn query(
}
/// Async request handler
fn add(
async fn add(
name: web::Path<String>,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
) -> Result<HttpResponse, Error> {
// run diesel blocking code
web::block(move || query(name.into_inner(), pool)).then(|res| match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
})
Ok(web::block(move || query(name.into_inner(), pool))
.await
.map(|user| HttpResponse::Ok().json(user))
.map_err(|_| HttpResponse::InternalServerError())?)
}
#[derive(Debug, Serialize, Deserialize)]
@ -62,62 +61,53 @@ struct MyUser {
const MAX_SIZE: usize = 262_144; // max payload size is 256k
/// This handler manually load request payload and parse json object
fn index_add(
pl: web::Payload,
async fn index_add(
mut pl: web::Payload,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
pl
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
// `fold` will asynchronously read each chunk of the request body and
// call supplied closure, then it resolves to result of closure
.fold(BytesMut::new(), move |mut body, chunk| {
) -> Result<HttpResponse, Error> {
let mut body = BytesMut::new();
// pl.next() gets next item from asynchronous stream of byte chunks
// it resolves to `Option<Result<Bytes, Error>>` object
// `None` - indicaets end of stream
while let Some(chunk) = pl.next().await {
let chunk = chunk?;
// limit max size of in-memory payload
if (body.len() + chunk.len()) > MAX_SIZE {
Err(error::ErrorBadRequest("overflow"))
} else {
body.extend_from_slice(&chunk);
Ok(body)
return Err(error::ErrorBadRequest("overflow"));
}
})
// `Future::and_then` can be used to merge an asynchronous workflow with a
// synchronous workflow
//
// Douman NOTE:
// The return value in this closure helps, to clarify result for compiler
// as otheriwse it cannot understand it
.and_then(move |body| {
body.extend_from_slice(&chunk);
}
// body is loaded, now we can deserialize serde-json
let r_obj = serde_json::from_slice::<MyUser>(&body);
// Send to the db for create
// Send to the db for create return response to peer
match r_obj {
Ok(obj) => {
Either::A(web::block(move || query(obj.name, pool)).then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
let user = web::block(move || query(obj.name, pool))
.await
.map_err(|_| Error::from(HttpResponse::InternalServerError()))?;
Ok(HttpResponse::Ok().json(user))
}
}))
Err(_) => Err(error::ErrorBadRequest("Json Decode Failed")),
}
Err(_) => Either::B(err(error::ErrorBadRequest("Json Decode Failed"))),
}
})
}
fn add2(
async fn add2(
item: web::Json<MyUser>,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = Error> {
) -> Result<HttpResponse, Error> {
// run diesel blocking code
web::block(move || query(item.into_inner().name, pool)).then(|res| match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
})
let user = web::block(move || query(item.into_inner().name, pool))
.await
.map_err(|_| HttpResponse::InternalServerError())?; // convert diesel error to http response
Ok(HttpResponse::Ok().json(user))
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -153,14 +143,15 @@ fn main() -> std::io::Result<()> {
.into()
}),
)
.route(web::post().to_async(add2)),
.route(web::post().to(add2)),
)
// Manual parsing would allow custom error construction, use of
// other parsers *beside* json (for example CBOR, protobuf, xml), and allows
// an application to standardise on a single parser implementation.
.service(web::resource("/add").route(web::post().to_async(index_add)))
.service(web::resource("/add/{name}").route(web::get().to_async(add)))
.service(web::resource("/add").route(web::post().to(index_add)))
.service(web::resource("/add/{name}").route(web::get().to(add)))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,14 +1,14 @@
[package]
name = "error_handling"
version = "0.1.0"
version = "1.0.0"
authors = ["dowwie <dkcdkg@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-web = "1.0.0"
derive_more = "0.14.0"
futures = "0.1.23"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
derive_more = "0.99.2"
futures = "0.3.1"
rand = "0.5.4"
env_logger = "0.6"

View File

@ -14,7 +14,6 @@ http errors will be chosen, each with an equal chance of being selected:
use actix_web::{web, App, Error, HttpResponse, HttpServer, ResponseError};
use derive_more::Display; // naming it clearly for illustration purposes
use futures::future::{err, ok, Future};
use rand::{
distributions::{Distribution, Standard},
thread_rng, Rng,
@ -71,32 +70,33 @@ impl ResponseError for CustomError {
}
/// randomly returns either () or one of the 4 CustomError variants
fn do_something_random() -> impl Future<Item = (), Error = CustomError> {
async fn do_something_random() -> Result<(), CustomError> {
let mut rng = thread_rng();
// 20% chance that () will be returned by this function
if rng.gen_bool(2.0 / 10.0) {
ok(())
Ok(())
} else {
err(rand::random::<CustomError>())
Err(rand::random::<CustomError>())
}
}
fn do_something() -> impl Future<Item = HttpResponse, Error = Error> {
do_something_random().from_err().and_then(|_| {
HttpResponse::Ok().body("Nothing interesting happened. Try again.")
})
async fn do_something() -> Result<HttpResponse, Error> {
do_something_random().await?;
Ok(HttpResponse::Ok().body("Nothing interesting happened. Try again."))
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
HttpServer::new(move || {
App::new().service(
web::resource("/something").route(web::get().to_async(do_something)),
)
App::new()
.service(web::resource("/something").route(web::get().to(do_something)))
})
.bind("127.0.0.1:8088")?
.run()
.start()
.await
}

View File

@ -1,12 +1,12 @@
[package]
name = "form-example"
version = "0.1.0"
version = "1.0.0"
authors = ["Gorm Casper <gcasper@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-web = "1.0.8"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
serde = "1.0"
serde_derive = "1.0"

View File

@ -9,14 +9,16 @@ struct AppState {
foo: String,
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::default())
.configure(app_config)
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}
fn app_config(config: &mut web::ServiceConfig) {
@ -28,11 +30,11 @@ fn app_config(config: &mut web::ServiceConfig) {
.service(web::resource("/").route(web::get().to(index)))
.service(web::resource("/post1").route(web::post().to(handle_post_1)))
.service(web::resource("/post2").route(web::post().to(handle_post_2)))
.service(web::resource("/post3").route(web::post().to(handle_post_3)))
.service(web::resource("/post3").route(web::post().to(handle_post_3))),
);
}
fn index() -> Result<HttpResponse> {
async fn index() -> Result<HttpResponse> {
Ok(HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(include_str!("../static/form.html")))
@ -44,14 +46,14 @@ pub struct MyParams {
}
/// Simple handle POST request
fn handle_post_1(params: web::Form<MyParams>) -> Result<HttpResponse> {
async fn handle_post_1(params: web::Form<MyParams>) -> Result<HttpResponse> {
Ok(HttpResponse::Ok()
.content_type("text/plain")
.body(format!("Your name is {}", params.name)))
}
/// State and POST Params
fn handle_post_2(
async fn handle_post_2(
state: web::Data<AppState>,
params: web::Form<MyParams>,
) -> HttpResponse {
@ -62,7 +64,7 @@ fn handle_post_2(
}
/// Request and POST Params
fn handle_post_3(req: HttpRequest, params: web::Form<MyParams>) -> impl Responder {
async fn handle_post_3(req: HttpRequest, params: web::Form<MyParams>) -> impl Responder {
println!("Handling POST request: {:?}", req);
HttpResponse::Ok()
@ -77,7 +79,7 @@ mod tests {
use actix_web::body::{Body, ResponseBody};
use actix_web::dev::{HttpResponseBuilder, Service, ServiceResponse};
use actix_web::http::{header::CONTENT_TYPE, HeaderValue, StatusCode};
use actix_web::test::{self, block_on, TestRequest};
use actix_web::test::{self, TestRequest};
use actix_web::web::Form;
trait BodyTest {
@ -99,47 +101,42 @@ mod tests {
}
}
#[test]
fn handle_post_1_unit_test() {
#[actix_rt::test]
async fn handle_post_1_unit_test() {
let params = Form(MyParams {
name: "John".to_string(),
});
let result = handle_post_1(params);
let resp = block_on(result).unwrap();
let resp = handle_post_1(params).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static("text/plain")
);
assert_eq!(
resp.body().as_str(),
"Your name is John"
);
assert_eq!(resp.body().as_str(), "Your name is John");
}
#[test]
fn handle_post_1_integration_test() {
let mut app = test::init_service(App::new().configure(app_config));
#[actix_rt::test]
async fn handle_post_1_integration_test() {
let mut app = test::init_service(App::new().configure(app_config)).await;
let req = test::TestRequest::post()
.uri("/post1")
.set_form(&MyParams {name: "John".to_string()})
.set_form(&MyParams {
name: "John".to_string(),
})
.to_request();
let resp: ServiceResponse = block_on(app.call(req)).unwrap();
let resp: ServiceResponse = app.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static("text/plain")
);
assert_eq!(
resp.response().body().as_str(),
"Your name is John"
);
assert_eq!(resp.response().body().as_str(), "Your name is John");
}
#[test]
fn handle_post_2_unit_test() {
#[actix_rt::test]
async fn handle_post_2_unit_test() {
let state = TestRequest::default()
.data(AppState {
foo: "bar".to_string(),
@ -150,8 +147,7 @@ mod tests {
let params = Form(MyParams {
name: "John".to_string(),
});
let result = handle_post_2(state, params);
let resp = block_on(result).unwrap();
let resp = handle_post_2(state, params).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
@ -164,14 +160,16 @@ mod tests {
);
}
#[test]
fn handle_post_2_integration_test() {
let mut app = test::init_service(App::new().configure(app_config));
#[actix_rt::test]
async fn handle_post_2_integration_test() {
let mut app = test::init_service(App::new().configure(app_config)).await;
let req = test::TestRequest::post()
.uri("/post2")
.set_form(&MyParams {name: "John".to_string()})
.set_form(&MyParams {
name: "John".to_string(),
})
.to_request();
let resp: ServiceResponse = block_on(app.call(req)).unwrap();
let resp: ServiceResponse = app.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
@ -184,16 +182,18 @@ mod tests {
);
}
#[test]
fn handle_post_3_unit_test() {
#[actix_rt::test]
async fn handle_post_3_unit_test() {
let req = TestRequest::default().to_http_request();
let params = Form(MyParams {
name: "John".to_string(),
});
let result = handle_post_3(req.clone(), params);
let resp = match block_on(result.respond_to(&req)) {
let result = handle_post_3(req.clone(), params).await;
let resp = match result.respond_to(&req).await {
Ok(t) => t,
Err(_) => HttpResponseBuilder::new(StatusCode::INTERNAL_SERVER_ERROR).finish(),
Err(_) => {
HttpResponseBuilder::new(StatusCode::INTERNAL_SERVER_ERROR).finish()
}
};
assert_eq!(resp.status(), StatusCode::OK);
@ -201,29 +201,25 @@ mod tests {
resp.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static("text/plain")
);
assert_eq!(
resp.body().as_str(),
"Your name is John"
);
assert_eq!(resp.body().as_str(), "Your name is John");
}
#[test]
fn handle_post_3_integration_test() {
let mut app = test::init_service(App::new().configure(app_config));
#[actix_rt::test]
async fn handle_post_3_integration_test() {
let mut app = test::init_service(App::new().configure(app_config)).await;
let req = test::TestRequest::post()
.uri("/post3")
.set_form(&MyParams {name: "John".to_string()})
.set_form(&MyParams {
name: "John".to_string(),
})
.to_request();
let resp: ServiceResponse = block_on(app.call(req)).unwrap();
let resp: ServiceResponse = app.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static("text/plain")
);
assert_eq!(
resp.response().body().as_str(),
"Your name is John"
);
assert_eq!(resp.response().body().as_str(), "Your name is John");
}
}

View File

@ -1,14 +1,16 @@
[package]
name = "actix-graphql-demo"
version = "0.1.0"
version = "2.0.0"
authors = ["Dwi Sulfahnur <hello@dwisulfahnur.com>"]
edition = "2018"
workspace = ".."
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "1.0"
futures = "0.1"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
futures = "0.3.1"
juniper = "0.13"

View File

@ -1,44 +1,42 @@
use std::sync::Arc;
use actix_web::{Error, HttpResponse, web};
use futures::Future;
use actix_web::{web, Error, HttpResponse};
use juniper::http::graphiql::graphiql_source;
use juniper::http::GraphQLRequest;
use crate::db::Pool;
use crate::schemas::root::{Context, create_schema, Schema};
use crate::schemas::root::{create_schema, Context, Schema};
pub fn graphql(
pub async fn graphql(
pool: web::Data<Pool>,
schema: web::Data<Arc<Schema>>,
data: web::Json<GraphQLRequest>,
) -> impl Future<Item=HttpResponse, Error=Error> {
) -> Result<HttpResponse, Error> {
let ctx = Context {
dbpool: pool.get_ref().to_owned(),
};
web::block(move || {
let res = web::block(move || {
let res = data.execute(&schema, &ctx);
Ok::<_, serde_json::error::Error>(serde_json::to_string(&res)?)
})
.map_err(Error::from)
.and_then(|res| {
.await
.map_err(Error::from)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(res))
})
}
pub fn graphql_playground() -> HttpResponse {
pub async fn graphql_playground() -> HttpResponse {
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(graphiql_source("/graphql"))
}
pub fn register(config: &mut web::ServiceConfig) {
let schema = std::sync::Arc::new(create_schema());
config
.data(schema)
.route("/graphql", web::post().to_async(graphql))
.route("/graphql", web::post().to(graphql))
.route("/graphiql", web::get().to(graphql_playground));
}

View File

@ -4,16 +4,17 @@ extern crate r2d2;
extern crate r2d2_mysql;
extern crate serde_json;
use actix_web::{App, HttpServer, middleware, web};
use actix_web::{middleware, web, App, HttpServer};
use crate::db::get_db_pool;
use crate::handlers::{register};
use crate::handlers::register;
mod db;
mod handlers;
mod schemas;
mod db;
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
std::env::set_var("RUST_LOG", "actix_web=info,info");
env_logger::init();
@ -24,8 +25,9 @@ fn main() -> std::io::Result<()> {
.data(pool.clone())
.wrap(middleware::Logger::default())
.configure(register)
.default_service(web::to(|| "404"))
.default_service(web::to(|| async { "404" }))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,3 +1,3 @@
pub mod product;
pub mod root;
pub mod user;
pub mod product;

View File

@ -1,5 +1,5 @@
use juniper;
use mysql::{Error as DBError, from_row, params, Row};
use mysql::{from_row, params, Error as DBError, Row};
use crate::schemas::root::Context;
use crate::schemas::user::User;

View File

@ -1,6 +1,6 @@
use juniper::{FieldError, FieldResult, RootNode};
use juniper;
use mysql::{Error as DBError, from_row, params, Row};
use juniper::{FieldError, FieldResult, RootNode};
use mysql::{from_row, params, Error as DBError, Row};
use crate::db::Pool;
@ -8,7 +8,7 @@ use super::product::{Product, ProductInput};
use super::user::{User, UserInput};
pub struct Context {
pub dbpool: Pool
pub dbpool: Pool,
}
impl juniper::Context for Context {}
@ -20,13 +20,18 @@ impl QueryRoot {
#[graphql(description = "List of all users")]
fn users(context: &Context) -> FieldResult<Vec<User>> {
let mut conn = context.dbpool.get().unwrap();
let users = conn.prep_exec("select * from user", ())
let users = conn
.prep_exec("select * from user", ())
.map(|result| {
result.map(|x| x.unwrap()).map(|mut row| {
result
.map(|x| x.unwrap())
.map(|mut row| {
let (id, name, email) = from_row(row);
User { id, name, email }
}).collect()
}).unwrap();
})
.collect()
})
.unwrap();
Ok(users)
}
@ -34,10 +39,8 @@ impl QueryRoot {
fn user(context: &Context, id: String) -> FieldResult<User> {
let mut conn = context.dbpool.get().unwrap();
let user: Result<Option<Row>, DBError> = conn.first_exec(
"SELECT * FROM user WHERE id=:id",
params! {"id" => id},
);
let user: Result<Option<Row>, DBError> =
conn.first_exec("SELECT * FROM user WHERE id=:id", params! {"id" => id});
if let Err(err) = user {
return Err(FieldError::new(
@ -53,23 +56,31 @@ impl QueryRoot {
#[graphql(description = "List of all users")]
fn products(context: &Context) -> FieldResult<Vec<Product>> {
let mut conn = context.dbpool.get().unwrap();
let products = conn.prep_exec("select * from product", ())
let products = conn
.prep_exec("select * from product", ())
.map(|result| {
result.map(|x| x.unwrap()).map(|mut row| {
result
.map(|x| x.unwrap())
.map(|mut row| {
let (id, user_id, name, price) = from_row(row);
Product { id, user_id, name, price }
}).collect()
}).unwrap();
Product {
id,
user_id,
name,
price,
}
})
.collect()
})
.unwrap();
Ok(products)
}
#[graphql(description = "Get Single user reference by user ID")]
fn product(context: &Context, id: String) -> FieldResult<Product> {
let mut conn = context.dbpool.get().unwrap();
let product: Result<Option<Row>, DBError> = conn.first_exec(
"SELECT * FROM user WHERE id=:id",
params! {"id" => id},
);
let product: Result<Option<Row>, DBError> =
conn.first_exec("SELECT * FROM user WHERE id=:id", params! {"id" => id});
if let Err(err) = product {
return Err(FieldError::new(
"Product Not Found",
@ -78,11 +89,15 @@ impl QueryRoot {
}
let (id, user_id, name, price) = from_row(product.unwrap().unwrap());
Ok(Product { id, user_id, name, price })
Ok(Product {
id,
user_id,
name,
price,
})
}
}
pub struct MutationRoot;
#[juniper::object(Context = Context)]
@ -101,17 +116,15 @@ impl MutationRoot {
);
match insert {
Ok(opt_row) => {
Ok(User {
Ok(opt_row) => Ok(User {
id: new_id,
name: user.name,
email: user.email,
})
}
}),
Err(err) => {
let msg = match err {
DBError::MySqlError(err) => err.message,
_ => "internal error".to_owned()
_ => "internal error".to_owned(),
};
Err(FieldError::new(
"Failed to create new user",
@ -136,18 +149,16 @@ impl MutationRoot {
);
match insert {
Ok(opt_row) => {
Ok(Product {
Ok(opt_row) => Ok(Product {
id: new_id,
user_id: product.user_id,
name: product.name,
price: product.price,
})
}
}),
Err(err) => {
let msg = match err {
DBError::MySqlError(err) => err.message,
_ => "internal error".to_owned()
_ => "internal error".to_owned(),
};
Err(FieldError::new(
"Failed to create new product",

View File

@ -19,27 +19,42 @@ pub struct UserInput {
pub email: String,
}
#[juniper::object(Context = Context)]
impl User {
fn id(&self) -> &str { &self.id }
fn id(&self) -> &str {
&self.id
}
fn name(&self) -> &str {
&self.name
}
fn email(&self) -> &str { &self.email }
fn email(&self) -> &str {
&self.email
}
fn products(&self, context: &Context) -> Vec<Product> {
let mut conn = context.dbpool.get().unwrap();
let products = conn.prep_exec(
"select * from product where user_id=:user_id", params! {
let products = conn
.prep_exec(
"select * from product where user_id=:user_id",
params! {
"user_id" => &self.id
})
},
)
.map(|result| {
result.map(|x| x.unwrap()).map(|mut row| {
result
.map(|x| x.unwrap())
.map(|mut row| {
let (id, user_id, name, price) = from_row(row);
Product { id, user_id, name, price }
}).collect()
}).unwrap();
Product {
id,
user_id,
name,
price,
}
})
.collect()
})
.unwrap();
products
}
}

View File

@ -1,10 +1,11 @@
[package]
name = "hello-world"
version = "0.1.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
env_logger = "0.6"

View File

@ -1,11 +1,12 @@
use actix_web::{middleware, web, App, HttpRequest, HttpServer};
fn index(req: HttpRequest) -> &'static str {
async fn index(req: HttpRequest) -> &'static str {
println!("REQ: {:?}", req);
"Hello world!"
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -13,28 +14,27 @@ fn main() -> std::io::Result<()> {
App::new()
// enable logger
.wrap(middleware::Logger::default())
.service(web::resource("/index.html").to(|| "Hello world!"))
.service(web::resource("/index.html").to(|| async { "Hello world!" }))
.service(web::resource("/").to(index))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}
#[cfg(test)]
mod tests {
use super::*;
use actix_web::dev::Service;
use actix_web::{test, web, App, http, Error};
use actix_web::{http, test, web, App, Error};
#[test]
fn test_index() -> Result<(), Error> {
#[actix_rt::test]
async fn test_index() -> Result<(), Error> {
let app = App::new().route("/", web::get().to(index));
let mut app = test::init_service(app);
let mut app = test::init_service(app).await;
let req = test::TestRequest::get()
.uri("/")
.to_request();
let resp = test::block_on(app.call(req)).unwrap();
let req = test::TestRequest::get().uri("/").to_request();
let resp = app.call(req).await.unwrap();
assert_eq!(resp.status(), http::StatusCode::OK);

View File

@ -1,14 +1,14 @@
[package]
name = "http-proxy"
version = "0.1.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>", "Rotem Yaari <vmalloc@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-rt = "0.2"
actix-web = { version = "1.0.0", features=["ssl"] }
actix-rt = "1.0.0-alpha.3"
actix-web = { version = "2.0.0-alpha.3", features=["openssl"] }
clap = "2.32.0"
futures = "0.1.25"
futures = "0.3.1"
failure = "0.1.3"
url = "1.7.1"

View File

@ -1,17 +1,16 @@
use std::net::ToSocketAddrs;
use actix_web::client::Client;
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
use clap::{value_t, Arg};
use futures::stream::Stream;
use futures::Future;
use std::net::ToSocketAddrs;
use url::Url;
fn forward(
async fn forward(
req: HttpRequest,
body: web::Bytes,
url: web::Data<Url>,
client: web::Data<Client>,
) -> impl Future<Item = HttpResponse, Error = Error> {
) -> Result<HttpResponse, Error> {
let mut new_url = url.get_ref().clone();
new_url.set_path(req.uri().path());
new_url.set_query(req.uri().query());
@ -27,10 +26,8 @@ fn forward(
forwarded_req
};
forwarded_req
.send_body(body)
.map_err(Error::from)
.map(|mut res| {
let mut res = forwarded_req.send_body(body).await.map_err(Error::from)?;
let mut client_resp = HttpResponse::build(res.status());
// Remove `Connection` as per
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection#Directives
@ -39,16 +36,12 @@ fn forward(
{
client_resp.header(header_name.clone(), header_value.clone());
}
res.body()
.into_stream()
.concat2()
.map(move |b| client_resp.body(b))
.map_err(|e| e.into())
})
.flatten()
Ok(client_resp.body(res.body().await?))
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
let matches = clap::App::new("HTTP Proxy")
.arg(
Arg::with_name("listen_addr")
@ -102,9 +95,10 @@ fn main() -> std::io::Result<()> {
.data(Client::new())
.data(forward_url.clone())
.wrap(middleware::Logger::default())
.default_service(web::route().to_async(forward))
.default_service(web::route().to(forward))
})
.bind((listen_addr, listen_port))?
.system_exit()
.run()
.start()
.await
}

View File

@ -6,10 +6,11 @@ workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
bytes = "0.4"
futures = "0.1"
bytes = "0.5.2"
futures = "0.3.1"
env_logger = "*"
serde = "1.0"

View File

@ -1,8 +1,8 @@
use actix_web::{
error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer,
};
use bytes::BytesMut;
use futures::{Future, Stream};
use bytes::{Bytes, BytesMut};
use futures::StreamExt;
use json::JsonValue;
use serde_derive::{Deserialize, Serialize};
@ -13,13 +13,13 @@ struct MyObj {
}
/// This handler uses json extractor
fn index(item: web::Json<MyObj>) -> HttpResponse {
async fn index(item: web::Json<MyObj>) -> HttpResponse {
println!("model: {:?}", &item);
HttpResponse::Ok().json(item.0) // <- send response
}
/// This handler uses json extractor with limit
fn extract_item(item: web::Json<MyObj>, req: HttpRequest) -> HttpResponse {
async fn extract_item(item: web::Json<MyObj>, req: HttpRequest) -> HttpResponse {
println!("request: {:?}", req);
println!("model: {:?}", item);
@ -29,37 +29,25 @@ fn extract_item(item: web::Json<MyObj>, req: HttpRequest) -> HttpResponse {
const MAX_SIZE: usize = 262_144; // max payload size is 256k
/// This handler manually load request payload and parse json object
fn index_manual(
payload: web::Payload,
) -> impl Future<Item = HttpResponse, Error = Error> {
async fn index_manual(mut payload: web::Payload) -> Result<HttpResponse, Error> {
// payload is a stream of Bytes objects
payload
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
// `fold` will asynchronously read each chunk of the request body and
// call supplied closure, then it resolves to result of closure
.fold(BytesMut::new(), move |mut body, chunk| {
let mut body = BytesMut::new();
while let Some(chunk) = payload.next().await {
let chunk = chunk?;
// limit max size of in-memory payload
if (body.len() + chunk.len()) > MAX_SIZE {
Err(error::ErrorBadRequest("overflow"))
} else {
body.extend_from_slice(&chunk);
Ok(body)
return Err(error::ErrorBadRequest("overflow"));
}
})
// `Future::and_then` can be used to merge an asynchronous workflow with a
// synchronous workflow
.and_then(|body| {
body.extend_from_slice(&chunk);
}
// body is loaded, now we can deserialize serde-json
let obj = serde_json::from_slice::<MyObj>(&body)?;
Ok(HttpResponse::Ok().json(obj)) // <- send response
})
}
/// This handler manually load request payload and parse json-rust
fn index_mjsonrust(pl: web::Payload) -> impl Future<Item = HttpResponse, Error = Error> {
pl.concat2().from_err().and_then(|body| {
async fn index_mjsonrust(body: Bytes) -> Result<HttpResponse, Error> {
// body is loaded, now we can deserialize json-rust
let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result
let injson: JsonValue = match result {
@ -69,10 +57,10 @@ fn index_mjsonrust(pl: web::Payload) -> impl Future<Item = HttpResponse, Error =
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(injson.dump()))
})
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -85,23 +73,22 @@ fn main() -> std::io::Result<()> {
.service(
web::resource("/extractor2")
.data(web::JsonConfig::default().limit(1024)) // <- limit size of the payload (resource level)
.route(web::post().to_async(extract_item)),
)
.service(web::resource("/manual").route(web::post().to_async(index_manual)))
.service(
web::resource("/mjsonrust").route(web::post().to_async(index_mjsonrust)),
.route(web::post().to(extract_item)),
)
.service(web::resource("/manual").route(web::post().to(index_manual)))
.service(web::resource("/mjsonrust").route(web::post().to(index_mjsonrust)))
.service(web::resource("/").route(web::post().to(index)))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}
#[cfg(test)]
mod tests {
use super::*;
use actix_web::dev::Service;
use actix_web::{test, web, App, http};
use actix_web::{http, test, web, App};
#[test]
fn test_index() -> Result<(), Error> {
@ -110,7 +97,10 @@ mod tests {
let req = test::TestRequest::post()
.uri("/")
.set_json(&MyObj { name: "my-name".to_owned(), number: 43 })
.set_json(&MyObj {
name: "my-name".to_owned(),
number: 43,
})
.to_request();
let resp = test::block_on(app.call(req)).unwrap();

View File

@ -1,13 +1,13 @@
[package]
name = "json_error"
version = "0.1.0"
version = "1.0.0"
authors = ["Kai Yao <kai.b.yao@gmail.com>"]
edition = "2018"
[dependencies]
actix = "0.8"
actix-web = "1.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
failure = "0.1"
futures = "0.1"
futures = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

@ -1,16 +1,12 @@
// This example is meant to show how to automatically generate a json error response when something goes wrong.
use actix::System;
use actix_web::http::StatusCode;
use actix_web::web::{get, resource, HttpRequest, HttpResponse};
use actix_web::{App, HttpServer, ResponseError};
use futures::future::err;
use futures::Future;
use serde::Serialize;
use serde_json::{json, to_string_pretty};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::io;
use actix_web::http::StatusCode;
use actix_web::{web, App, HttpServer, ResponseError};
use serde::Serialize;
use serde_json::{json, to_string_pretty};
#[derive(Debug, Serialize)]
struct Error {
msg: String,
@ -25,29 +21,30 @@ impl Display for Error {
impl ResponseError for Error {
// builds the actual response to send back when an error occurs
fn render_response(&self) -> HttpResponse {
fn error_response(&self) -> web::HttpResponse {
let err_json = json!({ "error": self.msg });
HttpResponse::build(StatusCode::from_u16(self.status).unwrap()).json(err_json)
web::HttpResponse::build(StatusCode::from_u16(self.status).unwrap())
.json(err_json)
}
}
fn index(_: HttpRequest) -> impl Future<Item = HttpResponse, Error = Error> {
err(Error {
async fn index() -> Result<web::HttpResponse, Error> {
Err(Error {
msg: "an example error message".to_string(),
status: 400,
})
}
fn main() -> io::Result<()> {
let sys = System::new("json_error_example");
#[actix_rt::main]
async fn main() -> io::Result<()> {
let ip_address = "127.0.0.1:8000";
HttpServer::new(|| App::new().service(resource("/").route(get().to_async(index))))
.bind(ip_address)
.expect("Can not bind to port 8000")
.start();
println!("Running server on {}", ip_address);
sys.run()
HttpServer::new(|| {
App::new().service(web::resource("/").route(web::get().to(index)))
})
.bind(ip_address)
.expect("Can not bind to port 8000")
.start()
.await
}

View File

@ -1,16 +1,16 @@
[package]
name = "jsonrpc-example"
version = "0.1.0"
version = "2.0.0"
authors = ["mohanson <mohanson@outlook.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix = "0.8.2"
actix-web = "1.0.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
bytes = "0.5"
env_logger = "0.6"
futures = "0.1.23"
futures-timer = "0.1"
futures = "0.3.1"
log = "0.4"
serde = "1.0"
serde_derive = "1.0"

View File

@ -1,11 +1,12 @@
use std::error;
use std::sync::Arc;
use std::sync::RwLock;
use std::pin::Pin;
use std::sync::{Arc, RwLock};
use std::time::Duration;
use actix_rt::time::delay_for;
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
use futures::{future, Future, Stream};
use futures_timer::Delay;
use bytes::Bytes;
use futures::{Future, FutureExt};
use serde_json;
use serde_json::Value;
@ -13,11 +14,7 @@ use serde_json::Value;
mod convention;
/// The main handler for JSONRPC server.
fn rpc_handler(
req: HttpRequest,
payload: web::Payload,
) -> impl Future<Item = HttpResponse, Error = Error> {
payload.concat2().from_err().and_then(move |body| {
async fn rpc_handler(req: HttpRequest, body: Bytes) -> Result<HttpResponse, Error> {
let reqjson: convention::Request = match serde_json::from_slice(body.as_ref()) {
Ok(ok) => ok,
Err(_) => {
@ -36,7 +33,7 @@ fn rpc_handler(
let mut result = convention::Response::default();
result.id = reqjson.id.clone();
match rpc_select(&app_state, reqjson.method.as_str(), reqjson.params) {
match rpc_select(&app_state, reqjson.method.as_str(), reqjson.params).await {
Ok(ok) => result.result = ok,
Err(e) => result.error = Some(e),
}
@ -44,10 +41,9 @@ fn rpc_handler(
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(result.dump()))
})
}
fn rpc_select(
async fn rpc_select(
app_state: &AppState,
method: &str,
params: Vec<Value>,
@ -66,7 +62,7 @@ fn rpc_select(
.read()
.unwrap()
.wait(params[0].as_u64().unwrap())
.wait()
.await
{
Ok(ok) => Ok(Value::from(ok)),
Err(e) => Err(convention::ErrorData::new(500, &format!("{:?}", e)[..])),
@ -89,7 +85,7 @@ pub trait ImplNetwork {
fn wait(
&self,
d: u64,
) -> Box<dyn Future<Item = String, Error = Box<dyn error::Error>>>;
) -> Pin<Box<dyn Future<Output = Result<String, Box<dyn error::Error>>>>>;
fn get(&self) -> u32;
fn inc(&mut self);
@ -113,12 +109,12 @@ impl ImplNetwork for ObjNetwork {
fn wait(
&self,
d: u64,
) -> Box<dyn Future<Item = String, Error = Box<dyn error::Error>>> {
if let Err(e) = Delay::new(Duration::from_secs(d)).wait() {
let e: Box<dyn error::Error> = Box::new(e);
return Box::new(future::err(e));
};
Box::new(future::ok(String::from("pong")))
) -> Pin<Box<dyn Future<Output = Result<String, Box<dyn error::Error>>>>> {
async move {
delay_for(Duration::from_secs(d)).await;
Ok(String::from("pong"))
}
.boxed_local()
}
fn get(&self) -> u32 {
@ -141,24 +137,22 @@ impl AppState {
}
}
fn main() {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "info");
env_logger::init();
let network = Arc::new(RwLock::new(ObjNetwork::new()));
let sys = actix::System::new("actix_jrpc");
HttpServer::new(move || {
let app_state = AppState::new(network.clone());
App::new()
.data(app_state)
.wrap(middleware::Logger::default())
.service(web::resource("/").route(web::post().to_async(rpc_handler)))
.service(web::resource("/").route(web::post().to(rpc_handler)))
})
.bind("127.0.0.1:8080")
.unwrap()
.workers(1)
.start();
let _ = sys.run();
.start()
.await
}

View File

@ -1,13 +1,15 @@
[package]
name = "middleware-example"
version = "0.1.0"
version = "1.0.0"
authors = ["Gorm Casper <gcasper@gmail.com>", "Sven-Hendrik Haase <svenstaro@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-service = "0.4.1"
actix-web = "1.0.0"
futures = "0.1.25"
actix-service = "1.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
actix-web = "2.0.0-alpha.3"
futures = "0.3.1"
env_logger = "0.6"
bytes = "0.4"
bytes = "0.5"
pin-project = "0.4.6"

View File

@ -1,17 +1,18 @@
use actix_web::{web, App, HttpServer};
use actix_service::Service;
use futures::future::Future;
use actix_web::{web, App, HttpServer};
use futures::future::FutureExt;
#[allow(dead_code)]
mod redirect;
#[allow(dead_code)]
mod read_request_body;
#[allow(dead_code)]
mod read_response_body;
#[allow(dead_code)]
mod redirect;
#[allow(dead_code)]
mod simple;
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=debug");
env_logger::init();
@ -30,14 +31,15 @@ fn main() -> std::io::Result<()> {
})
})
.service(web::resource("/login").to(|| {
async {
"You are on /login. Go to src/redirect.rs to change this behavior."
}
}))
.service(web::resource("/").to(|| {
async { "Hello, middleware! Check the console where the server is run." }
}))
.service(
web::resource("/").to(|| {
"Hello, middleware! Check the console where the server is run."
}),
)
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,12 +1,13 @@
use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::error::PayloadError;
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage};
use bytes::BytesMut;
use futures::future::{ok, FutureResult};
use futures::stream::Stream;
use futures::{Future, Poll};
use std::cell::RefCell;
use std::rc::Rc;
use futures::future::{ok, Future, Ready};
use futures::stream::StreamExt;
pub struct Logging;
@ -21,7 +22,7 @@ where
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware {
@ -45,26 +46,27 @@ where
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone();
Box::new(
req.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
Box::pin(async move {
let mut body = BytesMut::new();
let mut stream = req.take_payload();
while let Some(chunk) = stream.next().await {
body.extend_from_slice(&chunk?);
}
println!("request body: {:?}", body);
let res = svc.call(req).await?;
println!("response: {:?}", res.headers());
Ok(res)
})
.map_err(|e| e.into())
.and_then(move |bytes| {
println!("request body: {:?}", bytes);
svc.call(req).and_then(|res| Ok(res))
}),
)
}
}

View File

@ -1,11 +1,13 @@
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::body::{BodySize, MessageBody, ResponseBody};
use std::marker::PhantomData;
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use bytes::{Bytes, BytesMut};
use futures::Async;
use futures::future::{ok, FutureResult};
use futures::{Future, Poll};
use futures::future::{ok, Ready};
pub struct Logging;
@ -19,12 +21,10 @@ where
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware {
service,
})
ok(LoggingMiddleware { service })
}
}
@ -42,8 +42,8 @@ where
type Error = Error;
type Future = WrapperStream<S, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
@ -54,11 +54,13 @@ where
}
}
#[pin_project::pin_project]
pub struct WrapperStream<S, B>
where
B: MessageBody,
S: Service,
{
#[pin]
fut: S::Future,
_t: PhantomData<(B,)>,
}
@ -68,18 +70,19 @@ where
B: MessageBody,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
type Item = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type Output = Result<ServiceResponse<BodyLogger<B>>, Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let res = futures::try_ready!(self.fut.poll());
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = futures::ready!(self.project().fut.poll(cx));
Ok(Async::Ready(res.map_body(move |_, body| {
Poll::Ready(res.map(|res| {
res.map_body(move |_, body| {
ResponseBody::Body(BodyLogger {
body,
body_accum: BytesMut::new(),
})
})))
})
}))
}
}
@ -99,13 +102,15 @@ impl<B: MessageBody> MessageBody for BodyLogger<B> {
self.body.size()
}
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
match self.body.poll_next()? {
Async::Ready(Some(chunk)) => {
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, Error>>> {
match self.body.poll_next(cx) {
Poll::Ready(Some(Ok(chunk))) => {
self.body_accum.extend_from_slice(&chunk);
Ok(Async::Ready(Some(chunk)))
Poll::Ready(Some(Ok(chunk)))
}
val => Ok(val),
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}

View File

@ -1,8 +1,9 @@
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::{http, Error, HttpResponse};
use futures::future::{ok, Either, FutureResult};
use futures::Poll;
use futures::future::{ok, Either, Ready};
pub struct CheckLogin;
@ -16,7 +17,7 @@ where
type Error = Error;
type InitError = ();
type Transform = CheckLoginMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CheckLoginMiddleware { service })
@ -34,10 +35,10 @@ where
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Either<S::Future, FutureResult<Self::Response, Self::Error>>;
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
@ -46,13 +47,13 @@ where
let is_logged_in = false; // Change this to see the change in outcome in the browser
if is_logged_in {
Either::A(self.service.call(req))
Either::Left(self.service.call(req))
} else {
// Don't forward to /login if we are already on /login
if req.path() == "/login" {
Either::A(self.service.call(req))
Either::Left(self.service.call(req))
} else {
Either::B(ok(req.into_response(
Either::Right(ok(req.into_response(
HttpResponse::Found()
.header(http::header::LOCATION, "/login")
.finish()

View File

@ -1,7 +1,10 @@
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, FutureResult};
use futures::{Future, Poll};
use futures::future::{ok, Ready};
use futures::Future;
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
@ -23,7 +26,7 @@ where
type Error = Error;
type InitError = ();
type Transform = SayHiMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(SayHiMiddleware { service })
@ -43,18 +46,22 @@ where
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
println!("Hi from start. You requested: {}", req.path());
Box::new(self.service.call(req).and_then(|res| {
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
println!("Hi from response");
Ok(res)
}))
})
}
}

View File

@ -13,3 +13,4 @@ readme = "README.md"
futures = "0.3.1"
actix-multipart = "0.2.0-alpha.3"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"

View File

@ -1,7 +1,7 @@
use std::io::Write;
use actix_multipart::Multipart;
use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer};
use futures::{StreamExt};
use futures::StreamExt;
use std::io::Write;
async fn save_file(mut payload: Multipart) -> Result<HttpResponse, Error> {
// iterate over multipart stream
@ -38,19 +38,21 @@ fn index() -> HttpResponse {
HttpResponse::Ok().body(html)
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
std::fs::create_dir_all("./tmp").unwrap();
let ip = "0.0.0.0:3000";
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::default())
.service(
App::new().wrap(middleware::Logger::default()).service(
web::resource("/")
.route(web::get().to(index))
.route(web::post().to(save_file)),
)
})
.bind(ip)?
.run()
.start()
.await
}

12
openssl/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "openssl-example"
version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-rt = "1.0.0-alpha.3"
actix-web = { version="2.0.0-alpha.3", features=["openssl"] }
env_logger = "0.6"
openssl = "0.10"

View File

@ -4,18 +4,19 @@ use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServ
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
/// simple handle
fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
async fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
println!("{:?}", req);
Ok(HttpResponse::Ok()
.content_type("text/plain")
.body("Welcome!"))
}
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=debug");
env_logger::init();
let sys = actix_rt::System::new("tls-example");
println!("Started http server: 127.0.0.1:8443");
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
@ -37,9 +38,7 @@ fn main() -> io::Result<()> {
.finish()
})))
})
.bind_ssl("127.0.0.1:8443", builder)?
.start();
println!("Started http server: 127.0.0.1:8443");
sys.run()
.bind_openssl("127.0.0.1:8443", builder)?
.start()
.await
}

View File

@ -1,15 +1,15 @@
[package]
name = "r2d2-example"
version = "0.1.0"
version = "1.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-rt = "0.2"
actix-web = "1.0.0"
actix-rt = "1.0.0-alpha.3"
actix-web = "2.0.0-alpha.3"
futures = "0.1"
futures = "0.3.1"
env_logger = "0.6"
uuid = { version = "0.7", features = ["v4"] }

View File

@ -2,18 +2,17 @@
use std::io;
use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer};
use futures::Future;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use uuid;
/// Async request handler. Ddb pool is stored in application state.
fn index(
async fn index(
path: web::Path<String>,
db: web::Data<Pool<SqliteConnectionManager>>,
) -> impl Future<Item = HttpResponse, Error = Error> {
) -> Result<HttpResponse, Error> {
// execute sync code in threadpool
web::block(move || {
let res = web::block(move || {
let conn = db.get().unwrap();
let uuid = format!("{}", uuid::Uuid::new_v4());
@ -27,16 +26,16 @@ fn index(
row.get::<_, String>(0)
})
})
.then(|res| match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
})
.await
.map(|user| HttpResponse::Ok().json(user))
.map_err(|_| HttpResponse::InternalServerError())?;
Ok(res)
}
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=debug");
env_logger::init();
let sys = actix_rt::System::new("r2d2-example");
// r2d2 pool
let manager = SqliteConnectionManager::file("test.db");
@ -47,10 +46,9 @@ fn main() -> io::Result<()> {
App::new()
.data(pool.clone()) // <- store db pool in app state
.wrap(middleware::Logger::default())
.route("/{name}", web::get().to_async(index))
.route("/{name}", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.start();
sys.run()
.start()
.await
}

View File

@ -1,6 +1,6 @@
[package]
name = "rustls-example"
version = "0.1.0"
version = "1.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
@ -11,6 +11,7 @@ path = "src/main.rs"
[dependencies]
env_logger = "0.5"
rustls = "0.15"
actix-web = { version = "1.0.0", features=["rust-tls"] }
actix-files = "0.1.0"
rustls = "0.16"
actix-web = { version = "2.0.0-alpha.3", features=["rustls"] }
actix-files = "0.2.0-alpha.3"
actix-rt = "1.0.0-alpha.3"

View File

@ -2,19 +2,20 @@ use std::fs::File;
use std::io::BufReader;
use actix_files::Files;
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer};
use rustls::internal::pemfile::{certs, rsa_private_keys};
use rustls::{NoClientAuth, ServerConfig};
/// simple handle
fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
async fn index(req: HttpRequest) -> HttpResponse {
println!("{:?}", req);
Ok(HttpResponse::Ok()
HttpResponse::Ok()
.content_type("text/plain")
.body("Welcome!"))
.body("Welcome!")
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "actix_web=info");
}
@ -43,5 +44,6 @@ fn main() -> std::io::Result<()> {
.service(Files::new("/static", "static"))
})
.bind_rustls("127.0.0.1:8443", config)?
.run()
.start()
.await
}

View File

@ -1,13 +1,13 @@
[package]
name = "server-sent-events"
version = "0.1.0"
version = "1.0.0"
authors = ["Arve Seljebu"]
workspace = ".."
edition = "2018"
[dependencies]
actix-rt = "0.2"
actix-web = "1.0"
actix-rt = "1.0.0-alpha.3"
actix-web = "2.0.0-alpha.3"
env_logger = "0.6"
futures = "0.1"
tokio = "0.1"
futures = "0.3.1"
tokio = "0.2"

View File

@ -1,17 +1,17 @@
use actix_rt::Arbiter;
use actix_web::error::ErrorInternalServerError;
use std::pin::Pin;
use std::sync::Mutex;
use std::task::{Context, Poll};
use std::time::Duration;
use actix_web::web::{Bytes, Data, Path};
use actix_web::{web, App, Error, HttpResponse, HttpServer, Responder};
use env_logger;
use tokio::prelude::*;
use futures::{Stream, StreamExt};
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::timer::Interval;
use tokio::time::{interval_at, Instant};
use std::sync::Mutex;
use std::time::{Duration, Instant};
fn main() {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
env_logger::init();
let data = Broadcaster::create();
@ -22,13 +22,12 @@ fn main() {
.route("/events", web::get().to(new_client))
.route("/broadcast/{msg}", web::get().to(broadcast))
})
.bind("127.0.0.1:8080")
.expect("Unable to bind port")
.run()
.unwrap();
.bind("127.0.0.1:8080")?
.start()
.await
}
fn index() -> impl Responder {
async fn index() -> impl Responder {
let content = include_str!("index.html");
HttpResponse::Ok()
@ -36,7 +35,7 @@ fn index() -> impl Responder {
.body(content)
}
fn new_client(broadcaster: Data<Mutex<Broadcaster>>) -> impl Responder {
async fn new_client(broadcaster: Data<Mutex<Broadcaster>>) -> impl Responder {
let rx = broadcaster.lock().unwrap().new_client();
HttpResponse::Ok()
@ -45,7 +44,10 @@ fn new_client(broadcaster: Data<Mutex<Broadcaster>>) -> impl Responder {
.streaming(rx)
}
fn broadcast(msg: Path<String>, broadcaster: Data<Mutex<Broadcaster>>) -> impl Responder {
async fn broadcast(
msg: Path<String>,
broadcaster: Data<Mutex<Broadcaster>>,
) -> impl Responder {
broadcaster.lock().unwrap().send(&msg.into_inner());
HttpResponse::Ok().body("msg sent")
@ -73,14 +75,12 @@ impl Broadcaster {
}
fn spawn_ping(me: Data<Mutex<Self>>) {
let task = Interval::new(Instant::now(), Duration::from_secs(10))
.for_each(move |_| {
actix_rt::spawn(async move {
let mut task = interval_at(Instant::now(), Duration::from_secs(10));
while let Some(_) = task.next().await {
me.lock().unwrap().remove_stale_clients();
Ok(())
}
})
.map_err(|e| panic!("interval errored; err={:?}", e));
Arbiter::spawn(task);
}
fn remove_stale_clients(&mut self) {
@ -119,10 +119,16 @@ impl Broadcaster {
struct Client(Receiver<Bytes>);
impl Stream for Client {
type Item = Bytes;
type Error = Error;
type Item = Result<Bytes, Error>;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.0.poll().map_err(ErrorInternalServerError)
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
match Pin::new(&mut self.0).poll_next(cx) {
Poll::Ready(Some(v)) => Poll::Ready(Some(Ok(v))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}

View File

@ -1,20 +1,21 @@
[package]
name = "simple-auth-server"
version = "0.1.0"
version = "2.0.0"
authors = ["mygnu <tech@hgill.io>"]
edition = "2018"
workspace = ".."
[dependencies]
actix-identity = "0.1.0"
actix-web = "1.0.3"
actix-identity = "0.2.0-alpha.1"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
argonautica = "0.2.0"
chrono = { version = "0.4.6", features = ["serde"] }
derive_more = "0.15.0"
derive_more = "0.99.0"
diesel = { version = "1.4.2", features = ["postgres","uuidv07", "r2d2", "chrono"] }
dotenv = "0.14.1"
env_logger = "0.6"
futures = "0.1"
futures = "0.3.1"
r2d2 = "0.8"
lazy_static = "1.3.0"
serde = "1.0"
@ -22,4 +23,3 @@ serde_derive = "1.0"
serde_json = "1.0"
sparkpost = "0.5.2"
uuid = { version = "0.7", features = ["serde", "v4"] }

View File

@ -1,3 +1,5 @@
use std::pin::Pin;
use actix_identity::Identity;
use actix_web::{
dev::Payload, error::BlockingError, web, Error, FromRequest, HttpRequest,
@ -5,7 +7,7 @@ use actix_web::{
};
use diesel::prelude::*;
use diesel::PgConnection;
use futures::Future;
use futures::future::Future;
use crate::errors::ServiceError;
use crate::models::{Pool, SlimUser, User};
@ -24,29 +26,34 @@ pub type LoggedUser = SlimUser;
impl FromRequest for LoggedUser {
type Config = ();
type Error = Error;
type Future = Result<LoggedUser, Error>;
type Future = Pin<Box<dyn Future<Output = Result<LoggedUser, Error>>>>;
fn from_request(req: &HttpRequest, pl: &mut Payload) -> Self::Future {
if let Some(identity) = Identity::from_request(req, pl)?.identity() {
let fut = Identity::from_request(req, pl);
Box::pin(async move {
if let Some(identity) = fut.await?.identity() {
let user: LoggedUser = serde_json::from_str(&identity)?;
return Ok(user);
}
};
Err(ServiceError::Unauthorized.into())
})
}
}
pub fn logout(id: Identity) -> HttpResponse {
pub async fn logout(id: Identity) -> HttpResponse {
id.forget();
HttpResponse::Ok().finish()
}
pub fn login(
pub async fn login(
auth_data: web::Json<AuthData>,
id: Identity,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = ServiceError> {
web::block(move || query(auth_data.into_inner(), pool)).then(
move |res: Result<SlimUser, BlockingError<ServiceError>>| match res {
) -> Result<HttpResponse, ServiceError> {
let res = web::block(move || query(auth_data.into_inner(), pool)).await;
match res {
Ok(user) => {
let user_string = serde_json::to_string(&user).unwrap();
id.remember(user_string);
@ -56,11 +63,10 @@ pub fn login(
BlockingError::Error(service_error) => Err(service_error),
BlockingError::Canceled => Err(ServiceError::InternalServerError),
},
},
)
}
}
pub fn get_me(logged_user: LoggedUser) -> HttpResponse {
pub async fn get_me(logged_user: LoggedUser) -> HttpResponse {
HttpResponse::Ok().json(logged_user)
}
/// Diesel query

View File

@ -1,6 +1,5 @@
use actix_web::{error::BlockingError, web, HttpResponse};
use diesel::{prelude::*, PgConnection};
use futures::Future;
use crate::email_service::send_invitation;
use crate::errors::ServiceError;
@ -11,20 +10,22 @@ pub struct InvitationData {
pub email: String,
}
pub fn post_invitation(
pub async fn post_invitation(
invitation_data: web::Json<InvitationData>,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = ServiceError> {
) -> Result<HttpResponse, ServiceError> {
// run diesel blocking code
web::block(move || create_invitation(invitation_data.into_inner().email, pool)).then(
|res| match res {
let res =
web::block(move || create_invitation(invitation_data.into_inner().email, pool))
.await;
match res {
Ok(_) => Ok(HttpResponse::Ok().finish()),
Err(err) => match err {
BlockingError::Error(service_error) => Err(service_error),
BlockingError::Canceled => Err(ServiceError::InternalServerError),
},
},
)
}
}
fn create_invitation(

View File

@ -17,7 +17,8 @@ mod register_handler;
mod schema;
mod utils;
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
std::env::set_var(
"RUST_LOG",
@ -52,22 +53,23 @@ fn main() -> std::io::Result<()> {
// everything under '/api/' route
.service(
web::scope("/api")
.service(web::resource("/invitation").route(
web::post().to_async(invitation_handler::post_invitation),
))
.service(
web::resource("/register/{invitation_id}").route(
web::post().to_async(register_handler::register_user),
),
web::resource("/invitation")
.route(web::post().to(invitation_handler::post_invitation)),
)
.service(
web::resource("/register/{invitation_id}")
.route(web::post().to(register_handler::register_user)),
)
.service(
web::resource("/auth")
.route(web::post().to_async(auth_handler::login))
.route(web::post().to(auth_handler::login))
.route(web::delete().to(auth_handler::logout))
.route(web::get().to(auth_handler::get_me)),
),
)
})
.bind("127.0.0.1:3000")?
.run()
.start()
.await
}

View File

@ -1,6 +1,5 @@
use actix_web::{error::BlockingError, web, HttpResponse};
use diesel::prelude::*;
use futures::Future;
use crate::errors::ServiceError;
use crate::models::{Invitation, Pool, SlimUser, User};
@ -11,25 +10,27 @@ pub struct UserData {
pub password: String,
}
pub fn register_user(
pub async fn register_user(
invitation_id: web::Path<String>,
user_data: web::Json<UserData>,
pool: web::Data<Pool>,
) -> impl Future<Item = HttpResponse, Error = ServiceError> {
web::block(move || {
) -> Result<HttpResponse, ServiceError> {
let res = web::block(move || {
query(
invitation_id.into_inner(),
user_data.into_inner().password,
pool,
)
})
.then(|res| match res {
.await;
match res {
Ok(user) => Ok(HttpResponse::Ok().json(&user)),
Err(err) => match err {
BlockingError::Error(service_error) => Err(service_error),
BlockingError::Canceled => Err(ServiceError::InternalServerError),
},
})
}
}
fn query(

View File

@ -1,11 +1,12 @@
[package]
name = "state"
version = "0.1.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
futures = "0.1.25"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
futures = "0.3.1"
env_logger = "0.6"

View File

@ -17,14 +17,15 @@ use std::sync::Mutex;
use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer};
/// simple handle
fn index(state: web::Data<Mutex<usize>>, req: HttpRequest) -> HttpResponse {
async fn index(state: web::Data<Mutex<usize>>, req: HttpRequest) -> HttpResponse {
println!("{:?}", req);
*(state.lock().unwrap()) += 1;
HttpResponse::Ok().body(format!("Num of requests: {}", state.lock().unwrap()))
}
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -40,5 +41,6 @@ fn main() -> io::Result<()> {
.service(web::resource("/").to(index))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,13 +1,14 @@
[package]
name = "static_index"
version = "0.1.0"
version = "2.0.0"
authors = ["Jose Marinez <digeratus@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
futures = "0.1"
env_logger = "0.5"
futures = "0.3.1"
env_logger = "0.6"
actix-web = "1.0.0"
actix-files = "0.1.1"
actix-web = "2.0.0-alpha.3"
actix-files = "0.2.0-alpha.3"
actix-rt = "1.0.0-alpha.3"

View File

@ -1,7 +1,8 @@
use actix_files as fs;
use actix_web::{middleware, App, HttpServer};
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -15,5 +16,6 @@ fn main() -> std::io::Result<()> {
)
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,12 +1,13 @@
[package]
name = "template-askama"
version = "0.1.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
env_logger = "0.6"
askama = "0.8"

View File

@ -14,7 +14,7 @@ struct UserTemplate<'a> {
#[template(path = "index.html")]
struct Index;
fn index(query: web::Query<HashMap<String, String>>) -> Result<HttpResponse> {
async fn index(query: web::Query<HashMap<String, String>>) -> Result<HttpResponse> {
let s = if let Some(name) = query.get("name") {
UserTemplate {
name,
@ -28,11 +28,13 @@ fn index(query: web::Query<HashMap<String, String>>) -> Result<HttpResponse> {
Ok(HttpResponse::Ok().content_type("text/html").body(s))
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
// start http server
HttpServer::new(move || {
App::new().service(web::resource("/").route(web::get().to(index)))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,10 +1,11 @@
[package]
name = "template_handlebars"
version = "0.1.0"
version = "1.0.0"
authors = ["Alexandru Tiniuc <tiniuc.alexandru@gmail.com>"]
edition = "2018"
[dependencies]
actix-web = "1.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
handlebars = "2.0.0-beta.2"
serde_json = "1.0"

View File

@ -13,7 +13,7 @@ use std::io;
// Macro documentation can be found in the actix_web_codegen crate
#[get("/")]
fn index(hb: web::Data<Handlebars>) -> HttpResponse {
async fn index(hb: web::Data<Handlebars>) -> HttpResponse {
let data = json!({
"name": "Handlebars"
});
@ -23,7 +23,10 @@ fn index(hb: web::Data<Handlebars>) -> HttpResponse {
}
#[get("/{user}/{data}")]
fn user(hb: web::Data<Handlebars>, info: web::Path<(String, String)>) -> HttpResponse {
async fn user(
hb: web::Data<Handlebars>,
info: web::Path<(String, String)>,
) -> HttpResponse {
let data = json!({
"user": info.0,
"data": info.1
@ -33,7 +36,8 @@ fn user(hb: web::Data<Handlebars>, info: web::Path<(String, String)>) -> HttpRes
HttpResponse::Ok().body(body)
}
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
// Handlebars uses a repository for the compiled templates. This object must be
// shared between the application threads, and is therefore passed to the
// Application Builder as an atomic reference-counted pointer.
@ -50,5 +54,6 @@ fn main() -> io::Result<()> {
.service(user)
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,6 +1,6 @@
[package]
name = "template-tera"
version = "0.1.0"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = ".."
edition = "2018"
@ -8,4 +8,5 @@ edition = "2018"
[dependencies]
env_logger = "0.6"
tera = "0.11"
actix-web = "1.0.0"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"

View File

@ -6,7 +6,7 @@ use std::collections::HashMap;
use actix_web::{error, middleware, web, App, Error, HttpResponse, HttpServer};
// store tera template in application state
fn index(
async fn index(
tmpl: web::Data<tera::Tera>,
query: web::Query<HashMap<String, String>>,
) -> Result<HttpResponse, Error> {
@ -24,7 +24,8 @@ fn index(
Ok(HttpResponse::Ok().content_type("text/html").body(s))
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
@ -38,5 +39,6 @@ fn main() -> std::io::Result<()> {
.service(web::resource("/").route(web::get().to(index)))
})
.bind("127.0.0.1:8080")?
.run()
.start()
.await
}

View File

@ -1,16 +0,0 @@
[package]
name = "tls-example"
version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
edition = "2018"
workspace = ".."
[[bin]]
name = "tls-server"
path = "src/main.rs"
[dependencies]
actix-rt = "0.2"
actix-web = { version="1.0.0", features=["ssl"] }
env_logger = "0.6"
openssl = { version="0.10" }

View File

@ -1,17 +1,18 @@
[package]
authors = ["Dan Munckton <dangit@munckfish.net>"]
name = "actix-todo"
version = "0.1.0"
version = "2.0.0"
workspace = ".."
edition = "2018"
[dependencies]
actix-web = "1.0.0"
actix-files = "0.1.1"
actix-session = "0.2.0"
actix-web = "2.0.0-alpha.3"
actix-files = "0.2.0-alpha.3"
actix-session = "0.3.0-alpha.3"
actix-rt = "1.0.0-alpha.3"
dotenv = "0.13.0"
env_logger = "0.5.10"
futures = "0.1.22"
futures = "0.3.1"
log = "0.4.3"
serde = "1.0.69"
serde_derive = "1.0.69"

135
todo/src/api.rs Normal file
View File

@ -0,0 +1,135 @@
use actix_files::NamedFile;
use actix_session::Session;
use actix_web::middleware::errhandlers::ErrorHandlerResponse;
use actix_web::{dev, error, http, web, Error, HttpResponse, Result};
use tera::{Context, Tera};
use crate::db;
use crate::session::{self, FlashMessage};
pub async fn index(
pool: web::Data<db::PgPool>,
tmpl: web::Data<Tera>,
session: Session,
) -> Result<HttpResponse, Error> {
let tasks = web::block(move || db::get_all_tasks(&pool)).await?;
let mut context = Context::new();
context.insert("tasks", &tasks);
//Session is set during operations on other endpoints
//that can redirect to index
if let Some(flash) = session::get_flash(&session)? {
context.insert("msg", &(flash.kind, flash.message));
session::clear_flash(&session);
}
let rendered = tmpl
.render("index.html.tera", &context)
.map_err(|e| error::ErrorInternalServerError(e.description().to_owned()))?;
Ok(HttpResponse::Ok().body(rendered))
}
#[derive(Deserialize)]
pub struct CreateForm {
description: String,
}
pub async fn create(
params: web::Form<CreateForm>,
pool: web::Data<db::PgPool>,
session: Session,
) -> Result<HttpResponse, Error> {
if params.description.is_empty() {
session::set_flash(
&session,
FlashMessage::error("Description cannot be empty"),
)?;
Ok(redirect_to("/"))
} else {
web::block(move || db::create_task(params.into_inner().description, &pool))
.await?;
session::set_flash(&session, FlashMessage::success("Task successfully added"))?;
Ok(redirect_to("/"))
}
}
#[derive(Deserialize)]
pub struct UpdateParams {
id: i32,
}
#[derive(Deserialize)]
pub struct UpdateForm {
_method: String,
}
pub async fn update(
db: web::Data<db::PgPool>,
params: web::Path<UpdateParams>,
form: web::Form<UpdateForm>,
session: Session,
) -> Result<HttpResponse, Error> {
match form._method.as_ref() {
"put" => toggle(db, params).await,
"delete" => delete(db, params, session).await,
unsupported_method => {
let msg = format!("Unsupported HTTP method: {}", unsupported_method);
Err(error::ErrorBadRequest(msg))
}
}
}
async fn toggle(
pool: web::Data<db::PgPool>,
params: web::Path<UpdateParams>,
) -> Result<HttpResponse, Error> {
web::block(move || db::toggle_task(params.id, &pool)).await?;
Ok(redirect_to("/"))
}
async fn delete(
pool: web::Data<db::PgPool>,
params: web::Path<UpdateParams>,
session: Session,
) -> Result<HttpResponse, Error> {
web::block(move || db::delete_task(params.id, &pool)).await?;
session::set_flash(&session, FlashMessage::success("Task was deleted."))?;
Ok(redirect_to("/"))
}
fn redirect_to(location: &str) -> HttpResponse {
HttpResponse::Found()
.header(http::header::LOCATION, location)
.finish()
}
pub fn bad_request<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/400.html")?
.set_status_code(res.status())
.into_response(res.request())?;
Ok(ErrorHandlerResponse::Response(
res.into_response(new_resp.into_body()),
))
}
pub fn not_found<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/404.html")?
.set_status_code(res.status())
.into_response(res.request())?;
Ok(ErrorHandlerResponse::Response(
res.into_response(new_resp.into_body()),
))
}
pub fn internal_server_error<B>(
res: dev::ServiceResponse<B>,
) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/500.html")?
.set_status_code(res.status())
.into_response(res.request())?;
Ok(ErrorHandlerResponse::Response(
res.into_response(new_resp.into_body()),
))
}

View File

@ -24,7 +24,8 @@ mod session;
static SESSION_SIGNING_KEY: &[u8] = &[0; 32];
fn main() -> io::Result<()> {
#[actix_rt::main]
async fn main() -> io::Result<()> {
dotenv().ok();
env::set_var("RUST_LOG", "actix_todo=debug,actix_web=info");
@ -54,14 +55,12 @@ fn main() -> io::Result<()> {
.wrap(Logger::default())
.wrap(session_store)
.wrap(error_handlers)
.service(web::resource("/").route(web::get().to_async(api::index)))
.service(web::resource("/todo").route(web::post().to_async(api::create)))
.service(
web::resource("/todo/{id}").route(web::post().to_async(api::update)),
)
.service(web::resource("/").route(web::get().to(api::index)))
.service(web::resource("/todo").route(web::post().to(api::create)))
.service(web::resource("/todo/{id}").route(web::post().to(api::update)))
.service(fs::Files::new("/static", "static/"))
};
debug!("Starting server");
HttpServer::new(app).bind("localhost:8088")?.run()
HttpServer::new(app).bind("localhost:8088")?.start().await
}

View File

@ -1,12 +1,11 @@
[package]
name = "unix-socket"
version = "0.1.0"
version = "1.0.0"
authors = ["Messense Lv <messense@icloud.com>"]
workspace = ".."
edition = "2018"
[dependencies]
env_logger = "0.5"
tokio-uds = "0.2"
actix-web = { version = "1.0.5", features = ["uds"] }
env_logger = "0.6"
actix-web = "2.0.0-alpha.3"
actix-rt = "1.0.0-alpha.3"

View File

@ -1,10 +1,12 @@
use actix_web::{middleware, web, App, HttpRequest, HttpServer};
fn index(_req: HttpRequest) -> &'static str {
async fn index(_req: HttpRequest) -> &'static str {
"Hello world!"
}
fn main() -> std::io::Result<()> {
#[actix_rt::main]
#[cfg(unix)]
async fn main() -> std::io::Result<()> {
::std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
env_logger::init();
@ -13,10 +15,18 @@ fn main() -> std::io::Result<()> {
// enable logger - always register actix-web Logger middleware last
.wrap(middleware::Logger::default())
.service(
web::resource("/index.html").route(web::get().to(|| "Hello world!")),
web::resource("/index.html")
.route(web::get().to(|| async { "Hello world!" })),
)
.service(web::resource("/").to(index))
})
.bind_uds("/tmp/actix-uds.socket")?
.run()
.start()
.await
}
#[cfg(not(unix))]
fn main() -> std::io::Result<()> {
println!("not supported");
Ok(())
}