Skip to content

Commit

Permalink
feat: Support Poise (#560)
Browse files Browse the repository at this point in the history
* feat: impl Service for Poise

* feat(poise): add to ci

* doc(poise): add link to poise example

* feat(poise): add poise to cargo shuttle init

Co-authored-by: oddgrd <[email protected]>
  • Loading branch information
Anafabula and oddgrd authored Jan 9, 2023
1 parent 85268c9 commit 0599a13
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ workflows:
- workspace-fmt
matrix:
parameters:
framework: ["web-actix-web", "web-axum", "web-rocket", "web-poem", "web-thruster", "web-tide", "web-tower","web-warp", "web-salvo", "bot-serenity"]
framework: ["web-actix-web", "web-axum", "web-rocket", "web-poem", "web-thruster", "web-tide", "web-tower","web-warp", "web-salvo", "bot-serenity", "bot-poise"]
- check-standalone:
matrix:
parameters:
Expand Down
37 changes: 37 additions & 0 deletions Cargo.lock

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

29 changes: 18 additions & 11 deletions cargo-shuttle/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,37 +148,40 @@ pub struct RunArgs {
#[derive(Parser, Debug)]
pub struct InitArgs {
/// Initialize with actix-web framework
#[clap(long="actix-web", conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "serenity", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long="actix-web", conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "serenity", "poise", "warp", "salvo", "thruster", "no-framework"])]
pub actix_web: bool,
/// Initialize with axum framework
#[clap(long, conflicts_with_all = &["actix-web","rocket", "tide", "tower", "poem", "serenity", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","rocket", "tide", "tower", "poem", "serenity", "poise", "warp", "salvo", "thruster", "no-framework"])]
pub axum: bool,
/// Initialize with rocket framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "tide", "tower", "poem", "serenity", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "tide", "tower", "poem", "serenity", "poise", "warp", "salvo", "thruster", "no-framework"])]
pub rocket: bool,
/// Initialize with tide framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tower", "poem", "serenity", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tower", "poem", "serenity", "poise", "warp", "salvo", "thruster", "no-framework"])]
pub tide: bool,
/// Initialize with tower framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "poem", "serenity", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "poem", "serenity", "poise", "warp", "salvo", "thruster", "no-framework"])]
pub tower: bool,
/// Initialize with poem framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "serenity", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "serenity", "poise", "warp", "salvo", "thruster", "no-framework"])]
pub poem: bool,
/// Initialize with salvo framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "serenity", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "serenity", "poise", "thruster", "no-framework"])]
pub salvo: bool,
/// Initialize with serenity framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "poise", "salvo", "thruster", "no-framework"])]
pub serenity: bool,
/// Initialize with poise framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "serenity", "salvo", "thruster", "no-framework"])]
pub poise: bool,
/// Initialize with warp framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "serenity", "salvo", "thruster", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "serenity", "poise", "salvo", "thruster", "no-framework"])]
pub warp: bool,
/// Initialize with thruster framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "serenity", "no-framework"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "serenity", "poise", "no-framework"])]
pub thruster: bool,
/// Initialize without a framework
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "serenity", "thruster"])]
#[clap(long, conflicts_with_all = &["actix-web","axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "serenity", "poise", "thruster"])]
pub no_framework: bool,
/// Whether to create the environment for this project on Shuttle
#[clap(long)]
Expand Down Expand Up @@ -209,6 +212,8 @@ impl InitArgs {
Some(Framework::Poem)
} else if self.salvo {
Some(Framework::Salvo)
} else if self.poise {
Some(Framework::Poise)
} else if self.serenity {
Some(Framework::Serenity)
} else if self.warp {
Expand Down Expand Up @@ -257,6 +262,7 @@ mod tests {
poem: false,
salvo: false,
serenity: false,
poise: false,
warp: false,
thruster: false,
no_framework: false,
Expand All @@ -274,6 +280,7 @@ mod tests {
"poem" => init_args.poem = true,
"salvo" => init_args.salvo = true,
"serenity" => init_args.serenity = true,
"poise" => init_args.poise = true,
"warp" => init_args.warp = true,
"thruster" => init_args.thruster = true,
"none" => init_args.no_framework = true,
Expand Down
137 changes: 137 additions & 0 deletions cargo-shuttle/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub enum Framework {
Poem,
Salvo,
Serenity,
Poise,
Warp,
Thruster,
None,
Expand All @@ -39,6 +40,7 @@ impl Framework {
Framework::Poem => Box::new(ShuttleInitPoem),
Framework::Salvo => Box::new(ShuttleInitSalvo),
Framework::Serenity => Box::new(ShuttleInitSerenity),
Framework::Poise => Box::new(ShuttleInitPoise),
Framework::Warp => Box::new(ShuttleInitWarp),
Framework::Thruster => Box::new(ShuttleInitThruster),
Framework::None => Box::new(ShuttleInitNoOp),
Expand Down Expand Up @@ -446,6 +448,106 @@ impl ShuttleInit for ShuttleInitSerenity {
}
}

pub struct ShuttleInitPoise;

impl ShuttleInit for ShuttleInitPoise {
fn set_cargo_dependencies(
&self,
dependencies: &mut Table,
manifest_path: &Path,
url: &Url,
get_dependency_version_fn: GetDependencyVersionFn,
) {
set_inline_table_dependency_features(
"shuttle-service",
dependencies,
vec!["bot-poise".to_string()],
);

set_key_value_dependency_version(
"anyhow",
dependencies,
manifest_path,
url,
false,
get_dependency_version_fn,
);

set_key_value_dependency_version(
"poise",
dependencies,
manifest_path,
url,
false,
get_dependency_version_fn,
);

set_key_value_dependency_version(
"shuttle-secrets",
dependencies,
manifest_path,
url,
false,
get_dependency_version_fn,
);

set_key_value_dependency_version(
"tracing",
dependencies,
manifest_path,
url,
false,
get_dependency_version_fn,
);
}

fn get_boilerplate_code_for_framework(&self) -> &'static str {
indoc! {r#"
use anyhow::Context as _;
use poise::serenity_prelude as serenity;
use shuttle_secrets::SecretStore;
use shuttle_service::ShuttlePoise;
struct Data {} // User data, which is stored and accessible in all command invocations
type Error = Box<dyn std::error::Error + Send + Sync>;
type Context<'a> = poise::Context<'a, Data, Error>;
/// Responds with "world!"
#[poise::command(slash_command)]
async fn hello(ctx: Context<'_>) -> Result<(), Error> {
ctx.say("world!").await?;
Ok(())
}
#[shuttle_service::main]
async fn poise(#[shuttle_secrets::Secrets] secret_store: SecretStore) -> ShuttlePoise<Data, Error> {
// Get the discord token set in `Secrets.toml`
let discord_token = secret_store
.get("DISCORD_TOKEN")
.context("'DISCORD_TOKEN' was not found")?;
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
commands: vec![hello()],
..Default::default()
})
.token(discord_token)
.intents(serenity::GatewayIntents::non_privileged())
.setup(|ctx, _ready, framework| {
Box::pin(async move {
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
Ok(Data {})
})
})
.build()
.await
.map_err(shuttle_service::error::CustomError::new)?;
Ok(framework)
}"#}
}
}

pub struct ShuttleInitTower;

impl ShuttleInit for ShuttleInitTower {
Expand Down Expand Up @@ -1125,6 +1227,41 @@ mod shuttle_init_tests {
assert_eq!(cargo_toml.to_string(), expected);
}

#[test]
fn test_set_cargo_dependencies_poise() {
let mut cargo_toml = cargo_toml_factory();
let dependencies = cargo_toml["dependencies"].as_table_mut().unwrap();
let manifest_path = PathBuf::new();
let url = Url::parse("https://shuttle.rs").unwrap();

set_inline_table_dependency_version(
"shuttle-service",
dependencies,
&manifest_path,
&url,
false,
mock_get_latest_dependency_version,
);

ShuttleInitPoise.set_cargo_dependencies(
dependencies,
&manifest_path,
&url,
mock_get_latest_dependency_version,
);

let expected = indoc! {r#"
[dependencies]
shuttle-service = { version = "1.0", features = ["bot-poise"] }
anyhow = "1.0"
poise = "1.0"
shuttle-secrets = "1.0"
tracing = "1.0"
"#};

assert_eq!(cargo_toml.to_string(), expected);
}

#[test]
fn test_set_cargo_dependencies_warp() {
let mut cargo_toml = cargo_toml_factory();
Expand Down
2 changes: 2 additions & 0 deletions service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ rocket = { version = "0.5.0-rc.2", optional = true }
salvo = { version = "0.37.5", optional = true }
serde_json = { workspace = true }
serenity = { version = "0.11.5", default-features = false, features = ["client", "gateway", "rustls_backend", "model"], optional = true }
poise = { version = "0.5.2", optional = true }
sync_wrapper = { version = "0.1.1", optional = true }
thiserror = { workspace = true }
thruster = { version = "1.3.0", optional = true }
Expand Down Expand Up @@ -76,4 +77,5 @@ web-poem = ["poem"]
web-salvo = ["salvo"]

bot-serenity = ["serenity"]
bot-poise = ["poise"]
web-warp = ["warp"]
18 changes: 18 additions & 0 deletions service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ extern crate shuttle_codegen;
/// | `ShuttlePoem` | web-poem | [poem](https://docs.rs/poem/1.3.35) | 1.3.35 | [GitHub](https://github.com/shuttle-hq/examples/tree/main/poem/hello-world) |
/// | `Result<T, shuttle_service::Error>` | web-tower | [tower](https://docs.rs/tower/0.4.12) | 0.14.12 | [GitHub](https://github.com/shuttle-hq/examples/tree/main/tower/hello-world) |
/// | `ShuttleSerenity` | bot-serenity | [serenity](https://docs.rs/serenity/0.11.5) | 0.11.5 | [GitHub](https://github.com/shuttle-hq/examples/tree/main/serenity/hello-world) |
/// | `ShuttlePoise` | bot-poise | [poise](https://docs.rs/poise/0.5.2) | 0.5.2 | [GitHub](https://github.com/shuttle-hq/examples/tree/main/poise/hello-world) |
/// | `ShuttleActixWeb` | web-actix-web| [actix-web](https://docs.rs/actix-web/4.2.1)| 4.2.1 | [GitHub](https://github.com/shuttle-hq/examples/tree/main/actix-web/hello-world) |
///
Expand Down Expand Up @@ -661,5 +662,22 @@ impl Service for serenity::Client {
#[cfg(feature = "bot-serenity")]
pub type ShuttleSerenity = Result<serenity::Client, Error>;

#[cfg(feature = "bot-poise")]
#[async_trait]
impl<T, E> Service for std::sync::Arc<poise::Framework<T, E>>
where
T: std::marker::Send + std::marker::Sync + 'static,
E: std::marker::Send + std::marker::Sync + 'static,
{
async fn bind(mut self: Box<Self>, _addr: SocketAddr) -> Result<(), error::Error> {
self.start().await.map_err(error::CustomError::new)?;

Ok(())
}
}

#[cfg(feature = "bot-poise")]
pub type ShuttlePoise<T, E> = Result<std::sync::Arc<poise::Framework<T, E>>, Error>;

pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const NAME: &str = env!("CARGO_PKG_NAME");

0 comments on commit 0599a13

Please sign in to comment.