1
0
mirror of https://github.com/actix/examples synced 2024-11-23 14:31:07 +01:00
This commit is contained in:
Rob Ede 2022-02-18 02:44:02 +00:00
parent aca1dab890
commit fbd3b228e9
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
48 changed files with 103 additions and 261 deletions

View File

@ -5,10 +5,7 @@ use tokio::sync::RwLock;
use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer}; use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer};
/// simple handle /// simple handle
async fn success( async fn success(enforcer: web::Data<RwLock<Enforcer>>, req: HttpRequest) -> HttpResponse {
enforcer: web::Data<RwLock<Enforcer>>,
req: HttpRequest,
) -> HttpResponse {
let mut e = enforcer.write().await; let mut e = enforcer.write().await;
println!("{:?}", req); println!("{:?}", req);
assert_eq!(vec!["data2_admin"], e.get_roles_for_user("alice", None)); assert_eq!(vec!["data2_admin"], e.get_roles_for_user("alice", None));

View File

@ -11,8 +11,8 @@ static ref API_KEY: String = std::env::var("SPARKPOST_API_KEY").expect("SPARKPOS
pub fn send_invitation(invitation: &Invitation) -> Result<(), ServiceError> { pub fn send_invitation(invitation: &Invitation) -> Result<(), ServiceError> {
let tm = Transmission::new_eu(API_KEY.as_str()); let tm = Transmission::new_eu(API_KEY.as_str());
let sending_email = std::env::var("SENDING_EMAIL_ADDRESS") let sending_email =
.expect("SENDING_EMAIL_ADDRESS must be set"); std::env::var("SENDING_EMAIL_ADDRESS").expect("SENDING_EMAIL_ADDRESS must be set");
// new email message with sender name and email // new email message with sender name and email
let mut email = Message::new(EmailAddress::new(sending_email, "Let's Organise")); let mut email = Message::new(EmailAddress::new(sending_email, "Let's Organise"));

View File

@ -20,14 +20,11 @@ pub enum ServiceError {
impl ResponseError for ServiceError { impl ResponseError for ServiceError {
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> HttpResponse {
match self { match self {
ServiceError::InternalServerError => HttpResponse::InternalServerError() ServiceError::InternalServerError => {
.json("Internal Server Error, Please try later"), HttpResponse::InternalServerError().json("Internal Server Error, Please try later")
ServiceError::BadRequest(ref message) => {
HttpResponse::BadRequest().json(message)
}
ServiceError::Unauthorized => {
HttpResponse::Unauthorized().json("Unauthorized")
} }
ServiceError::BadRequest(ref message) => HttpResponse::BadRequest().json(message),
ServiceError::Unauthorized => HttpResponse::Unauthorized().json("Unauthorized"),
} }
} }
} }
@ -47,8 +44,7 @@ impl From<DBError> for ServiceError {
match error { match error {
DBError::DatabaseError(kind, info) => { DBError::DatabaseError(kind, info) => {
if let DatabaseErrorKind::UniqueViolation = kind { if let DatabaseErrorKind::UniqueViolation = kind {
let message = let message = info.details().unwrap_or_else(|| info.message()).to_string();
info.details().unwrap_or_else(|| info.message()).to_string();
return ServiceError::BadRequest(message); return ServiceError::BadRequest(message);
} }
ServiceError::InternalServerError ServiceError::InternalServerError

View File

@ -15,8 +15,7 @@ pub async fn post_invitation(
pool: web::Data<Pool>, pool: web::Data<Pool>,
) -> Result<HttpResponse, actix_web::Error> { ) -> Result<HttpResponse, actix_web::Error> {
// run diesel blocking code // run diesel blocking code
web::block(move || create_invitation(invitation_data.into_inner().email, pool)) web::block(move || create_invitation(invitation_data.into_inner().email, pool)).await??;
.await??;
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} }
@ -30,10 +29,7 @@ fn create_invitation(
} }
/// Diesel query /// Diesel query
fn query( fn query(eml: String, pool: web::Data<Pool>) -> Result<Invitation, crate::errors::ServiceError> {
eml: String,
pool: web::Data<Pool>,
) -> Result<Invitation, crate::errors::ServiceError> {
use crate::schema::invitations::dsl::invitations; use crate::schema::invitations::dsl::invitations;
let new_invitation: Invitation = eml.into(); let new_invitation: Invitation = eml.into();

View File

@ -31,8 +31,7 @@ async fn main() -> std::io::Result<()> {
let pool: models::Pool = r2d2::Pool::builder() let pool: models::Pool = r2d2::Pool::builder()
.build(manager) .build(manager)
.expect("Failed to create pool."); .expect("Failed to create pool.");
let domain: String = let domain: String = std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string());
std::env::var("DOMAIN").unwrap_or_else(|_| "localhost".to_string());
// Start http server // Start http server
HttpServer::new(move || { HttpServer::new(move || {

View File

@ -20,9 +20,10 @@ pub fn hash_password(password: &str) -> Result<String, ServiceError> {
} }
pub fn verify(hash: &str, password: &str) -> Result<bool, ServiceError> { pub fn verify(hash: &str, password: &str) -> Result<bool, ServiceError> {
argon2::verify_encoded_ext(hash, password.as_bytes(), SECRET_KEY.as_bytes(), &[]) argon2::verify_encoded_ext(hash, password.as_bytes(), SECRET_KEY.as_bytes(), &[]).map_err(
.map_err(|err| { |err| {
dbg!(err); dbg!(err);
ServiceError::Unauthorized ServiceError::Unauthorized
}) },
)
} }

View File

@ -9,8 +9,7 @@ use actix_web::{
header::{self, ContentType}, header::{self, ContentType},
Method, StatusCode, Method, StatusCode,
}, },
middleware, web, App, Either, HttpRequest, HttpResponse, HttpServer, Responder, middleware, web, App, Either, HttpRequest, HttpResponse, HttpServer, Responder, Result,
Result,
}; };
use async_stream::stream; use async_stream::stream;
@ -44,8 +43,7 @@ async fn welcome(req: HttpRequest, session: Session) -> Result<HttpResponse> {
async fn default_handler(req_method: Method) -> Result<impl Responder> { async fn default_handler(req_method: Method) -> Result<impl Responder> {
match req_method { match req_method {
Method::GET => { Method::GET => {
let file = NamedFile::open("static/404.html")? let file = NamedFile::open("static/404.html")?.set_status_code(StatusCode::NOT_FOUND);
.set_status_code(StatusCode::NOT_FOUND);
Ok(Either::Left(file)) Ok(Either::Left(file))
} }
_ => Ok(Either::Right(HttpResponse::MethodNotAllowed().finish())), _ => Ok(Either::Right(HttpResponse::MethodNotAllowed().finish())),
@ -93,9 +91,7 @@ async fn main() -> io::Result<()> {
// with path parameters // with path parameters
.service(web::resource("/user/{name}").route(web::get().to(with_param))) .service(web::resource("/user/{name}").route(web::get().to(with_param)))
// async response body // async response body
.service( .service(web::resource("/async-body/{name}").route(web::get().to(response_body)))
web::resource("/async-body/{name}").route(web::get().to(response_body)),
)
.service( .service(
web::resource("/test").to(|req: HttpRequest| match *req.method() { web::resource("/test").to(|req: HttpRequest| match *req.method() {
Method::GET => HttpResponse::Ok(), Method::GET => HttpResponse::Ok(),
@ -112,14 +108,14 @@ async fn main() -> io::Result<()> {
// static files // static files
.service(Files::new("/static", "static").show_files_listing()) .service(Files::new("/static", "static").show_files_listing())
// redirect // redirect
.service(web::resource("/").route(web::get().to( .service(
|req: HttpRequest| async move { web::resource("/").route(web::get().to(|req: HttpRequest| async move {
println!("{:?}", req); println!("{:?}", req);
HttpResponse::Found() HttpResponse::Found()
.insert_header((header::LOCATION, "static/welcome.html")) .insert_header((header::LOCATION, "static/welcome.html"))
.finish() .finish()
}, })),
))) )
// default // default
.default_service(web::to(default_handler)) .default_service(web::to(default_handler))
}) })

View File

@ -93,8 +93,7 @@ async fn main() -> std::io::Result<()> {
env_logger::init(); env_logger::init();
HttpServer::new(move || { HttpServer::new(move || {
App::new() App::new().service(web::resource("/something").route(web::get().to(do_something)))
.service(web::resource("/something").route(web::get().to(do_something)))
}) })
.bind("127.0.0.1:8088")? .bind("127.0.0.1:8088")?
.run() .run()

View File

@ -2,15 +2,11 @@ use actix_web::{web, Error, HttpResponse};
use crate::common::{Part, Product}; use crate::common::{Part, Product};
pub async fn get_products( pub async fn get_products(_query: web::Query<Option<Part>>) -> Result<HttpResponse, Error> {
_query: web::Query<Option<Part>>,
) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} }
pub async fn add_product( pub async fn add_product(_new_product: web::Json<Product>) -> Result<HttpResponse, Error> {
_new_product: web::Json<Product>,
) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().finish()) Ok(HttpResponse::Ok().finish())
} }

View File

@ -49,10 +49,7 @@ pub async fn create(
session: Session, session: Session,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
if params.description.is_empty() { if params.description.is_empty() {
session::set_flash( session::set_flash(&session, FlashMessage::error("Description cannot be empty"))?;
&session,
FlashMessage::error("Description cannot be empty"),
)?;
Ok(redirect_to("/")) Ok(redirect_to("/"))
} else { } else {
db::create_task(params.into_inner().description, &pool) db::create_task(params.into_inner().description, &pool)
@ -133,9 +130,7 @@ pub fn not_found<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse
Ok(ErrorHandlerResponse::Response(res.into_response(new_resp))) Ok(ErrorHandlerResponse::Response(res.into_response(new_resp)))
} }
pub fn internal_server_error<B>( pub fn internal_server_error<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
res: dev::ServiceResponse<B>,
) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/500.html")? let new_resp = NamedFile::open("static/errors/500.html")?
.set_status_code(res.status()) .set_status_code(res.status())
.into_response(res.request()) .into_response(res.request())

View File

@ -32,8 +32,7 @@ async fn main() -> io::Result<()> {
HttpServer::new(move || { HttpServer::new(move || {
log::debug!("Constructing the App"); log::debug!("Constructing the App");
let mut templates = let mut templates = Tera::new("templates/**/*").expect("errors in tera templates");
Tera::new("templates/**/*").expect("errors in tera templates");
templates.autoescape_on(vec!["tera"]); templates.autoescape_on(vec!["tera"]);
let session_store = CookieSession::signed(SESSION_SIGNING_KEY).secure(false); let session_store = CookieSession::signed(SESSION_SIGNING_KEY).secure(false);

View File

@ -28,10 +28,7 @@ impl Task {
Ok(tasks) Ok(tasks)
} }
pub async fn insert( pub async fn insert(todo: NewTask, connection: &SqlitePool) -> Result<(), sqlx::Error> {
todo: NewTask,
connection: &SqlitePool,
) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query!(
r#" r#"
INSERT INTO tasks (description) INSERT INTO tasks (description)
@ -45,10 +42,7 @@ impl Task {
Ok(()) Ok(())
} }
pub async fn toggle_with_id( pub async fn toggle_with_id(id: i32, connection: &SqlitePool) -> Result<(), sqlx::Error> {
id: i32,
connection: &SqlitePool,
) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query!(
r#" r#"
UPDATE tasks UPDATE tasks
@ -63,10 +57,7 @@ impl Task {
Ok(()) Ok(())
} }
pub async fn delete_with_id( pub async fn delete_with_id(id: i32, connection: &SqlitePool) -> Result<(), sqlx::Error> {
id: i32,
connection: &SqlitePool,
) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query!(
r#" r#"
DELETE FROM tasks DELETE FROM tasks

View File

@ -36,8 +36,7 @@ async fn get_user(
if let Some(user) = user { if let Some(user) = user {
Ok(HttpResponse::Ok().json(user)) Ok(HttpResponse::Ok().json(user))
} else { } else {
let res = HttpResponse::NotFound() let res = HttpResponse::NotFound().body(format!("No user found with uid: {}", user_uid));
.body(format!("No user found with uid: {}", user_uid));
Ok(res) Ok(res)
} }
} }

View File

@ -25,10 +25,7 @@ async fn add_user(client: web::Data<Client>, form: web::Form<User>) -> HttpRespo
/// Gets the user with the supplied username. /// Gets the user with the supplied username.
#[get("/get_user/{username}")] #[get("/get_user/{username}")]
async fn get_user( async fn get_user(client: web::Data<Client>, username: web::Path<String>) -> HttpResponse {
client: web::Data<Client>,
username: web::Path<String>,
) -> HttpResponse {
let username = username.into_inner(); let username = username.into_inner();
let collection: Collection<User> = client.database(DB_NAME).collection(COLL_NAME); let collection: Collection<User> = client.database(DB_NAME).collection(COLL_NAME);
match collection match collection
@ -36,8 +33,9 @@ async fn get_user(
.await .await
{ {
Ok(Some(user)) => HttpResponse::Ok().json(user), Ok(Some(user)) => HttpResponse::Ok().json(user),
Ok(None) => HttpResponse::NotFound() Ok(None) => {
.body(format!("No user found with username {}", username)), HttpResponse::NotFound().body(format!("No user found with username {}", username))
}
Err(err) => HttpResponse::InternalServerError().body(err.to_string()), Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
} }
} }
@ -59,8 +57,7 @@ async fn create_username_index(client: &Client) {
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
let uri = std::env::var("MONGODB_URI") let uri = std::env::var("MONGODB_URI").unwrap_or_else(|_| "mongodb://localhost:27017".into());
.unwrap_or_else(|_| "mongodb://localhost:27017".into());
let client = Client::with_uri_str(uri).await.expect("failed to connect"); let client = Client::with_uri_str(uri).await.expect("failed to connect");
create_username_index(&client).await; create_username_index(&client).await;

View File

@ -9,8 +9,7 @@ use super::*;
#[actix_web::test] #[actix_web::test]
#[ignore = "requires MongoDB instance running"] #[ignore = "requires MongoDB instance running"]
async fn test() { async fn test() {
let uri = std::env::var("MONGODB_URI") let uri = std::env::var("MONGODB_URI").unwrap_or_else(|_| "mongodb://localhost:27017".into());
.unwrap_or_else(|_| "mongodb://localhost:27017".into());
let client = Client::with_uri_str(uri).await.expect("failed to connect"); let client = Client::with_uri_str(uri).await.expect("failed to connect");

View File

@ -46,9 +46,7 @@ async fn cache_stuff(
} }
} }
async fn del_stuff( async fn del_stuff(redis: web::Data<Addr<RedisActor>>) -> actix_web::Result<HttpResponse> {
redis: web::Data<Addr<RedisActor>>,
) -> actix_web::Result<HttpResponse> {
let res = redis let res = redis
.send(Command(resp_array![ .send(Command(resp_array![
"DEL", "DEL",

View File

@ -63,13 +63,8 @@ async fn main() -> io::Result<()> {
// store db pool as Data object // store db pool as Data object
.app_data(web::Data::new(pool.clone())) .app_data(web::Data::new(pool.clone()))
.wrap(middleware::Logger::default()) .wrap(middleware::Logger::default())
.service( .service(web::resource("/asyncio_weather").route(web::get().to(asyncio_weather)))
web::resource("/asyncio_weather").route(web::get().to(asyncio_weather)), .service(web::resource("/parallel_weather").route(web::get().to(parallel_weather)))
)
.service(
web::resource("/parallel_weather")
.route(web::get().to(parallel_weather)),
)
}) })
.bind(("127.0.0.1", 8080))? .bind(("127.0.0.1", 8080))?
.workers(2) .workers(2)

View File

@ -1,8 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use actix_web::{ use actix_web::{middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder, Result};
middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder, Result,
};
struct AppState { struct AppState {
foo: String, foo: String,

View File

@ -23,8 +23,7 @@ async fn save_file(mut payload: Multipart) -> Result<HttpResponse, Error> {
//make key //make key
let s3_upload_key = format!("projects/{}/", "posts_id"); let s3_upload_key = format!("projects/{}/", "posts_id");
//create tmp file and upload s3 and remove tmp file //create tmp file and upload s3 and remove tmp file
let upload_files: Vec<UploadFile> = let upload_files: Vec<UploadFile> = upload_save_file(pl.1, s3_upload_key).await.unwrap();
upload_save_file(pl.1, s3_upload_key).await.unwrap();
println!("upload_files={:#?}", upload_files); println!("upload_files={:#?}", upload_files);
Ok(HttpResponse::Ok().into()) Ok(HttpResponse::Ok().into())
} }
@ -79,8 +78,7 @@ async fn main() -> std::io::Result<()> {
dotenv().ok(); dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let aws_access_key_id = let aws_access_key_id = env::var("AWS_ACCESS_KEY_ID").expect("AWS_ACCESS_KEY_ID must be set");
env::var("AWS_ACCESS_KEY_ID").expect("AWS_ACCESS_KEY_ID must be set");
let aws_secret_access_key = let aws_secret_access_key =
env::var("AWS_SECRET_ACCESS_KEY").expect("AWS_SECRET_ACCESS_KEY must be set"); env::var("AWS_SECRET_ACCESS_KEY").expect("AWS_SECRET_ACCESS_KEY must be set");
let aws_s3_bucket_name = let aws_s3_bucket_name =

View File

@ -12,10 +12,7 @@ use self::star_wars::{QueryRoot, StarWars, StarWarsSchema};
/// GraphQL endpoint /// GraphQL endpoint
#[route("/graphql", method = "GET", method = "POST")] #[route("/graphql", method = "GET", method = "POST")]
async fn graphql( async fn graphql(schema: web::Data<StarWarsSchema>, req: GraphQLRequest) -> GraphQLResponse {
schema: web::Data<StarWarsSchema>,
req: GraphQLRequest,
) -> GraphQLResponse {
schema.execute(req.into_inner()).await.into() schema.execute(req.into_inner()).await.into()
} }

View File

@ -25,10 +25,7 @@ async fn graphql_playground() -> impl Responder {
/// GraphQL endpoint /// GraphQL endpoint
#[route("/graphql", method = "GET", method = "POST")] #[route("/graphql", method = "GET", method = "POST")]
async fn graphql( async fn graphql(st: web::Data<Schema>, data: web::Json<GraphQLRequest>) -> impl Responder {
st: web::Data<Schema>,
data: web::Json<GraphQLRequest>,
) -> impl Responder {
let user = data.execute(&st, &()).await; let user = data.execute(&st, &()).await;
HttpResponse::Ok().json(user) HttpResponse::Ok().json(user)
} }

View File

@ -1,8 +1,6 @@
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use actix_web::{ use actix_web::{error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer,
};
use awc::Client; use awc::Client;
use clap::StructOpt; use clap::StructOpt;
use url::Url; use url::Url;
@ -23,9 +21,7 @@ async fn forward(
.request_from(new_url.as_str(), req.head()) .request_from(new_url.as_str(), req.head())
.no_decompress(); .no_decompress();
let forwarded_req = match req.head().peer_addr { let forwarded_req = match req.head().peer_addr {
Some(addr) => { Some(addr) => forwarded_req.insert_header(("x-forwarded-for", format!("{}", addr.ip()))),
forwarded_req.insert_header(("x-forwarded-for", format!("{}", addr.ip())))
}
None => forwarded_req, None => forwarded_req,
}; };
@ -37,9 +33,7 @@ async fn forward(
let mut client_resp = HttpResponse::build(res.status()); let mut client_resp = HttpResponse::build(res.status());
// Remove `Connection` as per // Remove `Connection` as per
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection#Directives // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection#Directives
for (header_name, header_value) in for (header_name, header_value) in res.headers().iter().filter(|(h, _)| *h != "connection") {
res.headers().iter().filter(|(h, _)| *h != "connection")
{
client_resp.insert_header((header_name.clone(), header_value.clone())); client_resp.insert_header((header_name.clone(), header_value.clone()));
} }

View File

@ -66,15 +66,13 @@ async fn main() -> std::io::Result<()> {
/// Create simple rustls client config from root certificates. /// Create simple rustls client config from root certificates.
fn rustls_config() -> ClientConfig { fn rustls_config() -> ClientConfig {
let mut root_store = RootCertStore::empty(); let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map( root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints(
OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject,
ta.subject, ta.spki,
ta.spki, ta.name_constraints,
ta.name_constraints, )
) }));
},
));
rustls::ClientConfig::builder() rustls::ClientConfig::builder()
.with_safe_defaults() .with_safe_defaults()

View File

@ -10,10 +10,7 @@ use openssl::{
x509::X509, x509::X509,
}; };
pub async fn gen_tls_cert( pub async fn gen_tls_cert(user_email: &str, user_domain: &str) -> anyhow::Result<Certificate> {
user_email: &str,
user_domain: &str,
) -> anyhow::Result<Certificate> {
// Create acme-challenge dir. // Create acme-challenge dir.
fs::create_dir("./acme-challenge").unwrap(); fs::create_dir("./acme-challenge").unwrap();

View File

@ -5,13 +5,11 @@ use std::{any::Any, env, fs::File, io::BufReader, net::SocketAddr};
use actix_tls::accept::rustls::{reexports::ServerConfig, TlsStream}; use actix_tls::accept::rustls::{reexports::ServerConfig, TlsStream};
use actix_web::{ use actix_web::{
dev::Extensions, rt::net::TcpStream, web, App, HttpRequest, HttpResponse, dev::Extensions, rt::net::TcpStream, web, App, HttpRequest, HttpResponse, HttpServer, Responder,
HttpServer, Responder,
}; };
use log::info; use log::info;
use rustls::{ use rustls::{
server::AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, server::AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, RootCertStore,
RootCertStore,
}; };
use rustls_pemfile::{certs, pkcs8_private_keys}; use rustls_pemfile::{certs, pkcs8_private_keys};

View File

@ -1,6 +1,4 @@
use actix_web::{ use actix_web::{error, post, web, App, HttpRequest, HttpResponse, HttpServer, Responder};
error, post, web, App, HttpRequest, HttpResponse, HttpServer, Responder,
};
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize)] #[derive(Deserialize)]
@ -18,9 +16,7 @@ fn json_error_handler(err: error::JsonPayloadError, _req: &HttpRequest) -> error
let detail = err.to_string(); let detail = err.to_string();
let resp = match &err { let resp = match &err {
JsonPayloadError::ContentType => { JsonPayloadError::ContentType => HttpResponse::UnsupportedMediaType().body(detail),
HttpResponse::UnsupportedMediaType().body(detail)
}
JsonPayloadError::Deserialize(json_err) if json_err.is_data() => { JsonPayloadError::Deserialize(json_err) if json_err.is_data() => {
HttpResponse::UnprocessableEntity().body(detail) HttpResponse::UnprocessableEntity().body(detail)
} }

View File

@ -23,8 +23,7 @@ impl ResponseError for Error {
// builds the actual response to send back when an error occurs // builds the actual response to send back when an error occurs
fn error_response(&self) -> web::HttpResponse { fn error_response(&self) -> web::HttpResponse {
let err_json = json!({ "error": self.msg }); let err_json = json!({ "error": self.msg });
web::HttpResponse::build(StatusCode::from_u16(self.status).unwrap()) web::HttpResponse::build(StatusCode::from_u16(self.status).unwrap()).json(err_json)
.json(err_json)
} }
} }
@ -40,11 +39,9 @@ async fn main() -> io::Result<()> {
let ip_address = "127.0.0.1:8000"; let ip_address = "127.0.0.1:8000";
println!("Running server on {}", ip_address); println!("Running server on {}", ip_address);
HttpServer::new(|| { HttpServer::new(|| App::new().service(web::resource("/").route(web::get().to(index))))
App::new().service(web::resource("/").route(web::get().to(index))) .bind(ip_address)
}) .expect("Can not bind to port 8000")
.bind(ip_address) .run()
.expect("Can not bind to port 8000") .await
.run()
.await
} }

View File

@ -1,6 +1,4 @@
use actix_web::{ use actix_web::{error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer,
};
use futures::StreamExt; use futures::StreamExt;
use json::JsonValue; use json::JsonValue;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -92,10 +90,9 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_index() { async fn test_index() {
let app = test::init_service( let app =
App::new().service(web::resource("/").route(web::post().to(index))), test::init_service(App::new().service(web::resource("/").route(web::post().to(index))))
) .await;
.await;
let req = test::TestRequest::post() let req = test::TestRequest::post()
.uri("/") .uri("/")

View File

@ -18,10 +18,7 @@ use serde_json::Value;
mod convention; mod convention;
/// The main handler for JSONRPC server. /// The main handler for JSONRPC server.
async fn rpc_handler( async fn rpc_handler(body: Bytes, app_state: web::Data<AppState>) -> Result<HttpResponse, Error> {
body: Bytes,
app_state: web::Data<AppState>,
) -> Result<HttpResponse, Error> {
let reqjson: convention::Request = match serde_json::from_slice(body.as_ref()) { let reqjson: convention::Request = match serde_json::from_slice(body.as_ref()) {
Ok(ok) => ok, Ok(ok) => ok,
Err(_) => { Err(_) => {
@ -90,10 +87,7 @@ async fn rpc_select(
pub trait ImplNetwork { pub trait ImplNetwork {
fn ping(&self) -> String; fn ping(&self) -> String;
fn wait( fn wait(&self, d: u64) -> Pin<Box<dyn Future<Output = Result<String, Box<dyn error::Error>>>>>;
&self,
d: u64,
) -> Pin<Box<dyn Future<Output = Result<String, Box<dyn error::Error>>>>>;
fn get(&self) -> u32; fn get(&self) -> u32;
fn inc(&mut self); fn inc(&mut self);
@ -114,10 +108,7 @@ impl ImplNetwork for ObjNetwork {
String::from("pong") String::from("pong")
} }
fn wait( fn wait(&self, d: u64) -> Pin<Box<dyn Future<Output = Result<String, Box<dyn error::Error>>>>> {
&self,
d: u64,
) -> Pin<Box<dyn Future<Output = Result<String, Box<dyn error::Error>>>>> {
async move { async move {
actix_web::rt::time::sleep(Duration::from_secs(d)).await; actix_web::rt::time::sleep(Duration::from_secs(d)).await;
Ok(String::from("pong")) Ok(String::from("pong"))

View File

@ -7,9 +7,7 @@ use rustls_pemfile::{certs, pkcs8_private_keys};
#[get("/")] #[get("/")]
async fn index() -> String { async fn index() -> String {
String::from( String::from("<html><head><title>FOO BAR</title></head><body><h1>FOO BAR</h1></body></html>")
"<html><head><title>FOO BAR</title></head><body><h1>FOO BAR</h1></body></html>",
)
} }
#[actix_web::main] #[actix_web::main]

View File

@ -32,9 +32,11 @@ async fn main() -> std::io::Result<()> {
.service(web::resource("/login").to(|| async { .service(web::resource("/login").to(|| async {
"You are on /login. Go to src/redirect.rs to change this behavior." "You are on /login. Go to src/redirect.rs to change this behavior."
})) }))
.service(web::resource("/").to(|| async { .service(
"Hello, middleware! Check the console where the server is run." web::resource("/").to(|| async {
})) "Hello, middleware! Check the console where the server is run."
}),
)
}) })
.bind(("127.0.0.1", 8080))? .bind(("127.0.0.1", 8080))?
.run() .run()

View File

@ -1,2 +1 @@
max_width = 89
reorder_imports = true reorder_imports = true

View File

@ -37,10 +37,8 @@ impl Broadcaster {
fn spawn_ping(me: Data<Mutex<Self>>) { fn spawn_ping(me: Data<Mutex<Self>>) {
actix_web::rt::spawn(async move { actix_web::rt::spawn(async move {
let mut task = IntervalStream::new(interval_at( let mut task =
Instant::now(), IntervalStream::new(interval_at(Instant::now(), Duration::from_secs(10)));
Duration::from_secs(10),
));
while task.next().await.is_some() { while task.next().await.is_some() {
me.lock().remove_stale_clients(); me.lock().remove_stale_clients();
@ -85,10 +83,7 @@ pub struct Client(ReceiverStream<Bytes>);
impl Stream for Client { impl Stream for Client {
type Item = Result<Bytes, Error>; type Item = Result<Bytes, Error>;
fn poll_next( fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
match Pin::new(&mut self.0).poll_next(cx) { match Pin::new(&mut self.0).poll_next(cx) {
Poll::Ready(Some(v)) => Poll::Ready(Some(Ok(v))), Poll::Ready(Some(v)) => Poll::Ready(Some(Ok(v))),
Poll::Ready(None) => Poll::Ready(None), Poll::Ready(None) => Poll::Ready(None),

View File

@ -46,10 +46,7 @@ async fn new_client(broadcaster: Data<Mutex<Broadcaster>>) -> impl Responder {
.streaming(rx) .streaming(rx)
} }
async fn broadcast( async fn broadcast(msg: Path<String>, broadcaster: Data<Mutex<Broadcaster>>) -> impl Responder {
msg: Path<String>,
broadcaster: Data<Mutex<Broadcaster>>,
) -> impl Responder {
broadcaster.lock().send(&msg.into_inner()); broadcaster.lock().send(&msg.into_inner());
HttpResponse::Ok().body("msg sent") HttpResponse::Ok().body("msg sent")
} }

View File

@ -20,10 +20,7 @@ async fn index(hb: web::Data<Handlebars<'_>>) -> HttpResponse {
} }
#[get("/{user}/{data}")] #[get("/{user}/{data}")]
async fn user( async fn user(hb: web::Data<Handlebars<'_>>, path: web::Path<(String, String)>) -> HttpResponse {
hb: web::Data<Handlebars<'_>>,
path: web::Path<(String, String)>,
) -> HttpResponse {
let info = path.into_inner(); let info = path.into_inner();
let data = json!({ let data = json!({
"user": info.0, "user": info.0,
@ -72,10 +69,7 @@ fn not_found<B>(res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<BoxBody>
} }
// Generic error handler. // Generic error handler.
fn get_error_response<B>( fn get_error_response<B>(res: &ServiceResponse<B>, error: &str) -> HttpResponse<BoxBody> {
res: &ServiceResponse<B>,
error: &str,
) -> HttpResponse<BoxBody> {
let request = res.request(); let request = res.request();
// Provide a fallback to a simple plain text response in case an error occurs during the // Provide a fallback to a simple plain text response in case an error occurs during the

View File

@ -33,8 +33,7 @@ async fn main() -> std::io::Result<()> {
println!("Listening on: 127.0.0.1:8080, open browser and visit have a try!"); println!("Listening on: 127.0.0.1:8080, open browser and visit have a try!");
HttpServer::new(|| { HttpServer::new(|| {
let tera = let tera = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
App::new() App::new()
.app_data(web::Data::new(tera)) .app_data(web::Data::new(tera))

View File

@ -13,9 +13,7 @@ impl ResponseError for MyErr {}
#[allow(unused_must_use)] // ywrite_min causes warning: unused borrow that must be used #[allow(unused_must_use)] // ywrite_min causes warning: unused borrow that must be used
#[get("/")] #[get("/")]
async fn index( async fn index(query: web::Query<HashMap<String, String>>) -> Result<HttpResponse, Error> {
query: web::Query<HashMap<String, String>>,
) -> Result<HttpResponse, Error> {
// `ywrite_min` is work in progress check your templates before put in production // `ywrite_min` is work in progress check your templates before put in production
// or use `ywrite_html` // or use `ywrite_html`
Ok(HttpResponse::Ok() Ok(HttpResponse::Ok()

View File

@ -14,10 +14,7 @@ async fn main() -> std::io::Result<()> {
App::new() App::new()
// enable logger - always register Actix Web Logger middleware last // enable logger - always register Actix Web Logger middleware last
.wrap(middleware::Logger::default()) .wrap(middleware::Logger::default())
.service( .service(web::resource("/index.html").route(web::get().to(|| async { "Hello world!" })))
web::resource("/index.html")
.route(web::get().to(|| async { "Hello world!" })),
)
.service(web::resource("/").to(index)) .service(web::resource("/").to(index))
}) })
.bind_uds("/tmp/actix-uds.socket")? .bind_uds("/tmp/actix-uds.socket")?

View File

@ -14,11 +14,7 @@ impl Actor for AutobahnWebSocket {
} }
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for AutobahnWebSocket { impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for AutobahnWebSocket {
fn handle( fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut Self::Context,
) {
if let Ok(msg) = msg { if let Ok(msg) = msg {
match msg { match msg {
ws::Message::Text(text) => ctx.text(text), ws::Message::Text(text) => ctx.text(text),

View File

@ -1,7 +1,5 @@
use actix_files::{Files, NamedFile}; use actix_files::{Files, NamedFile};
use actix_web::{ use actix_web::{middleware::Logger, web, App, Error, HttpRequest, HttpServer, Responder};
middleware::Logger, web, App, Error, HttpRequest, HttpServer, Responder,
};
use actix_web_actors::ws; use actix_web_actors::ws;
mod message; mod message;
@ -14,10 +12,7 @@ async fn index() -> impl Responder {
NamedFile::open_async("./static/index.html").await.unwrap() NamedFile::open_async("./static/index.html").await.unwrap()
} }
async fn chat_ws( async fn chat_ws(req: HttpRequest, stream: web::Payload) -> Result<impl Responder, Error> {
req: HttpRequest,
stream: web::Payload,
) -> Result<impl Responder, Error> {
ws::start(WsChatSession::default(), &req, stream) ws::start(WsChatSession::default(), &req, stream)
} }

View File

@ -20,12 +20,7 @@ impl WsChatServer {
Some(room) Some(room)
} }
fn add_client_to_room( fn add_client_to_room(&mut self, room_name: &str, id: Option<usize>, client: Client) -> usize {
&mut self,
room_name: &str,
id: Option<usize>,
client: Client,
) -> usize {
let mut id = id.unwrap_or_else(rand::random::<usize>); let mut id = id.unwrap_or_else(rand::random::<usize>);
if let Some(room) = self.rooms.get_mut(room_name) { if let Some(room) = self.rooms.get_mut(room_name) {
@ -50,12 +45,7 @@ impl WsChatServer {
id id
} }
fn send_chat_message( fn send_chat_message(&mut self, room_name: &str, msg: &str, _src: usize) -> Option<()> {
&mut self,
room_name: &str,
msg: &str,
_src: usize,
) -> Option<()> {
let mut room = self.take_room(room_name)?; let mut room = self.take_room(room_name)?;
for (id, client) in room.drain() { for (id, client) in room.drain() {

View File

@ -101,11 +101,7 @@ impl Handler<ChatMessage> for WsChatSession {
} }
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession { impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession {
fn handle( fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut Self::Context,
) {
let msg = match msg { let msg = match msg {
Err(_) => { Err(_) => {
ctx.stop(); ctx.stop();

View File

@ -68,11 +68,7 @@ impl Decoder for ChatCodec {
impl Encoder<ChatResponse> for ChatCodec { impl Encoder<ChatResponse> for ChatCodec {
type Error = io::Error; type Error = io::Error;
fn encode( fn encode(&mut self, msg: ChatResponse, dst: &mut BytesMut) -> Result<(), Self::Error> {
&mut self,
msg: ChatResponse,
dst: &mut BytesMut,
) -> Result<(), Self::Error> {
let msg = json::to_string(&msg).unwrap(); let msg = json::to_string(&msg).unwrap();
let msg_ref: &[u8] = msg.as_ref(); let msg_ref: &[u8] = msg.as_ref();
@ -112,11 +108,7 @@ impl Decoder for ClientChatCodec {
impl Encoder<ChatRequest> for ClientChatCodec { impl Encoder<ChatRequest> for ClientChatCodec {
type Error = io::Error; type Error = io::Error;
fn encode( fn encode(&mut self, msg: ChatRequest, dst: &mut BytesMut) -> Result<(), Self::Error> {
&mut self,
msg: ChatRequest,
dst: &mut BytesMut,
) -> Result<(), Self::Error> {
let msg = json::to_string(&msg).unwrap(); let msg = json::to_string(&msg).unwrap();
let msg_ref: &[u8] = msg.as_ref(); let msg_ref: &[u8] = msg.as_ref();

View File

@ -2,9 +2,7 @@ use std::time::{Duration, Instant};
use actix::prelude::*; use actix::prelude::*;
use actix_files::NamedFile; use actix_files::NamedFile;
use actix_web::{ use actix_web::{middleware::Logger, web, App, Error, HttpRequest, HttpServer, Responder};
middleware::Logger, web, App, Error, HttpRequest, HttpServer, Responder,
};
use actix_web_actors::ws; use actix_web_actors::ws;
mod codec; mod codec;
@ -103,11 +101,7 @@ impl Handler<session::Message> for WsChatSession {
/// WebSocket message handler /// WebSocket message handler
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession { impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession {
fn handle( fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut Self::Context,
) {
let msg = match msg { let msg = match msg {
Err(_) => { Err(_) => {
ctx.stop(); ctx.stop();

View File

@ -9,8 +9,7 @@ use std::{
use actix::*; use actix::*;
use actix_files::{Files, NamedFile}; use actix_files::{Files, NamedFile};
use actix_web::{ use actix_web::{
middleware::Logger, web, App, Error, HttpRequest, HttpResponse, HttpServer, middleware::Logger, web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder,
Responder,
}; };
use actix_web_actors::ws; use actix_web_actors::ws;

View File

@ -105,11 +105,7 @@ impl Handler<server::Message> for WsChatSession {
/// WebSocket message handler /// WebSocket message handler
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession { impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession {
fn handle( fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut Self::Context,
) {
let msg = match msg { let msg = match msg {
Err(_) => { Err(_) => {
ctx.stop(); ctx.stop();

View File

@ -3,9 +3,7 @@
//! Open `http://localhost:8080/` in browser to test. //! Open `http://localhost:8080/` in browser to test.
use actix_files::NamedFile; use actix_files::NamedFile;
use actix_web::{ use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder};
middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder,
};
use actix_web_actors::ws; use actix_web_actors::ws;
mod server; mod server;

View File

@ -55,11 +55,7 @@ impl Actor for MyWebSocket {
/// Handler for `ws::Message` /// Handler for `ws::Message`
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWebSocket { impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWebSocket {
fn handle( fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut Self::Context,
) {
// process websocket messages // process websocket messages
println!("WS: {:?}", msg); println!("WS: {:?}", msg);
match msg { match msg {