Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extract service integrations into separate crates #702

Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9508d42
feat: draft of extracting service integrations
oddgrd Mar 10, 2023
5bde6a3
refactor: revert codegen changes
oddgrd Mar 10, 2023
275c632
refactor: depend on shuttle_runtime & service integration
oddgrd Mar 10, 2023
2788e9a
feat: remove rocket bin, comment out version check
oddgrd Mar 10, 2023
ff57736
feat: impl from for integration wrapper
oddgrd Mar 10, 2023
966eb3c
feat: cleanup shuttle-axum docs, remove version check
oddgrd Mar 11, 2023
994b9cc
feat: actix-web service integration
oddgrd Mar 11, 2023
19ef966
feat: extract poem service integration
oddgrd Mar 11, 2023
c6d2033
feat: extract poise service integration
oddgrd Mar 11, 2023
017c9c2
feat: extract rocket service integration
oddgrd Mar 11, 2023
3257234
feat: extract salvo service integration
oddgrd Mar 11, 2023
d042562
feat: extract the serenity service integration
oddgrd Mar 11, 2023
68955b9
feat: extract the thruster service integration
oddgrd Mar 11, 2023
916f989
feat: extract warp service integration
oddgrd Mar 11, 2023
94531de
feat: extract the tower service integration
oddgrd Mar 11, 2023
3b66433
feat: delete persist from service
oddgrd Mar 11, 2023
a9128f8
feat: extract tide service integration
oddgrd Mar 11, 2023
f0aefe2
feat: update cargo.lock
oddgrd Mar 11, 2023
5659b23
Merge branch 'shuttle-next' into feature/eng-490-extract-the-service-…
oddgrd Mar 11, 2023
131cf6b
feat: make service integration inner pub
oddgrd Mar 11, 2023
41e0127
Merge remote-tracking branch 'upstream/shuttle-next' into feature/eng…
oddgrd Mar 13, 2023
22a6a23
fix: merge fixes
oddgrd Mar 13, 2023
830c2d1
refactor: rename integrations, remove comment
oddgrd Mar 13, 2023
6b03a74
ci: run check-standalone on services
oddgrd Mar 13, 2023
fbd88ff
Merge branch 'shuttle-next' into feature/eng-490-extract-the-service-…
oddgrd Mar 13, 2023
6ae1d49
feat: update test resources
oddgrd Mar 13, 2023
eecda1e
ci: refactor workspace-clippy job
oddgrd Mar 13, 2023
5ab7994
fix: add tokio dev dep to services
oddgrd Mar 13, 2023
4dfc724
fix: remaining services tests
oddgrd Mar 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,044 changes: 401 additions & 2,643 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ exclude = [
"resources/persist",
"resources/secrets",
"resources/shared-db",
"resources/static-folder"
"resources/static-folder",
"integrations"
oddgrd marked this conversation as resolved.
Show resolved Hide resolved
]

[workspace.package]
Expand Down
56 changes: 28 additions & 28 deletions codegen/src/shuttle_main/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct Input {
/// The identifier for a resource input
ident: Ident,

/// The shuttle_service builder for this resource
/// The shuttle_runtime builder for this resource
builder: Builder,
}

Expand Down Expand Up @@ -144,9 +144,9 @@ fn check_return_type(signature: Signature) -> Option<TypePath> {
ReturnType::Default => {
emit_error!(
signature,
"shuttle_service::main functions need to return a service";
"shuttle_runtime::main functions need to return a service";
hint = "See the docs for services with first class support";
doc = "https://docs.rs/shuttle-service/latest/shuttle_service/attr.main.html#shuttle-supported-services"
doc = "https://docs.rs/shuttle-service/latest/shuttle_runtime/attr.main.html#shuttle-supported-services"
);
None
}
Expand All @@ -155,9 +155,9 @@ fn check_return_type(signature: Signature) -> Option<TypePath> {
_ => {
emit_error!(
r#type,
"shuttle_service::main functions need to return a first class service or 'Result<impl Service, shuttle_service::Error>";
"shuttle_runtime::main functions need to return a first class service or 'Result<impl Service, shuttle_runtime::Error>";
hint = "See the docs for services with first class support";
doc = "https://docs.rs/shuttle-service/latest/shuttle_service/attr.main.html#shuttle-supported-services"
doc = "https://docs.rs/shuttle-service/latest/shuttle_runtime/attr.main.html#shuttle-supported-services"
);
None
}
Expand Down Expand Up @@ -213,7 +213,7 @@ impl ToTokens for Loader {
None
} else {
Some(parse_quote!(
use shuttle_service::ResourceBuilder;
use shuttle_runtime::ResourceBuilder;
))
};

Expand All @@ -222,16 +222,16 @@ impl ToTokens for Loader {
mut #factory_ident: shuttle_runtime::ProvisionerFactory<S>,
logger: shuttle_runtime::Logger,
) -> #return_type {
use shuttle_service::Context;
use shuttle_service::tracing_subscriber::prelude::*;
use shuttle_runtime::Context;
use shuttle_runtime::tracing_subscriber::prelude::*;
#extra_imports

let filter_layer =
shuttle_service::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_service::tracing_subscriber::EnvFilter::try_new("INFO"))
shuttle_runtime::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_runtime::tracing_subscriber::EnvFilter::try_new("INFO"))
.unwrap();

