Skip to content

Commit

Permalink
Merge #175: Axum API scaffolding
Browse files Browse the repository at this point in the history
d08f70e refactor(api): [#174] Axum API scaffolding (Jose Celano)
7bcf20e feat: disable sqlx logging for all statements (Jose Celano)
7347fee feat(api): [#174] new cargo dependencies: axum, hyper (Jose Celano)

Pull request description:

  Basic changes which are needed to run the Axum API implementation in parallel with the current one with ActixWeb. For the time being the Axum implementation will be only used for testing until all endpoints are migrated.

Top commit has no ACKs.

Tree-SHA512: 6d0b8ed20329e91ba92bf5d78caf366b1fb61c2048040154b68da876878cd73f5de372be0955c492b82f307cbe8786d702ce86dbfa201900d6d98ea1913ba85b
  • Loading branch information
josecelano committed Jun 8, 2023
2 parents ba1c37c + d08f70e commit a47c99b
Show file tree
Hide file tree
Showing 25 changed files with 523 additions and 101 deletions.
100 changes: 100 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ text-to-png = "0.2"
indexmap = "1.9"
thiserror = "1.0"
binascii = "0.1"
axum = "0.6.18"
hyper = "0.14.26"

[dev-dependencies]
rand = "0.8"
Expand Down
45 changes: 13 additions & 32 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use std::net::SocketAddr;
use std::sync::Arc;

use actix_cors::Cors;
use actix_web::dev::Server;
use actix_web::{middleware, web, App, HttpServer};
use log::info;
use tokio::task::JoinHandle;

use crate::auth::Authentication;
use crate::bootstrap::logging;
Expand All @@ -21,16 +18,18 @@ use crate::services::torrent::{
use crate::services::user::{self, DbBannedUserList, DbUserProfileRepository, DbUserRepository};
use crate::services::{proxy, settings, torrent};
use crate::tracker::statistics_importer::StatisticsImporter;
use crate::{mailer, routes, tracker};
use crate::web::api::{start, Implementation};
use crate::{mailer, tracker};

pub struct Running {
pub api_server: Server,
pub socket_address: SocketAddr,
pub api_socket_addr: SocketAddr,
pub actix_web_api_server: Option<JoinHandle<std::result::Result<(), std::io::Error>>>,
pub axum_api_server: Option<JoinHandle<std::result::Result<(), std::io::Error>>>,
pub tracker_data_importer_handle: tokio::task::JoinHandle<()>,
}

#[allow(clippy::too_many_lines)]
pub async fn run(configuration: Configuration) -> Running {
pub async fn run(configuration: Configuration, api_implementation: &Implementation) -> Running {
logging::setup();

let configuration = Arc::new(configuration);
Expand All @@ -42,6 +41,7 @@ pub async fn run(configuration: Configuration) -> Running {

let database_connect_url = settings.database.connect_url.clone();
let torrent_info_update_interval = settings.tracker_statistics_importer.torrent_info_update_interval;
let net_ip = "0.0.0.0".to_string();
let net_port = settings.net.port;

// IMPORTANT: drop settings before starting server to avoid read locks that
Expand Down Expand Up @@ -155,33 +155,14 @@ pub async fn run(configuration: Configuration) -> Running {
}
});

// Start main API server
// Start API server

// todo: get IP from settings
let ip = "0.0.0.0".to_string();

let server = HttpServer::new(move || {
App::new()
.wrap(Cors::permissive())
.app_data(web::Data::new(app_data.clone()))
.wrap(middleware::Logger::default())
.configure(routes::init)
})
.bind((ip, net_port))
.expect("can't bind server to socket address");

let socket_address = server.addrs()[0];

let running_server = server.run();

let starting_message = format!("Listening on http://{socket_address}");
info!("{}", starting_message);
// Logging could be disabled or redirected to file. So print to stdout too.
println!("{starting_message}");
let running_api = start(app_data, &net_ip, net_port, api_implementation).await;

Running {
api_server: running_server,
socket_address,
api_socket_addr: running_api.socket_addr,
actix_web_api_server: running_api.actix_web_api_server,
axum_api_server: running_api.axum_api_server,
tracker_data_importer_handle: tracker_statistics_importer_handle,
}
}
16 changes: 13 additions & 3 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
use torrust_index_backend::app;
use torrust_index_backend::bootstrap::config::init_configuration;
use torrust_index_backend::web::api::Implementation;

#[actix_web::main]
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
let configuration = init_configuration().await;

let app = app::run(configuration).await;
// todo: we are migrating from actix-web to axum, so we need to keep both
// implementations for a while. For production we only use ActixWeb.
// Once the Axum implementation is finished and stable, we can switch to it
// and remove the ActixWeb implementation.
let api_implementation = Implementation::ActixWeb;

app.api_server.await
let app = app::run(configuration, &api_implementation).await;

match api_implementation {
Implementation::ActixWeb => app.actix_web_api_server.unwrap().await.expect("the API server was dropped"),
Implementation::Axum => app.axum_api_server.unwrap().await.expect("the Axum API server was dropped"),
}
}
2 changes: 1 addition & 1 deletion src/bootstrap/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub fn setup() {

fn config_level_or_default(log_level: &Option<String>) -> LevelFilter {
match log_level {
None => log::LevelFilter::Warn,
None => log::LevelFilter::Info,
Some(level) => LevelFilter::from_str(level).unwrap(),
}
}
Expand Down
14 changes: 11 additions & 3 deletions src/databases/mysql.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::str::FromStr;
use std::time::Duration;

use async_trait::async_trait;
use chrono::NaiveDateTime;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::{query, query_as, Acquire, MySqlPool};
use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions};
use sqlx::{query, query_as, Acquire, ConnectOptions, MySqlPool};

use crate::databases::database;
use crate::databases::database::{Category, Database, Driver, Sorting, TorrentCompact};
Expand All @@ -25,8 +28,13 @@ impl Database for Mysql {
}

async fn new(database_url: &str) -> Self {
let mut connection_options = MySqlConnectOptions::from_str(database_url).expect("Unable to create connection options.");
connection_options
.log_statements(log::LevelFilter::Error)
.log_slow_statements(log::LevelFilter::Warn, Duration::from_secs(1));

let db = MySqlPoolOptions::new()
.connect(database_url)
.connect_with(connection_options)
.await
.expect("Unable to create database pool.");

Expand Down
14 changes: 11 additions & 3 deletions src/databases/sqlite.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::str::FromStr;
use std::time::Duration;

use async_trait::async_trait;
use chrono::NaiveDateTime;
use sqlx::sqlite::SqlitePoolOptions;
use sqlx::{query, query_as, Acquire, SqlitePool};
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use sqlx::{query, query_as, Acquire, ConnectOptions, SqlitePool};

use crate::databases::database;
use crate::databases::database::{Category, Database, Driver, Sorting, TorrentCompact};
Expand All @@ -25,8 +28,13 @@ impl Database for Sqlite {
}

async fn new(database_url: &str) -> Self {
let mut connection_options = SqliteConnectOptions::from_str(database_url).expect("Unable to create connection options.");
connection_options
.log_statements(log::LevelFilter::Error)
.log_slow_statements(log::LevelFilter::Warn, Duration::from_secs(1));

let db = SqlitePoolOptions::new()
.connect(database_url)
.connect_with(connection_options)
.await
.expect("Unable to create database pool.");

Expand Down
5 changes: 5 additions & 0 deletions src/services/about.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ use crate::routes::API_VERSION;

#[must_use]
pub fn index_page() -> String {
page()
}

#[must_use]
pub fn page() -> String {
format!(
r#"
<html>
Expand Down
Loading

0 comments on commit a47c99b

Please sign in to comment.