From ac5e7d327559628728ee1d9515b9bc07f8df9064 Mon Sep 17 00:00:00 2001 From: Dotan Nahum Date: Tue, 22 Oct 2024 16:09:09 +0300 Subject: [PATCH] tidy: move extras to loco-org --- Cargo.toml | 2 +- examples/demo/Cargo.toml | 4 +- examples/demo/src/app.rs | 8 -- loco-extras/Cargo.toml | 70 ----------- loco-extras/README.md | 10 -- loco-extras/src/initializers/extra_db.rs | 30 ----- loco-extras/src/initializers/mod.rs | 73 ------------ .../src/initializers/mongodb/README.md | 106 ----------------- loco-extras/src/initializers/mongodb/mod.rs | 110 ------------------ loco-extras/src/initializers/multi_db.rs | 28 ----- .../src/initializers/normalize_path.rs | 36 ------ .../src/initializers/opentelemetry/README.md | 11 -- .../src/initializers/opentelemetry/mod.rs | 32 ----- loco-extras/src/initializers/prometheus.rs | 21 ---- loco-extras/src/lib.rs | 14 --- 15 files changed, 4 insertions(+), 551 deletions(-) delete mode 100644 loco-extras/Cargo.toml delete mode 100644 loco-extras/README.md delete mode 100644 loco-extras/src/initializers/extra_db.rs delete mode 100644 loco-extras/src/initializers/mod.rs delete mode 100644 loco-extras/src/initializers/mongodb/README.md delete mode 100644 loco-extras/src/initializers/mongodb/mod.rs delete mode 100644 loco-extras/src/initializers/multi_db.rs delete mode 100644 loco-extras/src/initializers/normalize_path.rs delete mode 100644 loco-extras/src/initializers/opentelemetry/README.md delete mode 100644 loco-extras/src/initializers/opentelemetry/mod.rs delete mode 100644 loco-extras/src/initializers/prometheus.rs delete mode 100644 loco-extras/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 00ce87c4d..774f4c958 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["xtask", "loco-extras", "loco-gen"] +members = ["xtask", "loco-gen"] exclude = ["starters"] [workspace.package] diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml index 71aa9b99b..dc91e7d50 100644 --- a/examples/demo/Cargo.toml +++ b/examples/demo/Cargo.toml @@ -12,7 +12,9 @@ default-run = "demo_app-cli" [dependencies] loco-rs = { path = "../../", version = "*" } -loco-extras = { version = "*", path = "../../loco-extras", features = ["full"] } +loco-extras = { version = "*", path = "../../../loco-extras", features = [ + "full", +] } migration = { path = "migration" } serde = { version = "1", features = ["derive"] } diff --git a/examples/demo/src/app.rs b/examples/demo/src/app.rs index f625e6902..b2ba52f48 100644 --- a/examples/demo/src/app.rs +++ b/examples/demo/src/app.rs @@ -1,7 +1,6 @@ use std::path::Path; use async_trait::async_trait; -use loco_extras; use loco_rs::{ app::{AppContext, Hooks, Initializer}, boot::{create_app, BootResult, StartMode}, @@ -48,15 +47,8 @@ impl Hooks for App { Box::new(initializers::axum_session::AxumSessionInitializer), Box::new(initializers::view_engine::ViewEngineInitializer), Box::new(initializers::hello_view_engine::HelloViewEngineInitializer), - Box::new(loco_extras::initializers::normalize_path::NormalizePathInitializer), ]; - if ctx.environment != Environment::Test { - initializers.push(Box::new( - loco_extras::initializers::prometheus::AxumPrometheusInitializer, - )); - } - Ok(initializers) } // diff --git a/loco-extras/Cargo.toml b/loco-extras/Cargo.toml deleted file mode 100644 index 350c13cb8..000000000 --- a/loco-extras/Cargo.toml +++ /dev/null @@ -1,70 +0,0 @@ -[package] -name = "loco-extras" -version = "0.4.0" -description = "Common loco components" -license.workspace = true -edition.workspace = true -rust-version.workspace = true - -[lib] -path = "src/lib.rs" - -[dependencies] -async-trait = { workspace = true } -axum = { workspace = true } -# initializer -axum-prometheus = { version = "0.6.1", optional = true } -serde = { version = "1", optional = true } -serde_json = { version = "1", optional = true } -tower = { workspace = true, optional = true } -tower-http = { workspace = true, optional = true, features = [ - "normalize-path", -] } -opentelemetry = { version = "0.22", optional = true } -opentelemetry-otlp = { version = "0.15", optional = true, features = [ - "grpc-tonic", -] } -axum-tracing-opentelemetry = { version = "0.18", optional = true } -init-tracing-opentelemetry = { version = "0.18", optional = true, features = [ - "otlp", - "tracing_subscriber_ext", -] } -tracing-opentelemetry-instrumentation-sdk = { version = "0.18", optional = true } -tracing-subscriber = { version = "0.3.18", optional = true, features = [ - "env-filter", - "json", -] } -tracing = { version = "0.1.40", optional = true } -mongodb = { version = "2.8.0", optional = true } - -[dependencies.loco-rs] -path = "../" -version = "*" -default-features = true -features = ["with-db", "auth_jwt"] - -[features] -default = ["full"] -full = [ - "initializer-prometheus", - "initializer-extra-db", - "initializer-multi-db", - "initializer-normalize-path", - "initializer-opentelemetry", - "initializer-mongodb", -] - -initializer-prometheus = ["dep:axum-prometheus"] -initializer-extra-db = [] -initializer-multi-db = ["dep:serde_json"] -initializer-normalize-path = ["dep:tower", "dep:tower-http"] -initializer-opentelemetry = [ - "dep:opentelemetry", - "dep:opentelemetry-otlp", - "dep:axum-tracing-opentelemetry", - "dep:init-tracing-opentelemetry", - "dep:tracing-opentelemetry-instrumentation-sdk", - "dep:tracing-subscriber", - "dep:tracing", -] -initializer-mongodb = ["dep:mongodb", "dep:serde", "dep:serde_json"] diff --git a/loco-extras/README.md b/loco-extras/README.md deleted file mode 100644 index 5cd87b3d9..000000000 --- a/loco-extras/README.md +++ /dev/null @@ -1,10 +0,0 @@ - -![Loco.rs](https://github.com/loco-rs/loco/assets/83390/992d215a-3cd3-42ee-a1c7-de9fd25a5bac) - -# Loco Extras - -https://loco.rs - - -Loco extras contains a list of common implementation that are generally useful when working with [Loco](https://loco.rs/). - diff --git a/loco-extras/src/initializers/extra_db.rs b/loco-extras/src/initializers/extra_db.rs deleted file mode 100644 index 95c67cf7c..000000000 --- a/loco-extras/src/initializers/extra_db.rs +++ /dev/null @@ -1,30 +0,0 @@ -use async_trait::async_trait; -use axum::{Extension, Router as AxumRouter}; -use loco_rs::{db, prelude::*}; - -#[allow(clippy::module_name_repetitions)] -pub struct ExtraDbInitializer; - -#[async_trait] -impl Initializer for ExtraDbInitializer { - fn name(&self) -> String { - "extra-db".to_string() - } - - async fn after_routes(&self, router: AxumRouter, ctx: &AppContext) -> Result { - let extra_db_config = ctx - .config - .initializers - .clone() - .ok_or_else(|| Error::Message("initializers config not configured".to_string()))?; - - let extra_db_value = extra_db_config - .get("extra_db") - .ok_or_else(|| Error::Message("initializers config not configured".to_string()))?; - - let extra_db = serde_json::from_value(extra_db_value.clone())?; - - let db = db::connect(&extra_db).await?; - Ok(router.layer(Extension(db))) - } -} diff --git a/loco-extras/src/initializers/mod.rs b/loco-extras/src/initializers/mod.rs deleted file mode 100644 index 91d28a4ac..000000000 --- a/loco-extras/src/initializers/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Initializers -//! -//! Initializers are a way to encapsulate a piece of infrastructure "wiring" -//! that you need to do in your app. read more [here](https://loco.rs/docs/the-app/initializers/) -//! -//! ### How To Use -//! -//! To integrate `loco-extras` into your project, add the following line to your -//! `Cargo.toml` file: -//! -//! ```toml -//! loco-extras = { version = "*", features = ["FEATURE"] } -//! ``` -//! -//! After adding the crate to your project, navigate to the application hooks in -//! `app.rs` and include the `loco_extras` crate: -//! -//! ```rust -//! use loco_extras; -//! ``` -//! -//! Once the `loco_extras` crate is included, proceed to the `initializers` hook -//! function and add your initializations. Here's an example: -//! -//! ```rust,ignore -//! impl Hooks for App { -//! . -//! . -//! . -//! async fn initializers(_ctx: &AppContext) -> Result>> { -//! Ok(vec![ -//! Box::new(loco_extras::initializers::[MODULE_NAME]), -//! ]) -//! } -//! } -//! ``` -//! -//! ### Customization -//! -//! The extras initializers are intentionally not designed for extensive -//! modifications. The concept is to use them as-is without complexity. If you -//! need to customize the initializers, copy the relevant file from the -//! `loco_extras` project into your app, adapt it to your requirements, and -//! update the hook to reference the new source. -//! -//! ### Prometheus: -//!```rust -#![doc = include_str!("././prometheus.rs")] -//!```` -//! ### Extra Database connection: -//! ```rust -#![doc = include_str!("././extra_db.rs")] -//!```` -//! ### Extra Multiple Database Connections: -//! ```rust -#![doc = include_str!("././multi_db.rs")] -//!```` -//! ### Normalize path: -//! ```rust -#![doc = include_str!("././normalize_path.rs")] -//!```` -#[cfg(feature = "initializer-extra-db")] -pub mod extra_db; -#[cfg(feature = "initializer-mongodb")] -pub mod mongodb; -#[cfg(feature = "initializer-multi-db")] -pub mod multi_db; -#[cfg(feature = "initializer-normalize-path")] -pub mod normalize_path; -#[cfg(feature = "initializer-opentelemetry")] -pub mod opentelemetry; -#[cfg(feature = "initializer-prometheus")] -pub mod prometheus; diff --git a/loco-extras/src/initializers/mongodb/README.md b/loco-extras/src/initializers/mongodb/README.md deleted file mode 100644 index f5eaa7add..000000000 --- a/loco-extras/src/initializers/mongodb/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# This Initializer adds support for connection to a MongoDB database - -There is extra functionality that loco supports through the `loco_extras` crate. Each extra can be pulled in optionally and is intgerated into your loco app by adding them as intializers. - -This initializer adds support for using a MongoDB database. Choosing to use Mongo would mean sacrificing a lot of the features that loco provides out of the box, such as user authentication, but it can still be used quite effectively as loco will help with a lot of the boilerplate code. - -This initializer is recommended to be used with the base starter that does not come with a database connection (as those all use SQL), but it can be used with any other starter as well. - -## Steps - -To add this initializer to your project, follow these steps: - -### Add Dependencies - -Add the `mongodb` crate and mongodb initializer to your loco project. - -```toml -# Cargo.toml -[dependencies] -loco-extras = { version = "*", features = ["mongodb"] } -mongodb = { version = "2.8.0"} -``` - -### Add to the Config - -Add a mongodb connection section to you config.yaml file. - -```yaml -# config/[development/test/production...].yaml -initializers: - mongodb: - uri: {{ get_env(name="MONGODB_URI", default="mongodb://localhost:27017/") }} - db_name: "db_name" - client_options: - connectTimeout: - secs: 2 - nanos: 0 - serverSelectionTimeout: - secs: 2 - nanos: 0 -``` - -Although untested, the `client_options` should be able to take any options that the mongodb driver supports. The options are passed as a `serde_json::Value`, so however that type is serialized/deserialized should work here. Example above shows how `Duration` is serialized. - - -### Add the Initializer - -Add the initializer to your `src/app.rs` file. - -```rust -// src/app.rs -pub struct App; -#[async_trait] -impl Hooks for App { - // Other code... - async fn initializers(ctx: &AppContext) -> Result>> { - let mut initializers: Vec> = vec![ - Box::new(loco_extras::initializers::mongodb::MongoDbInitializer), - ]; - - Ok(initializers) - } - // Other code... -} -``` - -### Using the Connection - -Now you can use the connection in your handler code. - -```rust -// src/controllers/mongo.rs -use axum::Extension; -use loco_rs::prelude::*; -use serde_json::Value; -use mongodb::{bson::doc, Database}; - -pub async fn fetch(Extension(mongodb): Extension) -> Result { - let user: Option = mongodb.collection("users").find_one(doc!{}, None).await.map_err(|_| Error::NotFound)?; - format::json(user.ok_or_else(|| Error::NotFound)?) -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("mongo") - .add("/", get(fetch)) -} -``` - -If you are adding a new file, don't forget to add it to the `src/controllers/mod.rs` file. - -### Adding to the Router - -If you created a new controller, you need to register the routes in your `src/app.rs` file. - -```rust -// src/app.rs - -fn routes(ctx: &AppContext) -> AppRoutes { - AppRoutes::with_default_routes() - // Other routes... - .add_route(controllers::mongodb::routes()) -} -``` - -Now you can run the server with the config information set OR set the `MONGODB_URI` environment variable. diff --git a/loco-extras/src/initializers/mongodb/mod.rs b/loco-extras/src/initializers/mongodb/mod.rs deleted file mode 100644 index 0c9176565..000000000 --- a/loco-extras/src/initializers/mongodb/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -use async_trait::async_trait; -use axum::{Extension, Router as AxumRouter}; -use loco_rs::prelude::*; -use mongodb::{bson::doc, options::ClientOptions, Client, Database}; - -#[allow(clippy::module_name_repetitions)] -pub struct MongoDbInitializer; - -#[async_trait] -impl Initializer for MongoDbInitializer { - fn name(&self) -> String { - "mongodb".to_string() - } - - async fn after_routes(&self, router: AxumRouter, ctx: &AppContext) -> Result { - let mongo_db_config = ctx - .config - .initializers - .clone() - .ok_or_else(|| Error::Message("initializers config not configured".to_string()))?; - - let mongo_db_value = mongo_db_config - .get("mongodb") - .ok_or_else(|| Error::Message("mongo not configured as initializer".to_string()))?; - - let mongo_db: MongoDbConfig = serde_json::from_value(mongo_db_value.clone()) - .map_err(|e| Error::Message(e.to_string()))?; - - let db = connect_to_db(mongo_db).await?; - - Ok(router.layer(Extension(db))) - } -} - -#[derive(Debug, Clone, serde::Deserialize)] -struct MongoDbConfig { - uri: String, - db_name: String, - client_options: Option, -} - -async fn connect_to_db(config: MongoDbConfig) -> Result { - let mut client_options = ClientOptions::parse_async(&config.uri) - .await - .map_err(|e| Error::Message(e.to_string()))?; - - let client_options = merge_config_with_client(&mut client_options, config.clone()); - - let client = Client::with_options(client_options).map_err(|e| Error::Message(e.to_string()))?; - - let db = client.database(config.db_name.as_ref()); - - // Ping the Database to make sure a connection has been made - db.run_command(doc! { "ping": 1 }, None) - .await - .map_err(|e| Error::Message(e.to_string()))?; - - Ok(db) -} - -fn merge_config_with_client(co: &mut ClientOptions, config: MongoDbConfig) -> ClientOptions { - match config.client_options { - None => co.clone(), - Some(client_options) => { - co.app_name = client_options.app_name.or(co.app_name.clone()); - co.compressors = client_options.compressors.or(co.compressors.clone()); - co.cmap_event_handler = client_options - .cmap_event_handler - .or(co.cmap_event_handler.clone()); - co.command_event_handler = client_options - .command_event_handler - .or(co.command_event_handler.clone()); - co.connect_timeout = client_options.connect_timeout.or(co.connect_timeout); - co.credential = client_options.credential.or(co.credential.clone()); - co.direct_connection = client_options.direct_connection.or(co.direct_connection); - co.driver_info = client_options.driver_info.or(co.driver_info.clone()); - co.heartbeat_freq = client_options.heartbeat_freq.or(co.heartbeat_freq); - co.load_balanced = client_options.load_balanced.or(co.load_balanced); - co.local_threshold = client_options.local_threshold.or(co.local_threshold); - co.max_idle_time = client_options.max_idle_time.or(co.max_idle_time); - co.max_pool_size = client_options.max_pool_size.or(co.max_pool_size); - co.min_pool_size = client_options.min_pool_size.or(co.min_pool_size); - co.max_connecting = client_options.max_connecting.or(co.max_connecting); - co.read_concern = client_options.read_concern.or(co.read_concern.clone()); - co.repl_set_name = client_options.repl_set_name.or(co.repl_set_name.clone()); - co.retry_reads = client_options.retry_reads.or(co.retry_reads); - co.retry_writes = client_options.retry_writes.or(co.retry_writes); - co.sdam_event_handler = client_options - .sdam_event_handler - .or(co.sdam_event_handler.clone()); - co.selection_criteria = client_options - .selection_criteria - .or(co.selection_criteria.clone()); - co.server_api = client_options.server_api.or(co.server_api.clone()); - co.server_selection_timeout = client_options - .server_selection_timeout - .or(co.server_selection_timeout); - co.default_database = client_options - .default_database - .or(co.default_database.clone()); - co.tls = client_options.tls.or(co.tls.clone()); - // co.tracing_max_document_length_bytes = - // client_options.tracing_max_document_length_bytes; - co.write_concern = client_options.write_concern.or(co.write_concern.clone()); - co.srv_max_hosts = client_options.srv_max_hosts.or(co.srv_max_hosts); - - co.clone() - } - } -} diff --git a/loco-extras/src/initializers/multi_db.rs b/loco-extras/src/initializers/multi_db.rs deleted file mode 100644 index 6c4cffbe3..000000000 --- a/loco-extras/src/initializers/multi_db.rs +++ /dev/null @@ -1,28 +0,0 @@ -use async_trait::async_trait; -use axum::{Extension, Router as AxumRouter}; -use loco_rs::{db, errors::Error, prelude::*}; - -#[allow(clippy::module_name_repetitions)] -pub struct MultiDbInitializer; - -#[async_trait] -impl Initializer for MultiDbInitializer { - fn name(&self) -> String { - "multi-db".to_string() - } - - async fn after_routes(&self, router: AxumRouter, ctx: &AppContext) -> Result { - let settings = ctx - .config - .initializers - .clone() - .ok_or_else(|| Error::Message("settings config not configured".to_string()))?; - - let multi_db = settings - .get("multi_db") - .ok_or_else(|| Error::Message("multi_db not configured".to_string()))?; - - let multi_db = db::MultiDb::new(serde_json::from_value(multi_db.clone())?).await?; - Ok(router.layer(Extension(multi_db))) - } -} diff --git a/loco-extras/src/initializers/normalize_path.rs b/loco-extras/src/initializers/normalize_path.rs deleted file mode 100644 index 2c2ebd012..000000000 --- a/loco-extras/src/initializers/normalize_path.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! [Initializer] to add a [NormalizePathLayer] middleware to handle a trailing -//! `/` at the end of URIs. -//! -//! See the [layer's docs][normalize-docs] for more details. -//! -//! Note that the normal approach to adding middleware via [Router::layer] -//! results in the middleware running after routing has already occurred. This -//! means that any middleware that re-writes the request URI, including -//! [NormalizePathLayer], will not work as expected if added using -//! [Router::layer]. As a workaround, the middleware can be added by wrapping -//! the entire router. See [axum's docs][axum-docs] for more details and an -//! example. -//! -//! [normalize-docs]: https://docs.rs/tower-http/latest/tower_http/normalize_path/index.html -//! [axum-docs]: https://docs.rs/axum/latest/axum/middleware/index.html#rewriting-request-uri-in-middleware -use async_trait::async_trait; -use axum::Router; -use loco_rs::prelude::*; -use tower::Layer; -use tower_http::normalize_path::NormalizePathLayer; - -#[allow(clippy::module_name_repetitions)] -pub struct NormalizePathInitializer; - -#[async_trait] -impl Initializer for NormalizePathInitializer { - fn name(&self) -> String { - "normalize-path".to_string() - } - - async fn after_routes(&self, router: Router, _ctx: &AppContext) -> Result { - let router = NormalizePathLayer::trim_trailing_slash().layer(router); - let router = Router::new().nest_service("", router); - Ok(router) - } -} diff --git a/loco-extras/src/initializers/opentelemetry/README.md b/loco-extras/src/initializers/opentelemetry/README.md deleted file mode 100644 index 5d43d1084..000000000 --- a/loco-extras/src/initializers/opentelemetry/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Opentelemetry Initializer - -This initializer is responsible for initializing tracing with opentelemetry and adding it as a middleware in axum. - -Because opentelemetry tracing initializer is not compatible with loco's default tracing initialization we must turn off the default logging. - -```` -fn init_logger(_config: &config::Config, _env: &Environment) -> Result { - Ok(true) -} -```` \ No newline at end of file diff --git a/loco-extras/src/initializers/opentelemetry/mod.rs b/loco-extras/src/initializers/opentelemetry/mod.rs deleted file mode 100644 index 03cedc657..000000000 --- a/loco-extras/src/initializers/opentelemetry/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -use axum::{async_trait, Router as AxumRouter}; -use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer}; -use loco_rs::{ - app::{AppContext, Initializer}, - Error, Result, -}; - -pub struct OpenTelemetryInitializer; - -#[async_trait] -impl Initializer for OpenTelemetryInitializer { - fn name(&self) -> String { - "opentelemetry".to_string() - } - - async fn before_run(&self, _app_context: &AppContext) -> Result<()> { - match init_tracing_opentelemetry::tracing_subscriber_ext::init_subscribers() { - Ok(_) => Ok(()), - Err(e) => { - tracing::error!("Failed to initialize opentelemetry subscriber: {:?}", e); - Err(Error::Message(e.to_string())) - } - } - } - - async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result { - let router = router - .layer(OtelInResponseLayer) - .layer(OtelAxumLayer::default()); - Ok(router) - } -} diff --git a/loco-extras/src/initializers/prometheus.rs b/loco-extras/src/initializers/prometheus.rs deleted file mode 100644 index c071752a4..000000000 --- a/loco-extras/src/initializers/prometheus.rs +++ /dev/null @@ -1,21 +0,0 @@ -use async_trait::async_trait; -use axum::Router as AxumRouter; -use axum_prometheus::PrometheusMetricLayer; -use loco_rs::prelude::*; - -pub struct AxumPrometheusInitializer; - -#[async_trait] -impl Initializer for AxumPrometheusInitializer { - fn name(&self) -> String { - "axum-prometheus".to_string() - } - - async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result { - let (prometheus_layer, metric_handle) = PrometheusMetricLayer::pair(); - let router = router - .route("/metrics", get(|| async move { metric_handle.render() })) - .layer(prometheus_layer); - Ok(router) - } -} diff --git a/loco-extras/src/lib.rs b/loco-extras/src/lib.rs deleted file mode 100644 index faa88bced..000000000 --- a/loco-extras/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! # Loco Extras -//! -//! Loco Extras provides a collection of common implementations that prove to be generally useful when working with [Loco](https://loco.rs/). -//! -//! ## Features -//! -//! ### Initializers -//! * `initializer-prometheus` For adding prometheus collection metrics -//! endpoint. -//! * `initializer-extra-db` Adding extra DB connection -//! * `initializer-multi-db` Adding extra DB's connection -//! * `initializer-normalize-path` Normalize the request path -//! * `initializer-opentelemetry` For adding opentelemetry tracing -pub mod initializers;