Migrate to actix 4.0 and tokio 1
This commit is contained in:
parent
ed68b728be
commit
30bd3d6a37
11 changed files with 786 additions and 1085 deletions
1732
Cargo.lock
generated
1732
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
45
Cargo.toml
45
Cargo.toml
|
@ -5,18 +5,18 @@ description = "Mitra backend"
|
|||
license = "AGPL-3.0"
|
||||
|
||||
edition = "2018"
|
||||
rust-version = "1.53"
|
||||
rust-version = "1.54"
|
||||
publish = false
|
||||
default-run = "mitra"
|
||||
|
||||
[dependencies]
|
||||
# Used to handle incoming HTTP requests
|
||||
actix-cors = "0.5.4"
|
||||
actix-files = "0.5.0"
|
||||
actix-web = "3.3.3"
|
||||
actix-web-httpauth = "0.5.1"
|
||||
actix-cors = "0.6.1"
|
||||
actix-files = "0.6.0"
|
||||
actix-web = "4.0.1"
|
||||
actix-web-httpauth = "0.6.0"
|
||||
# Used for managing async tasks
|
||||
actix-rt = "1.1.1"
|
||||
actix-rt = "2.7.0"
|
||||
# Used for HTML sanitization
|
||||
ammonia = "3.1.2"
|
||||
# Used for working with RSA keys, HTTP signatures and file uploads
|
||||
|
@ -26,9 +26,9 @@ chrono = { version = "0.4.19", features = ["serde"] }
|
|||
# Used to build admin CLI tool
|
||||
# Versions greater than beta.2 require Rust 1.54
|
||||
clap = { version = "3.0.0-beta.2", default-features = false, features = ["std", "derive"] }
|
||||
# Used for pooling database connections (compatible with tokio 0.2)
|
||||
deadpool = "0.5.2"
|
||||
deadpool-postgres = { version = "0.5.6", default-features = false }
|
||||
# Used for pooling database connections
|
||||
deadpool = "0.9.2"
|
||||
deadpool-postgres = { version = "0.10.2", default-features = false }
|
||||
# Used to read .env files
|
||||
dotenv = "0.15.0"
|
||||
# Used to work with hexadecimal strings
|
||||
|
@ -46,9 +46,9 @@ regex = "1.5.4"
|
|||
# Used to generate random numbers
|
||||
rand = "0.8.4"
|
||||
# Used for managing database migrations
|
||||
refinery = { version = "0.4.0", features = ["tokio-postgres"] }
|
||||
refinery = { version = "0.8.4", features = ["tokio-postgres"] }
|
||||
# Used for making async HTTP requests
|
||||
reqwest = { version = "0.10.10", features = ["json"] }
|
||||
reqwest = { version = "0.11.10", features = ["json", "multipart"] }
|
||||
# Used for working with RSA keys
|
||||
rsa = "0.5.0"
|
||||
pem = "1.0.2"
|
||||
|
@ -57,8 +57,7 @@ rust-argon2 = "0.8.3"
|
|||
# Used for working with ethereum keys
|
||||
secp256k1 = { version = "0.20.3", features = ["rand", "rand-std"] }
|
||||
# Used for serialization/deserialization
|
||||
# https://github.com/rust-db/refinery/issues/160
|
||||
serde = { version = "=1.0.117", features = ["derive"] }
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
# Used to parse config file
|
||||
serde_yaml = "0.8.17"
|
||||
|
@ -68,15 +67,15 @@ sha2 = "0.9.5"
|
|||
siwe = { git = "https://github.com/silverpill/siwe-rs", rev = "6589eb6fdcffbfb9ee2880906014f5cf71f0f441" }
|
||||
# Used for creating error types
|
||||
thiserror = "1.0.24"
|
||||
# Async runtime ( required for #[tokio::main] )
|
||||
tokio = { version = "0.2.25", features = ["macros"] }
|
||||
# Used for working with Postgresql database (compatible with tokio 0.2)
|
||||
tokio-postgres = { version = "0.5.5", features = ["with-chrono-0_4", "with-uuid-0_8", "with-serde_json-1"] }
|
||||
postgres-types = { version = "0.1.2", features = ["derive", "with-chrono-0_4", "with-uuid-0_8", "with-serde_json-1"] }
|
||||
postgres-protocol = "0.5.3"
|
||||
# Async runtime
|
||||
tokio = { version = "1.17.0", features = ["macros"] }
|
||||
# Used for working with Postgresql database
|
||||
tokio-postgres = { version = "0.7.5", features = ["with-chrono-0_4", "with-uuid-0_8", "with-serde_json-1"] }
|
||||
postgres-types = { version = "0.2.2", features = ["derive", "with-chrono-0_4", "with-uuid-0_8", "with-serde_json-1"] }
|
||||
postgres-protocol = "0.6.1"
|
||||
# Used to construct PostgreSQL queries
|
||||
postgres_query = "0.3.3"
|
||||
postgres_query_macro = "0.3.1"
|
||||
postgres_query = { git = "https://github.com/nolanderc/rust-postgres-query", rev = "b4422051c8a31fbba4a35f88004c1cefb1878dd5" }
|
||||
postgres_query_macro = { git = "https://github.com/nolanderc/rust-postgres-query", rev = "b4422051c8a31fbba4a35f88004c1cefb1878dd5" }
|
||||
# Used to work with URLs
|
||||
url = "2.2.2"
|
||||
# Used to generate lexicographically sortable IDs
|
||||
|
@ -84,7 +83,9 @@ ulid = { version = "0.4.1", features = ["uuid"] }
|
|||
# Used to work with UUIDs
|
||||
uuid = { version = "0.8.2", features = ["serde", "v4"] }
|
||||
# Used to query ethereum node
|
||||
web3 = { version = "0.15.0", default-features = false, features = ["http", "http-tls", "signing"] }
|
||||
web3 = { version = "0.16.0", default-features = false, features = ["http", "http-tls", "signing"] }
|
||||
# Dependency of web3; version 0.2.2 requires edition 2021
|
||||
impl-trait-for-tuples = "=0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.5.1"
|
||||
|
|
|
@ -21,7 +21,7 @@ Demo instance: https://mitra.social/ (invite-only)
|
|||
|
||||
## Requirements
|
||||
|
||||
- Rust 1.53+
|
||||
- Rust 1.54+
|
||||
- PostgreSQL 10.2+
|
||||
- IPFS node (optional, see [guide](./docs/ipfs.md))
|
||||
- Ethereum node (optional)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use actix_web::{
|
||||
get, post, web,
|
||||
HttpRequest, HttpResponse, Scope,
|
||||
http::HeaderMap,
|
||||
http::header::HeaderMap,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
@ -84,7 +84,7 @@ async fn actor_view(
|
|||
if !is_activitypub_request(request.headers()) {
|
||||
let page_url = get_profile_page_url(&config.instance_url(), &user.id);
|
||||
let response = HttpResponse::Found()
|
||||
.header("Location", page_url)
|
||||
.append_header(("Location", page_url))
|
||||
.finish();
|
||||
return Ok(response);
|
||||
};
|
||||
|
@ -293,7 +293,7 @@ pub async fn object_view(
|
|||
if !is_activitypub_request(request.headers()) {
|
||||
let page_url = get_post_page_url(&config.instance_url(), &post.id);
|
||||
let response = HttpResponse::Found()
|
||||
.header("Location", page_url)
|
||||
.append_header(("Location", page_url))
|
||||
.finish();
|
||||
return Ok(response);
|
||||
};
|
||||
|
@ -321,7 +321,10 @@ pub async fn object_view(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_web::http::{header, HeaderMap, HeaderValue};
|
||||
use actix_web::http::{
|
||||
header,
|
||||
header::{HeaderMap, HeaderValue},
|
||||
};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use tokio_postgres::config::{Config as DbConfig};
|
||||
use tokio_postgres::error::{Error as PgError, SqlState};
|
||||
use crate::errors::DatabaseError;
|
||||
|
||||
pub mod int_enum;
|
||||
pub mod migrate;
|
||||
|
@ -21,19 +23,15 @@ pub async fn create_database_client(db_config: &DbConfig) -> tokio_postgres::Cli
|
|||
}
|
||||
|
||||
pub fn create_pool(database_url: &str) -> Pool {
|
||||
deadpool_postgres::Pool::new(
|
||||
deadpool_postgres::Manager::new(
|
||||
let manager = deadpool_postgres::Manager::new(
|
||||
database_url.parse().expect("invalid database URL"),
|
||||
tokio_postgres::NoTls,
|
||||
),
|
||||
);
|
||||
// https://wiki.postgresql.org/wiki/Number_Of_Database_Connections
|
||||
num_cpus::get() * 2,
|
||||
)
|
||||
let pool_size = num_cpus::get() * 2;
|
||||
Pool::builder(manager).max_size(pool_size).build().unwrap()
|
||||
}
|
||||
|
||||
use tokio_postgres::error::{Error as PgError, SqlState};
|
||||
use crate::errors::DatabaseError;
|
||||
|
||||
pub async fn get_database_client(pool: &Pool)
|
||||
-> Result<deadpool_postgres::Client, DatabaseError>
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use actix_web::{
|
||||
dev::HttpResponseBuilder,
|
||||
http::StatusCode,
|
||||
HttpResponse,
|
||||
HttpResponse, HttpResponseBuilder,
|
||||
error::ResponseError,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use actix_web::{
|
||||
HttpRequest,
|
||||
http::{HeaderMap, Method, Uri},
|
||||
http::{Method, Uri, header::HeaderMap},
|
||||
};
|
||||
use regex::Regex;
|
||||
use tokio_postgres::GenericClient;
|
||||
|
@ -154,7 +154,11 @@ pub async fn verify_http_signature(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_web::http::{header, HeaderMap, HeaderName, HeaderValue, Uri};
|
||||
use actix_web::http::{
|
||||
header,
|
||||
header::{HeaderMap, HeaderName, HeaderValue},
|
||||
Uri,
|
||||
};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -77,10 +77,10 @@ async fn main() -> std::io::Result<()> {
|
|||
.wrap(ActixLogger::new("%r : %s : %{r}a"))
|
||||
.wrap(cors_config)
|
||||
.wrap(create_auth_error_handler())
|
||||
.data(web::PayloadConfig::default().limit(MAX_UPLOAD_SIZE))
|
||||
.data(web::JsonConfig::default().limit(MAX_UPLOAD_SIZE))
|
||||
.data(config.clone())
|
||||
.data(db_pool.clone())
|
||||
.app_data(web::PayloadConfig::default().limit(MAX_UPLOAD_SIZE))
|
||||
.app_data(web::JsonConfig::default().limit(MAX_UPLOAD_SIZE))
|
||||
.app_data(web::Data::new(config.clone()))
|
||||
.app_data(web::Data::new(db_pool.clone()))
|
||||
.service(actix_files::Files::new(
|
||||
"/media",
|
||||
config.media_dir(),
|
||||
|
|
|
@ -112,8 +112,8 @@ pub async fn create_account(
|
|||
}
|
||||
// Generate RSA private key for actor
|
||||
let private_key = match web::block(generate_private_key).await {
|
||||
Ok(private_key) => private_key,
|
||||
Err(_) => return Err(HttpError::InternalError),
|
||||
Ok(Ok(private_key)) => private_key,
|
||||
_ => return Err(HttpError::InternalError),
|
||||
};
|
||||
let private_key_pem = serialize_private_key(private_key)
|
||||
.map_err(|_| HttpError::InternalError)?;
|
||||
|
|
|
@ -44,10 +44,10 @@ async fn get_notifications_view(
|
|||
let response = if let Some(item) = notifications.get(max_index) {
|
||||
let pagination_header = get_pagination_header(&config.instance_url(), &item.id);
|
||||
HttpResponse::Ok()
|
||||
.header("Link", pagination_header)
|
||||
.append_header(("Link", pagination_header))
|
||||
// Link header needs to be exposed
|
||||
// https://github.com/actix/actix-extras/issues/192
|
||||
.header("Access-Control-Expose-Headers", "Link")
|
||||
.append_header(("Access-Control-Expose-Headers", "Link"))
|
||||
.json(notifications)
|
||||
} else {
|
||||
HttpResponse::Ok().json(notifications)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use actix_web::{
|
||||
body::{Body, BodySize, MessageBody, ResponseBody},
|
||||
body::{BodySize, BoxBody, MessageBody},
|
||||
dev::ServiceResponse,
|
||||
http::StatusCode,
|
||||
middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers},
|
||||
middleware::{ErrorHandlerResponse, ErrorHandlers},
|
||||
};
|
||||
use actix_web::dev::ServiceResponse;
|
||||
use serde_json::json;
|
||||
use tokio_postgres::GenericClient;
|
||||
|
||||
|
@ -27,22 +27,20 @@ pub async fn get_current_user(
|
|||
}
|
||||
|
||||
/// Error handler for 401 Unauthorized
|
||||
pub fn create_auth_error_handler<B: MessageBody>() -> ErrorHandlers<B> {
|
||||
pub fn create_auth_error_handler<B: MessageBody + 'static>() -> ErrorHandlers<B> {
|
||||
ErrorHandlers::new()
|
||||
.handler(StatusCode::UNAUTHORIZED, |mut response: ServiceResponse<B>| {
|
||||
response = response.map_body(|_, body| {
|
||||
if let ResponseBody::Body(data) = &body {
|
||||
if let BodySize::Empty = data.size() {
|
||||
.handler(StatusCode::UNAUTHORIZED, |response: ServiceResponse<B>| {
|
||||
let response_new = response.map_body(|_, body| {
|
||||
if let BodySize::None | BodySize::Sized(0) = body.size() {
|
||||
// Insert error description if response body is empty
|
||||
// https://github.com/actix/actix-extras/issues/156
|
||||
let error_data = json!({
|
||||
"message": "auth header is not present",
|
||||
});
|
||||
return ResponseBody::Body(Body::from(error_data)).into_body();
|
||||
}
|
||||
}
|
||||
body
|
||||
return BoxBody::new(error_data.to_string());
|
||||
};
|
||||
body.boxed()
|
||||
});
|
||||
Ok(ErrorHandlerResponse::Response(response))
|
||||
Ok(ErrorHandlerResponse::Response(response_new.map_into_right_body()))
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue