From 442ad6ae867e3f852c67e2d7e9cb265a9e84be99 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Fri, 18 Oct 2024 22:05:02 -0700 Subject: [PATCH 1/4] fix tests tower::ServiceExt is used in the tests, but it is behind the util feature flag, which is not enabled --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index a7d342418..c67e3e6ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -174,3 +174,4 @@ insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] } tree-fs = { version = "0.1.0" } reqwest = { version = "0.12.7" } serial_test = "3.1.1" +tower = { workspace = true, features = ["util"]} From f4d49e1d063a716b33a649c537103607c897701c Mon Sep 17 00:00:00 2001 From: devartes Date: Sat, 19 Oct 2024 08:33:11 -0300 Subject: [PATCH 2/4] docs: Brazilian Portuguese README --- README-pt_BR.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ README-zh_CN.md | 2 +- README.fr.md | 2 +- README.md | 2 +- 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 README-pt_BR.md diff --git a/README-pt_BR.md b/README-pt_BR.md new file mode 100644 index 000000000..017470d2a --- /dev/null +++ b/README-pt_BR.md @@ -0,0 +1,113 @@ +
+ + + +

Bem-vindo ao Loco

+ +

+ +🚂 Loco é Rust on Rails. + +

+ + [![crate](https://img.shields.io/crates/v/loco-rs.svg)](https://crates.io/crates/loco-rs) + [![docs](https://docs.rs/loco-rs/badge.svg)](https://docs.rs/loco-rs) + [![Discord channel](https://img.shields.io/badge/discord-Join-us)](https://discord.gg/fTvyBzwKS8) + +
+ +[English](./README.md) · [中文](./README-zh_CN.md) · [Français](./README.fr.md) · Portuguese (Brazil) + + +## O que é o Loco? +`Loco` é fortemente inspirado no Rails. Se você conhece Rails e Rust, se sentirá em casa. Se você só conhece Rails e é novo em Rust, achará o Loco refrescante. Não presumimos que você conheça o Rails. + +Para uma imersão mais profunda em como o Loco funciona, incluindo guias detalhados, exemplos e referências da API, confira nosso [site de documentação](https://loco.rs). + + +## Recursos do Loco: + +* `Convenção sobre Configuração:` Semelhante ao Ruby on Rails, o Loco enfatiza simplicidade e produtividade ao reduzir a necessidade de código boilerplate. Ele utiliza padrões sensatos, permitindo que os desenvolvedores se concentrem em escrever a lógica de negócios em vez de perder tempo com configuração. + +* `Desenvolvimento Rápido:` Com o objetivo de alta produtividade para o desenvolvedor, o design do Loco se concentra em reduzir código boilerplate e fornecer APIs intuitivas, permitindo que os desenvolvedores iteren rapidamente e construam protótipos com esforço mínimo. + +* `Integração ORM:` Modele seu negócio com entidades robustas, eliminando a necessidade de escrever SQL. Defina relacionamentos, validações e lógica personalizada diretamente em suas entidades para melhorar a manutenção e escalabilidade. + +* `Controladores:` Manipule os parâmetros de solicitações web, corpo, validação e renderize uma resposta que é consciente do conteúdo. Usamos Axum para o melhor desempenho, simplicidade e extensibilidade. Os controladores também permitem que você construa facilmente middlewares, que podem ser usados para adicionar lógica como autenticação, registro ou tratamento de erros antes de passar as solicitações para as ações principais do controlador. + +* `Views:` O Loco pode se integrar com mecanismos de template para gerar conteúdo HTML dinâmico a partir de templates. + +* `Trabalhos em segundo plano:` Realize trabalhos intensivos de computação ou I/O em segundo plano com uma fila baseada em Redis ou com threads. Implementar um trabalhador é tão simples quanto implementar uma função de execução para o trait Worker. + +* `Scheduler:` Simplifica o tradicional e frequentemente complicado sistema crontab, tornando mais fácil e elegante agendar tarefas ou scripts shell. + +* `Mailers:` Um mailer entregará e-mails em segundo plano usando a infraestrutura de trabalhador existente do loco. Tudo será transparente para você. + +* `Armazenamento:` No Armazenamento do Loco, facilitamos o trabalho com arquivos por meio de várias operações. O armazenamento pode ser em memória, no disco ou utilizar serviços em nuvem, como AWS S3, GCP e Azure. + +* `Cache:` O Loco fornece uma camada de cache para melhorar o desempenho da aplicação armazenando dados acessados frequentemente. + +Para ver mais recursos do Loco, confira nosso [site de documentação](https://loco.rs/docs/getting-started/tour/). + + + +## Começando + +```sh +cargo install loco-cli +cargo install sea-orm-cli # Only when DB is needed +``` + + +Agora você pode criar seu novo aplicativo (escolha "`SaaS` app"). + + + +```sh +❯ loco new +✔ ❯ App name? · myapp +✔ ❯ What would you like to build? · SaaS app (with DB and user auth) +✔ ❯ Select a DB Provider · Sqlite +✔ ❯ Select your background worker type · Async (in-process tokio async tasks) +✔ ❯ Select an asset serving configuration · Client (configures assets for frontend serving) + +🚂 Loco app generated successfully in: +myapp/ +``` + + + Agora execute `cd` no seu `myapp` e inicie seu aplicativo: + +```sh +$ cargo loco start + + ▄ ▀ + ▀ ▄ + ▄ ▀ ▄ ▄ ▄▀ + ▄ ▀▄▄ + ▄ ▀ ▀ ▀▄▀█▄ + ▀█▄ +▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄ ▀▀█ +██████ █████ ███ █████ ███ █████ ███ ▀█ +██████ █████ ███ █████ ▀▀▀ █████ ███ ▄█▄ +██████ █████ ███ █████ █████ ███ ████▄ +██████ █████ ███ █████ ▄▄▄ █████ ███ █████ +██████ █████ ███ ████ ███ █████ ███ ████▀ + ▀▀▀██▄ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ██▀ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + https://loco.rs + +listening on port 5150 +``` + + +## Impulsionado pelo Loco ++ [SpectralOps](https://spectralops.io) - vários serviços impulsionados pelo framework Loco ++ [Nativish](https://nativi.sh) - backend do aplicativo impulsionado pelo framework Loco + +## Contribuidores ✨ +Agradecimentos a essas pessoas maravilhosas: + + + + diff --git a/README-zh_CN.md b/README-zh_CN.md index 36b3fca62..0452d054d 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -11,7 +11,7 @@ -[English](./README.md) · 中文 · [Français](./README.fr.md) +[English](./README.md) · 中文 · [Français](./README.fr.md) · [Portuguese (Brazil)](./README-pt_BR.md) Loco 是一个用 Rust 编写的 Web 框架,类似于 Rails。Loco 提供快速构建 Web 应用的功能,并且允许创建自定义任务,可以通过 CLI 运行。 diff --git a/README.fr.md b/README.fr.md index 7d97944bf..719de4aaa 100644 --- a/README.fr.md +++ b/README.fr.md @@ -14,7 +14,7 @@ -[English](./README.md) · [中文](./README-zh_CN.md) · Français +[English](./README.md) · [中文](./README-zh_CN.md) · Français · [Portuguese (Brazil)](./README-pt_BR.md) ## À propos de Loco diff --git a/README.md b/README.md index 2a464e295..e1c19397e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ -English · [中文](./README-zh_CN.md) · [Français](./README.fr.md) +English · [中文](./README-zh_CN.md) · [Français](./README.fr.md) · [Portuguese (Brazil)](./README-pt_BR.md) ## What's Loco? From b016709bc46b286599744e282484c8b5c83635b8 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sun, 20 Oct 2024 00:18:39 -0700 Subject: [PATCH 3/4] fix clippy lints (#872) * fix tests tower::ServiceExt is used in the tests, but it is behind the util feature flag, which is not enabled * fix clippy lints --- Cargo.toml | 1 + loco-extras/src/initializers/mongodb/mod.rs | 32 ++++++++----------- .../src/initializers/opentelemetry/mod.rs | 2 +- macros/tests/attr_macro.rs | 6 +++- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a7d342418..c67e3e6ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -174,3 +174,4 @@ insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] } tree-fs = { version = "0.1.0" } reqwest = { version = "0.12.7" } serial_test = "3.1.1" +tower = { workspace = true, features = ["util"]} diff --git a/loco-extras/src/initializers/mongodb/mod.rs b/loco-extras/src/initializers/mongodb/mod.rs index 87564ae4e..0c9176565 100644 --- a/loco-extras/src/initializers/mongodb/mod.rs +++ b/loco-extras/src/initializers/mongodb/mod.rs @@ -70,27 +70,21 @@ fn merge_config_with_client(co: &mut ClientOptions, config: MongoDbConfig) -> Cl 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.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.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.clone()); - co.load_balanced = client_options.load_balanced.or(co.load_balanced.clone()); - co.local_threshold = client_options - .local_threshold - .or(co.local_threshold.clone()); - co.max_idle_time = client_options.max_idle_time.or(co.max_idle_time.clone()); - co.max_pool_size = client_options.max_pool_size.or(co.max_pool_size.clone()); - co.min_pool_size = client_options.min_pool_size.or(co.min_pool_size.clone()); - co.max_connecting = client_options.max_connecting.or(co.max_connecting.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.clone()); - co.retry_writes = client_options.retry_writes.or(co.retry_writes.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()); @@ -100,7 +94,7 @@ fn merge_config_with_client(co: &mut ClientOptions, config: MongoDbConfig) -> Cl 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.clone()); + .or(co.server_selection_timeout); co.default_database = client_options .default_database .or(co.default_database.clone()); @@ -108,7 +102,7 @@ fn merge_config_with_client(co: &mut ClientOptions, config: MongoDbConfig) -> Cl // 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.clone()); + co.srv_max_hosts = client_options.srv_max_hosts.or(co.srv_max_hosts); co.clone() } diff --git a/loco-extras/src/initializers/opentelemetry/mod.rs b/loco-extras/src/initializers/opentelemetry/mod.rs index dc7330fa7..03cedc657 100644 --- a/loco-extras/src/initializers/opentelemetry/mod.rs +++ b/loco-extras/src/initializers/opentelemetry/mod.rs @@ -25,7 +25,7 @@ impl Initializer for OpenTelemetryInitializer { async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result { let router = router - .layer(OtelInResponseLayer::default()) + .layer(OtelInResponseLayer) .layer(OtelAxumLayer::default()); Ok(router) } diff --git a/macros/tests/attr_macro.rs b/macros/tests/attr_macro.rs index e37442e72..6e5da0ef8 100644 --- a/macros/tests/attr_macro.rs +++ b/macros/tests/attr_macro.rs @@ -1,5 +1,6 @@ // tests/attribute_macro.rs +#[allow(unused)] use loco_macros::*; // macro converts struct S to struct H @@ -7,5 +8,8 @@ use loco_macros::*; #[test] //#[test_request] fn test_macro() { - assert!(true); + #[allow(clippy::assertions_on_constants)] + { + assert!(true); + } } From e3804aae7a510c99dce0efb5cc49fb5bd54f2dc6 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sun, 20 Oct 2024 00:45:31 -0700 Subject: [PATCH 4/4] fix formatting (#870) Co-authored-by: Dotan J. Nahum --- src/bgworker/skq.rs | 5 +++-- src/controller/format.rs | 5 +++-- src/controller/middleware/powered_by.rs | 22 +++++++++++++--------- src/controller/views/mod.rs | 4 ++-- src/scheduler.rs | 20 ++++++++++---------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/bgworker/skq.rs b/src/bgworker/skq.rs index 280c328e6..2b8bab9ab 100644 --- a/src/bgworker/skq.rs +++ b/src/bgworker/skq.rs @@ -1,10 +1,11 @@ use std::{marker::PhantomData, sync::Arc}; -use super::{BackgroundWorker, Queue}; -use crate::{config::RedisQueueConfig, Result}; use async_trait::async_trait; use bb8::Pool; use sidekiq::{Processor, ProcessorConfig, RedisConnectionManager}; + +use super::{BackgroundWorker, Queue}; +use crate::{config::RedisQueueConfig, Result}; pub type RedisPool = Pool; #[derive(Debug)] diff --git a/src/controller/format.rs b/src/controller/format.rs index 5d7afa37e..230e4523f 100644 --- a/src/controller/format.rs +++ b/src/controller/format.rs @@ -372,11 +372,12 @@ pub fn render() -> RenderBuilder { #[cfg(test)] mod tests { - use super::*; - use crate::{controller::views::engines::TeraView, prelude::*}; use insta::assert_debug_snapshot; use tree_fs; + use super::*; + use crate::{controller::views::engines::TeraView, prelude::*}; + async fn response_body_to_string(response: hyper::Response) -> String { let bytes = axum::body::to_bytes(response.into_body(), 200) .await diff --git a/src/controller/middleware/powered_by.rs b/src/controller/middleware/powered_by.rs index 927fc0128..0656a93de 100644 --- a/src/controller/middleware/powered_by.rs +++ b/src/controller/middleware/powered_by.rs @@ -1,29 +1,33 @@ //! Powered-By Middleware //! -//! This middleware injects an HTTP header `X-Powered-By` into the response headers of -//! every request handled by the application. The header identifies the software or technology -//! stack powering the application. It supports a custom identifier string or defaults to "loco.rs" -//! if no identifier is provided. +//! This middleware injects an HTTP header `X-Powered-By` into the response +//! headers of every request handled by the application. The header identifies +//! the software or technology stack powering the application. It supports a +//! custom identifier string or defaults to "loco.rs" if no identifier is +//! provided. -use crate::{app::AppContext, controller::middleware::MiddlewareLayer, Result}; use axum::{ http::header::{HeaderName, HeaderValue}, Router as AXRouter, }; use tower_http::set_header::SetResponseHeaderLayer; +use crate::{app::AppContext, controller::middleware::MiddlewareLayer, Result}; + lazy_static::lazy_static! { static ref DEFAULT_IDENT_HEADER_VALUE: HeaderValue = HeaderValue::from_static("loco.rs"); } -/// [`Middleware`] struct responsible for managing the identifier value for the `X-Powered-By` header. +/// [`Middleware`] struct responsible for managing the identifier value for the +/// `X-Powered-By` header. #[derive(Debug)] pub struct Middleware { ident: Option, } -/// Creates a new instance of [`Middleware`] by cloning the [`Config`] configuration. +/// Creates a new instance of [`Middleware`] by cloning the [`Config`] +/// configuration. #[must_use] pub fn new(ident: Option<&str>) -> Middleware { let ident_value = ident.map_or_else( @@ -68,8 +72,8 @@ impl MiddlewareLayer for Middleware { ) } - /// Applies the middleware to the application by adding the `X-Powered-By` header to - /// each response. + /// Applies the middleware to the application by adding the `X-Powered-By` + /// header to each response. fn apply(&self, app: AXRouter) -> Result> { Ok(app.layer(SetResponseHeaderLayer::overriding( HeaderName::from_static("x-powered-by"), diff --git a/src/controller/views/mod.rs b/src/controller/views/mod.rs index 2948cb61f..4eccc672e 100644 --- a/src/controller/views/mod.rs +++ b/src/controller/views/mod.rs @@ -28,8 +28,8 @@ impl ViewEngine { /// A struct representing an inline Tera view renderer. /// -/// This struct provides functionality to render templates using the Tera templating engine -/// directly from raw template strings. +/// This struct provides functionality to render templates using the Tera +/// templating engine directly from raw template strings. /// /// # Example /// ``` diff --git a/src/scheduler.rs b/src/scheduler.rs index f4caab4b9..25c9656c0 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -1,8 +1,6 @@ //! # Scheduler Module //! TBD -use regex::Regex; -use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, fmt, io, @@ -10,10 +8,12 @@ use std::{ time::Instant, }; -use crate::{app::Hooks, environment::Environment, task::Tasks}; - +use regex::Regex; +use serde::{Deserialize, Serialize}; use tokio_cron_scheduler::{JobScheduler, JobSchedulerError}; +use crate::{app::Hooks, environment::Environment, task::Tasks}; + lazy_static::lazy_static! { static ref RE_IS_CRON_SYNTAX: Regex = Regex::new(r"^[\*\d]").unwrap(); } @@ -71,7 +71,7 @@ pub struct Job { /// /// The format is as follows: /// sec min hour day of month month day of week year - /// * * * * * * * + /// * * * * * * * pub cron: String, /// Tags for tagging the job. pub tags: Option>, @@ -219,8 +219,8 @@ impl Scheduler { /// Creates a new scheduler instance from the provided configuration data. /// - /// When creating a new scheduler instance all register task should be loaded for validate the - /// given configuration. + /// When creating a new scheduler instance all register task should be + /// loaded for validate the given configuration. /// /// # Errors /// @@ -352,14 +352,14 @@ impl Scheduler { #[cfg(test)] mod tests { - use super::*; - use crate::tests_cfg; use insta::assert_debug_snapshot; - use rstest::rstest; use tests_cfg::db::AppHook; use tokio::time::{self, Duration}; + use super::*; + use crate::tests_cfg; + fn get_scheduler_from_config() -> Result { let scheduler_config_path = PathBuf::from("tests") .join("fixtures")