shuttle_service::tracing_subscriber::registry()
shuttle_runtime::tracing_subscriber::registry()
.with(filter_layer)
.with(logger)
.init();
Expand Down Expand Up @@ -281,15 +281,15 @@ mod tests {
mut _factory: shuttle_runtime::ProvisionerFactory<S>,
logger: shuttle_runtime::Logger,
) -> ShuttleSimple {
use shuttle_service::Context;
use shuttle_service::tracing_subscriber::prelude::*;
use shuttle_runtime::Context;
use shuttle_runtime::tracing_subscriber::prelude::*;

let filter_layer =
shuttle_service::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_service::tracing_subscriber::EnvFilter::try_new("INFO"))
shuttle_runtime::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_runtime::tracing_subscriber::EnvFilter::try_new("INFO"))
.unwrap();

shuttle_service::tracing_subscriber::registry()
shuttle_runtime::tracing_subscriber::registry()
.with(filter_layer)
.with(logger)
.init();
Expand Down Expand Up @@ -361,16 +361,16 @@ mod tests {
mut factory: shuttle_runtime::ProvisionerFactory<S>,
logger: shuttle_runtime::Logger,
) -> ShuttleComplex {
use shuttle_service::Context;
use shuttle_service::tracing_subscriber::prelude::*;
use shuttle_service::ResourceBuilder;
use shuttle_runtime::Context;
use shuttle_runtime::tracing_subscriber::prelude::*;
use shuttle_runtime::ResourceBuilder;

let filter_layer =
shuttle_service::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_service::tracing_subscriber::EnvFilter::try_new("INFO"))
shuttle_runtime::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_runtime::tracing_subscriber::EnvFilter::try_new("INFO"))
.unwrap();

shuttle_service::tracing_subscriber::registry()
shuttle_runtime::tracing_subscriber::registry()
.with(filter_layer)
.with(logger)
.init();
Expand Down Expand Up @@ -489,16 +489,16 @@ mod tests {
mut factory: shuttle_runtime::ProvisionerFactory<S>,
logger: shuttle_runtime::Logger,
) -> ShuttleComplex {
use shuttle_service::Context;
use shuttle_service::tracing_subscriber::prelude::*;
use shuttle_service::ResourceBuilder;
use shuttle_runtime::Context;
use shuttle_runtime::tracing_subscriber::prelude::*;
use shuttle_runtime::ResourceBuilder;

let filter_layer =
shuttle_service::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_service::tracing_subscriber::EnvFilter::try_new("INFO"))
shuttle_runtime::tracing_subscriber::EnvFilter::try_from_default_env()
.or_else(|_| shuttle_runtime::tracing_subscriber::EnvFilter::try_new("INFO"))
.unwrap();

shuttle_service::tracing_subscriber::registry()
shuttle_runtime::tracing_subscriber::registry()
.with(filter_layer)
.with(logger)
.init();
Expand Down
5 changes: 5 additions & 0 deletions integrations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Service Integrations
The list of supported frameworks for shuttle is always growing. If you feel we are missing a framework you would like, then feel to create a feature request for your desired framework.

