Skip to content

Commit

Permalink
feat(service): Add thruster framework as service
Browse files Browse the repository at this point in the history
    Adds the [thruster](https://github.com/thruster-rs/Thruster) framework as a launchable target for use with shuttle.rs. Also includes a hello-world and postgres example.
  • Loading branch information
trezm committed Oct 17, 2022
1 parent 2d67c6b commit 6242eac
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 13 deletions.
19 changes: 11 additions & 8 deletions cargo-shuttle/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,29 +137,32 @@ pub struct RunArgs {
#[derive(Parser, Debug)]
pub struct InitArgs {
/// Initialize with axum framework
#[clap(long, conflicts_with_all = &["rocket", "tide", "tower", "poem", "serenity", "warp", "salvo"])]
#[clap(long, conflicts_with_all = &["rocket", "tide", "tower", "poem", "serenity", "warp", "salvo", "thruster"])]
pub axum: bool,
/// Initialize with rocket framework
#[clap(long, conflicts_with_all = &["axum", "tide", "tower", "poem", "serenity", "warp", "salvo"])]
#[clap(long, conflicts_with_all = &["axum", "tide", "tower", "poem", "serenity", "warp", "salvo", "thruster"])]
pub rocket: bool,
/// Initialize with tide framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tower", "poem", "serenity", "warp", "salvo"])]
#[clap(long, conflicts_with_all = &["axum", "rocket", "tower", "poem", "serenity", "warp", "salvo", "thruster"])]
pub tide: bool,
/// Initialize with tower framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "poem", "serenity", "warp", "salvo"])]
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "poem", "serenity", "warp", "salvo", "thruster"])]
pub tower: bool,
/// Initialize with poem framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "serenity", "warp", "salvo"])]
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "serenity", "warp", "salvo", "thruster"])]
pub poem: bool,
/// Initialize with salvo framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "warp", "serenity"])]
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "warp", "serenity", "thruster"])]
pub salvo: bool,
/// Initialize with serenity framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "warp", "salvo"])]
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "thruster"])]
pub serenity: bool,
/// Initialize with warp framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "serenity", "salvo"])]
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "serenity", "salvo", "thruster"])]
pub warp: bool,
/// Initialize with thruster framework
#[clap(long, conflicts_with_all = &["axum", "rocket", "tide", "tower", "poem", "warp", "salvo", "serenity"])]
pub thruster: bool,
/// Path to initialize a new shuttle project
#[clap(
parse(try_from_os_str = parse_init_path),
Expand Down
98 changes: 96 additions & 2 deletions cargo-shuttle/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl ShuttleInit for ShuttleInitPoem {
#[shuttle_service::main]
async fn poem() -> shuttle_service::ShuttlePoem<impl poem::Endpoint> {
let app = Route::new().at("/hello", get(hello_world));
Ok(app)
}"#}
}
Expand Down Expand Up @@ -481,6 +481,61 @@ impl ShuttleInit for ShuttleInitWarp {
}
}

pub struct ShuttleInitThruster;

impl ShuttleInit for ShuttleInitThruster {
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!["web-thruster".to_string()],
);

set_inline_table_dependency_version(
"thruster",
dependencies,
manifest_path,
url,
false,
get_dependency_version_fn,
);

set_inline_table_dependency_features(
"thruster",
dependencies,
vec!["hyper_server".to_string()],
);
}

fn get_boilerplate_code_for_framework(&self) -> &'static str {
indoc! {r#"
use thruster::{
context::basic_hyper_context::{generate_context, BasicHyperContext as Ctx, HyperRequest},
m, middleware_fn, App, HyperServer, MiddlewareNext, MiddlewareResult, ThrusterServer,
};
#[middleware_fn]
async fn hello(mut context: Ctx, _next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
context.body("Hello, World!");
Ok(context)
}
#[shuttle_service::main]
async fn thruster() -> shuttle_service::ShuttleThruster<HyperServer<Ctx, ()>> {
Ok(HyperServer::new(
App::<HyperRequest, Ctx, ()>::create(generate_context, ()).get("/hello", m![hello]),
))
}
"#}
}
}

