diff --git a/crates/flux-releaser/src/api.rs b/crates/flux-releaser/src/api.rs new file mode 100644 index 0000000..3991ac6 --- /dev/null +++ b/crates/flux-releaser/src/api.rs @@ -0,0 +1,20 @@ +use std::net::SocketAddr; + +use axum::{routing::get, Router}; + +use crate::app::SharedApp; + +pub async fn axum_serve(host: SocketAddr, app: SharedApp) -> anyhow::Result<()> { + let app = Router::new().route("/", get(root)).with_state(app); + + tracing::info!("listening on {}", host); + let listener = tokio::net::TcpListener::bind(host).await.unwrap(); + + axum::serve(listener, app.into_make_service()).await?; + + Ok(()) +} + +async fn root() -> &'static str { + "Hello, flux-releaser!" +} diff --git a/crates/flux-releaser/src/app.rs b/crates/flux-releaser/src/app.rs new file mode 100644 index 0000000..94c010a --- /dev/null +++ b/crates/flux-releaser/src/app.rs @@ -0,0 +1,38 @@ +use std::{ops::Deref, sync::Arc}; + +#[derive(Clone)] +pub struct SharedApp(Arc); + +impl Deref for SharedApp { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for SharedApp { + fn default() -> Self { + Self::new() + } +} + +impl SharedApp { + pub fn new() -> Self { + Self(Arc::new(App::new())) + } +} + +pub struct App {} + +impl Default for App { + fn default() -> Self { + Self::new() + } +} + +impl App { + pub fn new() -> Self { + Self {} + } +} diff --git a/crates/flux-releaser/src/cli.rs b/crates/flux-releaser/src/cli.rs new file mode 100644 index 0000000..27862a2 --- /dev/null +++ b/crates/flux-releaser/src/cli.rs @@ -0,0 +1,46 @@ +use clap::{Parser, Subcommand}; +use std::net::SocketAddr; + +use crate::{api::axum_serve, app::SharedApp, grpc::tonic_serve}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None, subcommand_required = true)] +pub struct Command { + #[command(subcommand)] + pub command: Option, +} + +#[derive(Subcommand)] +pub enum Commands { + Serve { + #[arg(env = "SERVICE_HOST", long, default_value = "127.0.0.1:3000")] + host: SocketAddr, + #[arg(env = "SERVICE_GRPC_HOST", long, default_value = "127.0.0.1:7900")] + grpc_host: SocketAddr, + }, +} + +impl Command { + pub async fn run() -> anyhow::Result<()> { + let cli = Command::parse(); + + if let Some(Commands::Serve { host, grpc_host }) = cli.command { + tracing_subscriber::fmt::init(); + + tracing::info!("Starting service"); + + let app = SharedApp::new(); + + tokio::select! { + res = axum_serve(host, app) => { + res?; + }, + res = tonic_serve(grpc_host) => { + res?; + }, + }; + } + + Ok(()) + } +} diff --git a/crates/flux-releaser/src/grpc.rs b/crates/flux-releaser/src/grpc.rs new file mode 100644 index 0000000..a694e30 --- /dev/null +++ b/crates/flux-releaser/src/grpc.rs @@ -0,0 +1,35 @@ +use std::net::SocketAddr; + +use tonic::transport::Server; + +use self::gen::{greeter_server, HelloReply, HelloRequest}; + +mod gen { + tonic::include_proto!("flux_releaser"); +} + +#[derive(Debug, Default)] +pub struct FluxReleaserGrpc {} +#[tonic::async_trait] +impl greeter_server::Greeter for FluxReleaserGrpc { + async fn say_hello( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + Ok(tonic::Response::new(HelloReply { + message: "something".into(), + })) + } +} + +pub async fn tonic_serve(host: SocketAddr) -> anyhow::Result<()> { + tracing::info!("grpc listening on: {}", host); + Server::builder() + .add_service(greeter_server::GreeterServer::new( + FluxReleaserGrpc::default(), + )) + .serve(host) + .await?; + + Ok(()) +} diff --git a/crates/flux-releaser/src/main.rs b/crates/flux-releaser/src/main.rs index d895113..bda7699 100644 --- a/crates/flux-releaser/src/main.rs +++ b/crates/flux-releaser/src/main.rs @@ -1,93 +1,17 @@ -use std::net::SocketAddr; +use cli::Command; -use axum::routing::get; -use axum::Router; -use clap::{Parser, Subcommand}; -use grpc::{greeter_server, HelloReply, HelloRequest}; -use tokio::net::TcpListener; -use tonic::transport::Server; +mod cli; -#[derive(Parser)] -#[command(author, version, about, long_about = None, subcommand_required = true)] -struct Command { - #[command(subcommand)] - command: Option, -} +mod api; +mod grpc; -#[derive(Subcommand)] -enum Commands { - Serve { - #[arg(env = "SERVICE_HOST", long, default_value = "127.0.0.1:3000")] - host: SocketAddr, - #[arg(env = "SERVICE_GRPC_HOST", long, default_value = "127.0.0.1:7900")] - grpc_host: SocketAddr, - }, -} - -async fn axum_serve(listener: TcpListener, app: Router) -> anyhow::Result<()> { - axum::serve(listener, app.into_make_service()).await?; - - Ok(()) -} - -mod grpc { - tonic::include_proto!("flux_releaser"); -} - -#[derive(Debug, Default)] -pub struct FluxReleaserGrpc {} -#[tonic::async_trait] -impl greeter_server::Greeter for FluxReleaserGrpc { - async fn say_hello( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - Ok(tonic::Response::new(HelloReply { - message: "something".into(), - })) - } -} - -async fn tonic_serve(host: SocketAddr) -> anyhow::Result<()> { - tracing::info!("grpc listening on: {}", host); - Server::builder() - .add_service(greeter_server::GreeterServer::new( - FluxReleaserGrpc::default(), - )) - .serve(host) - .await?; - - Ok(()) -} +mod app; #[tokio::main] async fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); - tracing_subscriber::fmt::init(); - let cli = Command::parse(); - - if let Some(Commands::Serve { host, grpc_host }) = cli.command { - tracing::info!("Starting service"); - - let app = Router::new().route("/", get(root)); - - tracing::info!("listening on {}", host); - let listener = tokio::net::TcpListener::bind(host).await.unwrap(); - - tokio::select! { - res = axum_serve(listener, app) => { - res?; - }, - res = tonic_serve(grpc_host) => { - res?; - }, - }; - } + Command::run().await?; Ok(()) } - -async fn root() -> &'static str { - "Hello, flux-releaser!" -}