Skip to content

Commit

Permalink
Merge branch 'master' into seed-with-nullable-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
kaplanelad authored Oct 14, 2024
2 parents 1e8b660 + ae1bf11 commit 060c69a
Show file tree
Hide file tree
Showing 16 changed files with 188 additions and 34 deletions.
2 changes: 1 addition & 1 deletion docs-site/content/docs/getting-started/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Loco is a Web or API framework for Rust. It's also a productivity suite for deve

## Creating a New Loco App

You can follow this guide for a step-by-step "bottom up" learning, or you can jump and go with the [tour](./tour.md) instead for a quicker "top down" intro.
You can follow this guide for a step-by-step "bottom up" learning, or you can jump and go with the [tour](@/docs/getting-started/tour/index.md) instead for a quicker "top down" intro.

### Installing

Expand Down
4 changes: 2 additions & 2 deletions docs-site/content/docs/processing/scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ flair =[]
+++


Loco simplifies the traditional, often cumbersome `crontab` system, making it easier and more elegant to schedule cron jobs. The scheduler job can execute either a shell script command or run a registered [task](./task.md).
Loco simplifies the traditional, often cumbersome `crontab` system, making it easier and more elegant to schedule cron jobs. The scheduler job can execute either a shell script command or run a registered [task](@/docs/processing/task.md).


## Setting Up
Expand Down Expand Up @@ -96,7 +96,7 @@ The scheduler configuration consists of the following elements:
```
* `shell`: by default `false` meaning executing the the `run` value as a task. if `true` execute the `run` value as shell command
* `run`: Cronjob command to run.
* `Task:` The task name (with variables e.x `[TASK_NAME] KEY:VAl`. follow [here](./task.md) to see task arguments ). Note that the `shell` field should be false.
* `Task:` The task name (with variables e.x `[TASK_NAME] KEY:VAl`. follow [here](@/docs/processing/task.md) to see task arguments ). Note that the `shell` field should be false.
* `Shell`: Run a shell command (e.x `"echo loco >> ./scheduler.txt"`). Note that the `shell` field should be true.
* `tags` (Optional): A list of tags to categorize and manage the job.
* `output` (Optional): Overrides the global `scheduler.output` for this job.
Expand Down
6 changes: 6 additions & 0 deletions docs-site/content/docs/resources/around-the-web.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ Check out Loco resources and links from around the Web.

- [A Legendary Web Framework is Reborn... in Rust](https://www.youtube.com/watch?v=7utPutDORb4) - by [Code to the Moon](https://www.youtube.com/@codetothemoon)


## Ecosystem

- [rhai-loco](https://docs.rs/rhai-loco/latest/rhai_loco/) - This crate adds [Rhai](https://rhai.rs) script support to [Loco](https://loco.rs)
- [loco-oauth2](https://github.com/yinho999/loco-oauth2) - Loco OAuth2 is a simple OAuth2 initializer for the Loco API. It is designed to be a tiny and easy-to-use library for implementing OAuth2 in your application.

## App Examples

* [Chat rooms](https://github.com/loco-rs/chat-rooms) - With opening a web socket
Expand Down
14 changes: 14 additions & 0 deletions docs-site/content/docs/the-app/your-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,20 @@ if let Some(settings) = &ctx.config.settings {
}
```

### Server



Here is a detailed description of the interface (listening, etc.) parameters under `server:`:

* `port:` as the name says, for changing ports, mostly when behind a load balancer, etc.

* `binding:` for changing what the IP interface "binds" to, mostly, when you are behind a load balancer like `ngnix` you bind to a local address (when the LB is also there). However you can also bind to "world" (`0.0.0.0`). You can set the binding: field via config, or via the CLI (using the `-b` flag) -- which is what Rails is doing.

* `host:` - for "visibility" use cases or out-of-band use cases. For example, some times you want to display the current server host (in terms of domain name, etc.), which serves for visibility. And some times, as in the case of emails -- your server address is "out of band", meaning when I open my gmail account and I have your email -- I have to click what looks like your external address or visible address (official domain name, etc), and not an internal "host" address which is what may be the wrong thing to do (imagine an email link pointing to "http://127.0.0.1/account/verify")



### Logger

Other than the commented fields in the `logger:` section on your YAML file, here's some more context:
Expand Down
45 changes: 41 additions & 4 deletions examples/demo/Cargo.lock

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

1 change: 1 addition & 0 deletions examples/demo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ unic-langid = "0.9.4"
tera = "1.19.1"
tower = "0.4.13"
futures-util = "0.3.30"
utoipa = "4.2.3"

[[bin]]
name = "demo_app-cli"
Expand Down
9 changes: 9 additions & 0 deletions examples/demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Demo