pub struct ShuttleInitNoOp;
impl ShuttleInit for ShuttleInitNoOp {
fn set_cargo_dependencies(
Expand Down Expand Up @@ -533,6 +588,10 @@ pub fn get_framework(init_args: &InitArgs) -> Box<dyn ShuttleInit> {
return Box::new(ShuttleInitWarp);
}

if init_args.thruster {
return Box::new(ShuttleInitThruster);
}

Box::new(ShuttleInitNoOp)
}

Expand Down Expand Up @@ -691,6 +750,7 @@ mod shuttle_init_tests {
salvo: false,
serenity: false,
warp: false,
thruster: false,
path: PathBuf::new(),
};

Expand All @@ -703,6 +763,7 @@ mod shuttle_init_tests {
"salvo" => init_args.salvo = true,
"serenity" => init_args.serenity = true,
"warp" => init_args.warp = true,
"thruster" => init_args.thruster = true,
_ => unreachable!(),
}

Expand All @@ -729,7 +790,7 @@ mod shuttle_init_tests {
#[test]
fn test_get_framework_via_get_boilerplate_code() {
let frameworks = vec![
"axum", "rocket", "tide", "tower", "poem", "salvo", "serenity", "warp",
"axum", "rocket", "tide", "tower", "poem", "salvo", "serenity", "warp", "thruster",
];
let framework_inits: Vec<Box<dyn ShuttleInit>> = vec![
Box::new(ShuttleInitAxum),
Expand All @@ -740,6 +801,7 @@ mod shuttle_init_tests {
Box::new(ShuttleInitSalvo),
Box::new(ShuttleInitSerenity),
Box::new(ShuttleInitWarp),
Box::new(ShuttleInitThruster),
];

for (framework, expected_framework_init) in frameworks.into_iter().zip(framework_inits) {
Expand Down Expand Up @@ -1079,6 +1141,38 @@ mod shuttle_init_tests {
assert_eq!(cargo_toml.to_string(), expected);
}

#[test]
fn test_set_cargo_dependencies_thruster() {
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,
);

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

let expected = indoc! {r#"
[dependencies]
shuttle-service = { version = "1.0", features = ["web-thruster"] }
thruster = { version = "1.0", features = ["hyper_server"] }
"#};

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

#[test]
/// Makes sure that Rocket uses allow_prerelease flag when fetching the latest version
fn test_get_latest_dependency_version_rocket() {
Expand Down
8 changes: 5 additions & 3 deletions cargo-shuttle/tests/integration/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ async fn cargo_shuttle_init(path: PathBuf) -> anyhow::Result<CommandOutcome> {
salvo: false,
serenity: false,
warp: false,
thruster: false,
path,
}),
})
Expand All @@ -53,6 +54,7 @@ async fn cargo_shuttle_init_framework(path: PathBuf) -> anyhow::Result<CommandOu
salvo: false,
serenity: false,
warp: false,
thruster: false,
path,
}),
})
Expand Down Expand Up @@ -93,16 +95,16 @@ async fn framework_init() {
let expected = indoc! {r#"
#[macro_use]
extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
#[shuttle_service::main]
async fn rocket() -> shuttle_service::ShuttleRocket {
let rocket = rocket::build().mount("/hello", routes![index]);
Ok(rocket)
}"#};

Expand Down
10 changes: 10 additions & 0 deletions examples/thruster/hello-world/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"

[lib]

[dependencies]
shuttle-service = { version = "0.5.2", features = ["web-thruster"] }
thruster = { version = "1.2.6", features = ["hyper_server"] }
1 change: 1 addition & 0 deletions examples/thruster/hello-world/Shuttle.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name = "hello-world-thruster-app"
17 changes: 17 additions & 0 deletions examples/thruster/hello-world/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use thruster::{
context::basic_hyper_context::{generate_context, BasicHyperContext as Ctx, HyperRequest},
m, middleware_fn, App, HyperServer, MiddlewareNext, MiddlewareResult, ThrusterServer,
};

#[middleware_fn]
async fn hello(mut context: Ctx, _next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
context.body("Hello, World!");
Ok(context)
}

#[shuttle_service::main]
async fn thruster() -> shuttle_service::ShuttleThruster<HyperServer<Ctx, ()>> {
Ok(HyperServer::new(
App::<HyperRequest, Ctx, ()>::create(generate_context, ()).get("/hello", m![hello]),
))
}
17 changes: 17 additions & 0 deletions examples/thruster/postgres/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "postgres"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
hyper = "0.14.20"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
shuttle-aws-rds = { version = "0.5.2", features = ["postgres"] }
shuttle-service = { version = "0.5.2", features = ["web-thruster"] }
sqlx = { version = "0.6", features = ["runtime-tokio-native-tls", "postgres"] }
thruster = { version = "1.2.6", features = ["hyper_server"] }
1 change: 1 addition & 0 deletions examples/thruster/postgres/Shuttle.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name = "postgres-tide-app"
6 changes: 6 additions & 0 deletions examples/thruster/postgres/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DROP TABLE IF EXISTS todos;

CREATE TABLE todos (
id serial PRIMARY KEY,
note TEXT NOT NULL
);
Loading

0 comments on commit 6242eac

Please sign in to comment.