Skip to content

Commit

Permalink
feat(axum): Switched to axum with e2e typesafety
Browse files Browse the repository at this point in the history
* Started migration to axum

* Added lock file

* Started migration to axum

* feat(cargo): continued mig to axum

* feat(cargo): continued mig to axum

* feat(cargo): continued mig to axum

* Fixed all errors

* Working and starting server

* Working and starting server

* Fixed podcast

* Fixed gpodder

* Continue unifying frontend and backend

* Continued removing errors in fe

* Continued removing errors in fe

* Frontend starting and working

* Fixed for more state in ui

* Fixed auth not working

* Added socketio support

* Added ui config, decoupled tests

* Added api tests for notification handler

* Fixed tests

* Added cleanup of old paniced containers

* Added also on remove

* Added notification controller

* Fixed invalid operation

* Fixed rss feeds

* Fixed opml download

* Fixed itunes and podindex request

* fixed opml and itunes

* Rebased
  • Loading branch information
SamTV12345 authored Feb 4, 2025
1 parent 1140115 commit 82a58ac
Show file tree
Hide file tree
Showing 138 changed files with 8,468 additions and 5,058 deletions.
1,342 changes: 615 additions & 727 deletions Cargo.lock

Large diffs are not rendered by default.

29 changes: 20 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,15 @@ postgresql = ["diesel/postgres", "diesel_migrations/postgres", "diesel/chrono",
sqlite = ["diesel/sqlite", "diesel_migrations/sqlite", "libsqlite3-sys", "diesel/returning_clauses_for_sqlite_3_35"]

[dependencies]
awc = {version="3.5.1", features = ["rustls"]}
rpassword = "7.3.1"
reqwest = { version = "0.12.11", features = ["stream", "json","blocking"] }
tokio-stream = { version = "0.1.17", features = ["sync"] }
actix = "0.13.5"
async-recursion = "1.1.1"
base64 = "0.22.1"
uuid = {version="1.11.1", features = ["v4", "serde"]}
libsqlite3-sys = {version = "0.30.1", features = ["bundled"], optional = true}
r2d2_postgres = {version = "0.18.2", optional = true}
diesel_migrations = "2.2.0"
actix-files = "0.6.6"
actix-web = {version="4.9.0", features=["rustls", "http2"]}
jsonwebtoken = {version="9.3.0"}
log = "0.4.22"
futures-util = "0.3.31"
Expand All @@ -38,15 +34,14 @@ rand = "0.8.5"
env_logger = "0.11.6"
chrono = {version = "0.4.39", default-features=false, features = ["serde"]}
rss = "2.0.11"
actix-ws = "0.3.0"
frankenstein = "0.38.0"
regex = "1.11.0"
xml-builder = "0.5.2"
diesel = { version = "2.2.6", features = ["chrono", "r2d2"] }
r2d2 = "0.8.10"
utoipa = { version = "5.3.1", features = ["actix_extras", "chrono"] }
utoipa = { version = "5.3.1", features = ["chrono", "axum_extras"] }
futures = "0.3.31"
utoipa-swagger-ui = {version = "9.0.0", features = ["actix-web"] }
utoipa-swagger-ui = {version = "9.0.0", features = ["axum"] }
clokwerk= "0.4.0"
tokio = {version = "1.43.0", features = ["full"]}
serde = "1.0.217"
Expand All @@ -63,19 +58,35 @@ urlencoding="2.1.3"
id3 = "1.16.0"
mp4ameta = "0.11.0"
file-format = "0.26.0"
maud = { version = "*", features = ["actix-web"] }
maud = { version = "*", features = ["axum","axum-core"] }
url = "2.5.4"
rust-s3 = { version = "0.35.1", features = ["blocking", "fail-on-err"] }
rust-s3 = { version = "0.36.0-beta.2", features = ["blocking", "fail-on-err", "futures", "tokio", "tokio-rustls-tls"], default-features = false }
async-trait = "0.1.85"
axum = { version = "0.8.1", features = ["macros","http2"] }
tower-http = { version = "0.6.1", features = ["fs"] }
tower = { version = "0.5.2", features = ["util"] }
utoipa-axum = { version = "0.2.0" }
utoipa-rapidoc = { version = "6.0.0",features = ["axum"] }
utoipa-redoc = { version = "6.0.0", features = ["axum"] }
utoipa-scalar = { version = "0.3.0", features = ["axum"] }
axum-extra={version = "0.10.0", features = ["cookie", "query"]}
axum-test = "17.1.0"
socketioxide = "0.16.0"
mime_guess = "2.0.5"

[target.'cfg(not(windows))'.dependencies]
openssl = "0.10.68"


[dev-dependencies]
serial_test = {version="3.2.0"}
testcontainers = { version = "0.23.1" }
testcontainers-modules = { version = "0.11.5", features = ["postgres","blocking"] }
ctor = "0.2.9"
derive_builder = {version = "0.20.2"}
fake = { version = "3.1.0", features = ["chrono"] }
bollard = {version = "*"}


[profile.release]
debug = true
Expand Down
63 changes: 0 additions & 63 deletions src/adapters/api/controllers/device_controller.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/adapters/api/controllers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
mod device_controller;
pub mod routes;
94 changes: 34 additions & 60 deletions src/adapters/api/controllers/routes.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,46 @@
use crate::adapters::api::controllers::device_controller::{get_devices_of_user, post_device};
use axum::middleware::from_fn;
use utoipa_axum::router::OpenApiRouter;
use utoipa_axum::routes;
use crate::commands::startup::get_api_config;
use crate::constants::inner_constants::ENVIRONMENT_SERVICE;
use crate::controllers::api_doc::ApiDoc;
use crate::controllers::file_hosting::get_podcast_serving;
use crate::controllers::manifest_controller::get_manifest;
use crate::controllers::podcast_controller::proxy_podcast;
use crate::controllers::websocket_controller::{
get_rss_feed, get_rss_feed_for_podcast, start_connection,
};
use crate::gpodder::auth::authentication::login;
use crate::gpodder::parametrization::get_client_parametrization;
use crate::gpodder::subscription::subscriptions::{get_subscriptions, get_subscriptions_all, upload_subscription_changes};
use crate::{get_api_config, get_ui_config};
use actix_web::body::{BoxBody, EitherBody};
use actix_web::dev::{ServiceFactory, ServiceRequest, ServiceResponse};
use actix_web::web::redirect;
use actix_web::{web, Error, Scope};
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
use crate::gpodder::parametrization::{get_client_parametrization_router};
use crate::gpodder::device::device_controller::get_device_router;
use crate::gpodder::episodes::gpodder_episodes::get_gpodder_episodes_router;
use crate::gpodder::session_middleware::handle_cookie_session;
use crate::gpodder::subscription::subscriptions::get_subscription_router;

pub fn global_routes() -> Scope {
pub fn global_routes() -> OpenApiRouter {
let base_path = ENVIRONMENT_SERVICE
.sub_directory
.clone()
.unwrap_or("/".to_string());
let openapi = ApiDoc::openapi();
let service = get_api_config();

web::scope(&base_path)
.service(get_client_parametrization)
.service(proxy_podcast)
.service(get_ui_config())
.service(get_podcast_serving())
.service(redirect("/swagger-ui", "/swagger-ui/"))
.service(SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-doc/openapi.json", openapi))
.service(redirect("/", "./ui/"))
.service(service)
.service(start_connection)
.service(get_rss_feed)
.service(get_manifest)
.service(get_rss_feed_for_podcast)
}
let mut router = match base_path.is_empty() {
true=>{
OpenApiRouter::new()
.merge(get_client_parametrization_router())
.merge(service)
}
false=>{
OpenApiRouter::new()
.nest(&base_path, OpenApiRouter::new()
.merge(get_client_parametrization_router())
.merge(service))
}
};

pub fn get_gpodder_api() -> Scope {
if ENVIRONMENT_SERVICE.gpodder_integration_enabled {
web::scope("/api/2")
.service(login)
.service(get_authenticated_gpodder())
} else {
web::scope("/api/2")
use crate::gpodder::auth::authentication::__path_login;
router = router
.routes(routes!(login))
.nest("/api/2",OpenApiRouter::new()
.merge(get_subscription_router())
.merge(get_device_router())
.merge(get_gpodder_episodes_router())
.layer(from_fn(handle_cookie_session))
);
}
}

fn get_authenticated_gpodder() -> Scope<
impl ServiceFactory<
ServiceRequest,
Config = (),
Response = ServiceResponse<EitherBody<BoxBody>>,
Error = Error,
InitError = (),
>,
> {
web::scope("")
.wrap(crate::gpodder::session_middleware::CookieFilter::new())
.service(post_device)
.service(get_devices_of_user)
.service(get_subscriptions)
.service(get_subscriptions_all)
.service(upload_subscription_changes)
.service(crate::gpodder::episodes::gpodder_episodes::get_episode_actions)
.service(crate::gpodder::episodes::gpodder_episodes::upload_episode_actions)
}
router
}
3 changes: 2 additions & 1 deletion src/adapters/api/models/device/device_response.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use utoipa::ToSchema;
use crate::domain::models::device::model::Device;

#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, ToSchema)]
pub struct DeviceResponse {
id: String,
caption: String,
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/file/file_handle_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl FileHandleWrapper {
path: &'a str,
content: &'a mut [u8],
download_location: &FileHandlerType,
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + 'a>> {
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + Send + 'a>> {
match download_location {
FileHandlerType::Local => LocalFileHandler::write_file_async(path, content),
FileHandlerType::S3 => S3Handler::write_file_async(path, content),
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/file/file_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub trait FileHandler: Sync + Send {
fn write_file_async<'a>(
path: &'a str,
content: &'a mut [u8],
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + 'a>>;
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + Send + 'a>>;
fn create_dir(path: &str) -> Result<(), CustomError>;
fn path_exists(path: &str, req: FileRequest) -> bool;
fn remove_dir(path: &str) -> Result<(), CustomError>;
Expand Down
4 changes: 2 additions & 2 deletions src/adapters/file/local_file_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl FileHandler for LocalFileHandler {
fn write_file_async<'a>(
path: &'a str,
content: &'a mut [u8],
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + 'a>> {
Box::pin(async { LocalFileHandler::write_file(path, content) })
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + Send + 'a>> {
Box::pin(async move { LocalFileHandler::write_file(path, content) })
}
}
2 changes: 1 addition & 1 deletion src/adapters/file/s3_file_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl FileHandler for S3Handler {
fn write_file_async<'a>(
path: &'a str,
content: &'a mut [u8],
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + 'a>> {
) -> Pin<Box<dyn Future<Output = Result<(), CustomError>> + Send + 'a>> {
Box::pin(async {
Self::handle_write_async(&Self::prepare_path_resolution(path), content).await
})
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/persistence/dbconfig/db.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::adapters::persistence::dbconfig::DBType;
use crate::constants::inner_constants::ENVIRONMENT_SERVICE;
use crate::DbPool;
use diesel::r2d2::ConnectionManager;
use diesel::Connection;
use r2d2::Pool;
use std::process::exit;
use std::sync::OnceLock;
use std::time::Duration;
use crate::commands::startup::DbPool;

#[derive(Debug)]
pub struct ConnectionOptions {
Expand Down
Loading

0 comments on commit 82a58ac

Please sign in to comment.