Skip to content

Commit

Permalink
feat(www/docs): update blog and secrets readme (#402)
Browse files Browse the repository at this point in the history
  • Loading branch information
oddgrd authored Oct 17, 2022
1 parent 1b4e8ab commit c2d7fcc
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 43 deletions.
9 changes: 5 additions & 4 deletions resources/secrets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
This plugin manages secrets on [shuttle](https://www.shuttle.rs).

## Usage
Add `shuttle-secrets` to the dependencies for your service. Also add a dependency which will give you a `PgPool` like [shuttle-shared-db](https://github.com/shuttle-hq/shuttle/tree/main/resources/shared-db)
Add `shuttle-secrets` to the dependencies for your service, and add a `Secrets.toml` to the root of your project
with the secrets you'd like to store. Make sure to add `Secrets.toml` to a `.gitignore` to omit your secrets from version control.

[`SecretStore::get_secret`] can now be called on any instance of this pool to retrieve stored secrets.

An example using the Rocket framework can be found on [GitHub](https://github.com/shuttle-hq/shuttle/tree/main/examples/rocket/postgres)
Next, pass `#[shuttle_secrets::Secrets] secret_store: SecretStore` as an argument to your `shuttle_service::main` function.
`SecretStore::get` can now be called to retrieve your API keys and other secrets at runtime.

An example using the Rocket framework can be found on [GitHub](https://github.com/shuttle-hq/shuttle/tree/main/examples/rocket/secrets)
22 changes: 15 additions & 7 deletions www/_blog/2022-08-11-authentication-tutorial.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,16 @@ The `id` is generated by the database using a sequence. The `id` is a primary ke

### Registering our database

Before our app can use the database we have to add sqlx with some features: `cargo add sqlx -F postgres runtime-tokio-native-tls`. We will also enable the Postgres feature for shuttle with `cargo add shuttle-service -F sqlx-postgres`.
Before our app can use the database we have to add sqlx with some features: `cargo add sqlx -F postgres runtime-tokio-native-tls`. We will also add the `shuttle-shared-db` crate with `cargo add shuttle-shared-db -F postgres`.

Now back in the code we add a parameter with `#[shared::Postgres] pool: Database`. The `#[shared::Postgres]` annotation tells shuttle to provision a Postgres database using the [infrastructure from code design](https://www.shuttle.rs/blog/2022/05/09/ifc)!
Now back in the code we add a parameter with `#[shuttle_shared_db::Postgres] pool: Database`. The `#[shuttle_shared_db::Postgres]` annotation tells shuttle to provision a Postgres database using the [infrastructure from code design](https://www.shuttle.rs/blog/2022/05/09/ifc)!

```rust
type Database = sqlx::PgPool;

#[shuttle_service::main]
async fn axum(
#[shared::Postgres] pool: Database
#[shuttle_shared_db::Postgres] pool: Database
) -> ShuttleAxum {
// Build tera as before

Expand Down Expand Up @@ -359,7 +359,7 @@ To initialize the random generator we use [SeedableRng::from_seed](https://docs.
```rust
#[shuttle_service::main]
async fn axum(
#[shared::Postgres] pool: Database
#[shuttle_shared_db::Postgres] pool: Database
) -> ShuttleAxum {
// Build tera as before

Expand Down Expand Up @@ -537,7 +537,7 @@ We can add the middleware to our chain using:
```rust
#[shuttle_service::main]
async fn axum(
#[shared::Postgres] pool: Database
#[shuttle_shared_db::Postgres] pool: Database
) -> ShuttleAxum {
// tera and random creation as before

Expand Down Expand Up @@ -650,7 +650,7 @@ Then we refer back to the [signup section](#using-html-forms) and replicate the
```rust
#[shuttle_service::main]
async fn axum(
#[shared::Postgres] pool: Database
#[shuttle_shared_db::Postgres] pool: Database
) -> ShuttleAxum {
// tera, middleware and random creation as before

Expand All @@ -668,7 +668,15 @@ async fn axum(

This is great, we now have a site with signup and login functionality. But we have no users, our friends can't log in on our localhost. We want it live on the interwebs. Luckily we are using shuttle, so it is as simple as:

`cargo shuttle project new` and `cargo shuttle deploy`
Create a project, this will start an isolated deployer container for you under the hood:
```
cargo shuttle project new
```

Finally, to deploy your app, all you need to do is:
```
cargo shuttle deploy
```

Because of our `#[shuttle_service::main]` annotation and out-the-box Axum support our deployment doesn't need any prior config, it is instantly live!

Expand Down
66 changes: 34 additions & 32 deletions www/_blog/2022-09-14-serentity-discord-bot.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,13 @@ cargo shuttle init --serenity
After running it you, should see the following generated in `src/lib.rs`:

```rust
use log::{error, info};
use anyhow::anyhow;
use serenity::async_trait;
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::prelude::*;
use shuttle_service::error::CustomError;
use shuttle_service::SecretStore;
use sqlx::PgPool;
use shuttle_secrets::SecretStore;
use tracing::{error, info};

struct Bot;

Expand All @@ -90,12 +89,15 @@ impl EventHandler for Bot {
}

#[shuttle_service::main]
async fn serenity(#[shared::Postgres] pool: PgPool) -> shuttle_service::ShuttleSerenity {
// Get the discord token set in `Secrets.toml` from the shared Postgres database
let token = pool
.get_secret("DISCORD_TOKEN")
.await
.map_err(CustomError::new)?;
async fn serenity(
#[shuttle_secrets::Secrets] secret_store: SecretStore,
) -> shuttle_service::ShuttleSerenity {
// Get the discord token set in `Secrets.toml`
let token = if let Some(token) = secret_store.get("DISCORD_TOKEN") {
token
} else {
return Err(anyhow!("'DISCORD_TOKEN' was not found").into());
};

// Set gateway intents, which decides what events the bot will be notified about
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
Expand Down Expand Up @@ -176,16 +178,14 @@ impl EventHandler for Bot {

### Trying it out

Now with the code written we can test it locally. Before we do that we have to authenticate the bot with Discord. We do this with the value we got from "Reset Token" on the bot screen in one of the previous steps. To register a secret with shuttle we create a `Secrets.toml` file with a key value pair. This pair is read by the `pool.get_secret("DISCORD_TOKEN")` call in the `ready` hook:
Now with the code written we can test it locally. Before we do that we have to authenticate the bot with Discord. We do this with the value we got from "Reset Token" on the bot screen in one of the previous steps. To register a secret with shuttle we create a `Secrets.toml` file with a key value pair. This pair is read by the `secret_store.get("DISCORD_TOKEN")` call in the `ready` hook:

```
# Secrets.toml
DISCORD_TOKEN="*your discord token*"
DISCORD_GUILD_ID="*the guild we are testing on*"
```

> Currently *secrets* are stored using shuttle's database Postgres offering (thus why the parameter on main is `PgPool`). Therefore during local testing you need access to a Postgres database. Shuttle's local runner does this using Docker which will require [Docker desktop](https://community.chocolatey.org/packages/docker-desktop/2.1.0.3) being locally installed to use the Secrets locally. **This is is subject to change in the future so that it doesn't require Docker for local secrets.** There is also a known issue with deploying Secrets on Windows so if you have problems [consult the Discord](https://discord.gg/shuttle).
`cargo shuttle run`

We should see that our bot now displays as online:
Expand Down Expand Up @@ -338,26 +338,23 @@ Our `get_forecast` requires a `reqwest` Client and the weather API key. We will
struct Bot {
weather_api_key: String,
client: reqwest::Client,
discord_guild_id: GuildId,
discord_guild_id: GuildId,
}

#[shuttle_service::main]
async fn serenity(#[shared::Postgres] pool: PgPool) -> shuttle_service::ShuttleSerenity {
// Get the discord token set in `Secrets.toml` from the shared Postgres database
let token = pool
.get_secret("DISCORD_TOKEN")
.await
.map_err(CustomError::new)?;
async fn serenity(#[shuttle_secrets::Secrets] secret_store: SecretStore) -> shuttle_service::ShuttleSerenity {
// Get the discord token set in `Secrets.toml`
let token = secret_store
.get("DISCORD_TOKEN")
.context("'DISCORD_TOKEN' was not found")?;

let weather_api_key = pool
.get_secret("WEATHER_API_KEY")
.await
.map_err(CustomError::new)?;
let weather_api_key = secret_store
.get("WEATHER_API_KEY")
.context("'WEATHER_API_KEY' was not found")?;

let discord_guild_id = pool
.get_secret("DISCORD_GUILD_ID")
.await
.map_err(CustomError::new)?;
let discord_guild_id = secret_store
.get("DISCORD_GUILD_ID")
.context("'DISCORD_GUILD_ID' was not found")?;

// Set gateway intents, which decides what events the bot will be notified about
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
Expand All @@ -366,7 +363,7 @@ async fn serenity(#[shared::Postgres] pool: PgPool) -> shuttle_service::ShuttleS
.event_handler(Bot {
weather_api_key,
client: reqwest::Client::new(),
discord_guild_id: GuildId(discord_guild_id.parse().unwrap())
discord_guild_id: GuildId(discord_guild_id.parse().unwrap())
})
.await
.expect("Err creating client");
Expand Down Expand Up @@ -460,9 +457,14 @@ And entering a location that isn’t registered returns an error, thanks to the

With all of that setup, it is really easy to get your bot hosted and running without having to run your PC 24/7.

Just write:

`cargo shuttle project new` and `cargo shuttle deploy`
Create a project, this will start an isolated deployer container for you under the hood:
```bash
cargo shuttle project new
```
Finally, to deploy your app, all you need to do is:
```bash
cargo shuttle deploy
```

And you are good to go. Easy-pease, right?

Expand Down

0 comments on commit c2d7fcc

Please sign in to comment.