## Writing your own service integration
Creating your own service integration is quite simple. You only need to implement the [`Service`](https://docs.rs/shuttle-service/latest/shuttle_service/trait.Service.html) trait for your framework.
12 changes: 12 additions & 0 deletions integrations/shuttle-actix-web/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "shuttle-actix-web"
version = "0.1.0"
edition = "2021"

[workspace]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
actix-web = { version = "4.3.1" }
shuttle-runtime = { path = "../../runtime", version = "0.1.0" }
num_cpus = "1.15.0"
60 changes: 60 additions & 0 deletions integrations/shuttle-actix-web/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! Shuttle service integration for the Actix Web framework.
//! ## Example
//! ```rust,no_run
//! use actix_web::{get, web::ServiceConfig};
//! use shuttle_actix_web::ShuttleActixWeb;
//!
//! #[get("/hello")]
//! async fn hello_world() -> &'static str {
//! "Hello World!"
//! }
//!
//! #[shuttle_runtime::main]
//! async fn actix_web(
//! ) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static> {
//! let config = move |cfg: &mut ServiceConfig| {
//! cfg.service(hello_world);
//! };
//!
//! Ok(config.into())
//! }
//! ```
use std::net::SocketAddr;

/// A wrapper type for a closure that returns an [actix_web::web::ServiceConfig] so we can implement
/// [shuttle_runtime::Service] for it.
#[derive(Clone)]
pub struct ActixWebService<F>(pub F);

#[shuttle_runtime::async_trait]
impl<F> shuttle_runtime::Service for ActixWebService<F>
where
F: FnOnce(&mut actix_web::web::ServiceConfig) + Send + Clone + 'static,
{
async fn bind(mut self, addr: SocketAddr) -> Result<(), shuttle_runtime::Error> {
// Start a worker for each cpu, but no more than 4.
let worker_count = num_cpus::get().min(4);

let server =
actix_web::HttpServer::new(move || actix_web::App::new().configure(self.0.clone()))
.workers(worker_count)
.bind(addr)?
.run();

server.await.map_err(shuttle_runtime::CustomError::new)?;

Ok(())
}
}

impl<F> From<F> for ActixWebService<F>
where
F: FnOnce(&mut actix_web::web::ServiceConfig) + Send + Clone + 'static,
{
fn from(service_config: F) -> Self {
Self(service_config)
}
}

/// The return type that should be returned from the [shuttle_runtime::main] function.
pub type ShuttleActixWeb<F> = Result<ActixWebService<F>, shuttle_runtime::Error>;
11 changes: 11 additions & 0 deletions integrations/shuttle-axum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "shuttle-axum"
version = "0.1.0"
edition = "2021"

[workspace]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
axum = { version = "0.6.10" }
shuttle-runtime = { path = "../../runtime", version = "0.1.0" }
43 changes: 43 additions & 0 deletions integrations/shuttle-axum/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! Shuttle service integration for the Axum web framework.
//! ## Example
//! ```rust,no_run
//! use axum::{routing::get, Router};
//!
//! async fn hello_world() -> &'static str {
//! "Hello, world!"
//! }
//!
//! #[shuttle_runtime::main]
//! async fn axum() -> shuttle_axum::ShuttleAxum {
//! let router = Router::new().route("/hello", get(hello_world));
//!
//! Ok(router.into())
//! }
//! ```
use shuttle_runtime::{CustomError, Error};
use std::net::SocketAddr;

/// A wrapper type for [axum::Router] so we can implement [shuttle_runtime::Service] for it.
pub struct AxumService(pub axum::Router);

#[shuttle_runtime::async_trait]
impl shuttle_runtime::Service for AxumService {
/// Takes the router that is returned by the user in their [shuttle_runtime::main] function
/// and binds to an address passed in by shuttle.
async fn bind(mut self, addr: SocketAddr) -> Result<(), Error> {
axum::Server::bind(&addr)
.serve(self.0.into_make_service())
.await
.map_err(CustomError::new)?;

Ok(())
}
}

impl From<axum::Router> for AxumService {
fn from(router: axum::Router) -> Self {
Self(router)
}
}
/// The return type that should be returned from the [shuttle_runtime::main] function.
pub type ShuttleAxum = Result<AxumService, Error>;
11 changes: 11 additions & 0 deletions integrations/shuttle-poem/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "shuttle-poem"
version = "0.1.0"
edition = "2021"

[workspace]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
poem = { version = "1.3.55" }
shuttle-runtime = { path = "../../runtime", version = "0.1.0" }
49 changes: 49 additions & 0 deletions integrations/shuttle-poem/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Shuttle service integration for the Poem web framework.
//! ## Example
//! ```rust,no_run
//! use poem::{get, handler, Route};
//! use shuttle_poem::ShuttlePoem;
//!
//! #[handler]
//! fn hello_world() -> &'static str {
//! "Hello, world!"
//! }
//!
//! #[shuttle_runtime::main]
//! async fn poem() -> ShuttlePoem<impl poem::Endpoint> {
//! let app = Route::new().at("/hello", get(hello_world));
//!
//! Ok(app.into())
//! }
//!
//! ```

/// A wrapper type for [poem::Endpoint] so we can implement [shuttle_runtime::Service] for it.
pub struct PoemService<T>(pub T);

#[shuttle_runtime::async_trait]
impl<T> shuttle_runtime::Service for PoemService<T>
where
T: poem::Endpoint + Send + 'static,
{
async fn bind(mut self, addr: std::net::SocketAddr) -> Result<(), shuttle_runtime::Error> {
poem::Server::new(poem::listener::TcpListener::bind(addr))
.run(self.0)
.await
.map_err(shuttle_runtime::CustomError::new)?;

Ok(())
}
}

impl<T> From<T> for PoemService<T>
where
T: poem::Endpoint + Send + 'static,
{
fn from(router: T) -> Self {
Self(router)
}
}

/// The return type that should be returned from the [shuttle_runtime::main] function.
pub type ShuttlePoem<T> = Result<PoemService<T>, shuttle_runtime::Error>;
11 changes: 11 additions & 0 deletions integrations/shuttle-poise/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "shuttle-poise"
version = "0.1.0"
edition = "2021"

[workspace]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
poise = { version = "0.5.2" }
shuttle-runtime = { path = "../../runtime", version = "0.1.0" }
Loading