This app is a kitchensink for various capabilities and examples of the [Loco](https://loco.rs) project.

# Example Listings

## OpenAPI with `utoipa`

See [src/controllers/responses.rs](src/controllers/responses.rs)
2 changes: 1 addition & 1 deletion examples/demo/examples/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ async fn main() -> loco_rs::Result<()> {
port: boot_result.app_context.config.server.port,
binding: boot_result.app_context.config.server.binding.to_string(),
};
start::<App>(boot_result, serve_params).await?;
start::<App>(boot_result, serve_params, false).await?;
Ok(())
}
2 changes: 1 addition & 1 deletion examples/demo/examples/workers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ async fn main() -> loco_rs::Result<()> {
port: boot_result.app_context.config.server.port,
binding: boot_result.app_context.config.server.binding.to_string(),
};
start::<App>(boot_result, serve_params).await?;
start::<App>(boot_result, serve_params, false).await?;
Ok(())
}
35 changes: 35 additions & 0 deletions examples/demo/src/controllers/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use axum_extra::extract::cookie::Cookie;
use loco_rs::prelude::*;
use serde::Serialize;
use utoipa::{openapi, OpenApi, ToSchema};

#[derive(Serialize)]
pub struct Health {
Expand Down Expand Up @@ -97,6 +98,39 @@ pub async fn set_cookie() -> Result<Response> {
format::render().cookies(&[cookie])?.json(())
}

#[derive(Serialize, Debug, ToSchema)]
pub struct Album {
title: String,
rating: u32,
}

//
// OpenAPI spec with `utoipa`
//
#[derive(OpenApi)]
#[openapi(paths(album))]
struct Spec;

/// Return an OpenAPI-spec'd response
///
/// # Errors
///
/// This function will return an error if it fails
#[utoipa::path(
get,
path = "/response/album",
responses(
(status = 200, description = "Album found", body = Album),
),
)]
pub async fn album() -> Result<Response> {
println!("{}", Spec::openapi().to_pretty_json().unwrap());

format::json(Album {
title: "VH II".to_string(),
rating: 10,
})
}
pub fn routes() -> Routes {
Routes::new()
.prefix("response")
Expand All @@ -108,5 +142,6 @@ pub fn routes() -> Routes {
.add("/redirect", get(redirect))
.add("/render_with_status_code", get(render_with_status_code))
.add("/etag", get(etag))
.add("/album", get(album))
.add("/set_cookie", get(set_cookie))
}
3 changes: 1 addition & 2 deletions examples/demo/tests/cmd/cli.trycmd
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ $ demo_app-cli routes --environment test
[GET] /notes/:id
[DELETE] /notes/:id
[POST] /notes/:id
[GET] /response/album
[GET] /response/empty
[GET] /response/empty_json
[GET] /response/etag
Expand All @@ -126,10 +127,8 @@ $ demo_app-cli routes --environment test

```console
$ demo_app-cli doctor
[..][0m DEBUG app: loco_rs::bgworker: job queue ping requested environment=development
✅ SeaORM CLI is installed
✅ DB connection: success
✅ redis queue: queue connection: success

```

Expand Down
19 changes: 15 additions & 4 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use axum::Router as AxumRouter;
use crate::controller::channels::AppChannels;
use crate::{
bgworker::{self, Queue},
boot::{BootResult, ServeParams, StartMode},
boot::{shutdown_signal, BootResult, StartMode},
cache::{self},
config::{self, Config},
controller::{
Expand Down Expand Up @@ -63,7 +63,7 @@ pub struct AppContext {
/// the application's routing, worker connections, task registration, and
/// database actions according to their specific requirements and use cases.
#[async_trait]
pub trait Hooks {
pub trait Hooks: Send {
/// Defines the composite app version
#[must_use]
fn app_version() -> String {
Expand Down Expand Up @@ -111,17 +111,23 @@ pub trait Hooks {
///
/// # Returns
/// A Result indicating success () or an error if the server fails to start.
async fn serve(app: AxumRouter, server_config: ServeParams) -> Result<()> {
async fn serve(app: AxumRouter, ctx: &AppContext) -> Result<()> {
let listener = tokio::net::TcpListener::bind(&format!(
"{}:{}",
server_config.binding, server_config.port
ctx.config.server.binding, ctx.config.server.port
))
.await?;

let cloned_ctx = ctx.clone();
axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.with_graceful_shutdown(async move {
shutdown_signal().await;
tracing::info!("shutting down...");
Self::on_shutdown(&cloned_ctx).await;
})
.await?;

Ok(())
Expand Down Expand Up @@ -208,6 +214,11 @@ pub trait Hooks {
/// Seeds the database with initial data.
#[cfg(feature = "with-db")]
async fn seed(db: &DatabaseConnection, path: &Path) -> Result<()>;

/// Called when the application is shutting down.
/// This function allows users to perform any necessary cleanup or final
/// actions before the application stops completely.
async fn on_shutdown(_ctx: &AppContext) {}
}

/// An initializer.
Expand Down
Loading

0 comments on commit 060c69a

Please sign in to comment.