-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
`cli` has been configured with a command to launch an http server using axum. `cargo run --bin annapurna-cli server http` can now launch a webserver. This expects a running instance of [lockpad](https://github.com/justinrubek/lockpad) or equivalent host running and its URL accessible in environment variable `ANNAPURNA_AUTH_URL`.
- Loading branch information
1 parent
63b0041
commit 9aa1260
Showing
10 changed files
with
1,682 additions
and
50 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,24 @@ | ||
[package] | ||
name = "annapurna-cli" | ||
name = "annapurna" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[[bin]] | ||
name = "annapurna-cli" | ||
path = "src/main.rs" | ||
|
||
[dependencies] | ||
annapurna-logic = { path = "../logic" } | ||
annapurna-http = { path = "../http" } | ||
clap = { version = "4.1.13", features = ["derive"] } | ||
config = "0.13.3" | ||
lockpad-auth = { path = "../../../lockpad/crates/auth" } | ||
ron = "0.8.0" | ||
# clap = { version = "4.0.19", features = ["derive"] } | ||
# reqwest = { version = "0.11.12", features = ["rustls-tls"] } | ||
serde = { version = "1", features = ["derive"] } | ||
serde_json = "1.0.87" | ||
tracing-subscriber = "0.3.16" | ||
reqwest = { version = "0.11.14", default-features = false, features = ["rustls-tls", "json"] } | ||
tokio.workspace = true | ||
# tokio = { version = "1", features = ["full"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use annapurna::config::Config; | ||
use lockpad_auth::PublicKey; | ||
|
||
#[derive(clap::Args, Debug)] | ||
pub(crate) struct ServerCommand { | ||
#[clap(subcommand)] | ||
pub command: ServerCommands, | ||
|
||
#[arg(default_value = "0.0.0.0:5000", long, short)] | ||
pub addr: std::net::SocketAddr, | ||
} | ||
|
||
#[derive(clap::Subcommand, Debug)] | ||
pub(crate) enum ServerCommands { | ||
/// start the http server | ||
Http, | ||
} | ||
|
||
impl ServerCommand { | ||
pub(crate) async fn run(&self) -> Result<(), Box<dyn std::error::Error>> { | ||
let config = Config::load()?; | ||
let auth_url = config.auth_url; | ||
|
||
let client = reqwest::Client::new(); | ||
let res = client | ||
.get(format!("{auth_url}/.well-known/jwks.json")) | ||
.send() | ||
.await | ||
.unwrap(); | ||
let jwks_str = res.text().await.unwrap(); | ||
|
||
let key_set = PublicKey::parse_from_jwks(&jwks_str)?; | ||
|
||
let server = annapurna_http::Server::builder() | ||
.addr(self.addr) | ||
.public_keys(key_set) | ||
.build()?; | ||
|
||
match self.command { | ||
ServerCommands::Http => server.run().await?, | ||
} | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] | ||
pub struct Config { | ||
pub auth_url: String, | ||
} | ||
|
||
impl Config { | ||
pub fn load() -> Result<Self, config::ConfigError> { | ||
let config = config::Config::builder() | ||
.add_source(config::Environment::with_prefix("ANNAPURNA")) | ||
.build()?; | ||
|
||
config.try_deserialize() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "annapurna-http" | ||
version.workspace = true | ||
edition.workspace = true | ||
|
||
[dependencies] | ||
axum = { workspace = true } | ||
hyper = "0.14.24" | ||
lockpad-auth = { path = "../../../lockpad/crates/auth" } | ||
serde = { workspace = true } | ||
serde_json = "1.0.87" | ||
thiserror = { workspace = true } | ||
tokio = { workspace = true } | ||
tower = { version = "0.4", features = ["util"] } | ||
tower-http = { version = "0.3.0", features = ["fs", "cors"] } | ||
tracing = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#[derive(thiserror::Error, Debug)] | ||
pub enum Error { | ||
#[error(transparent)] | ||
Hyper(#[from] hyper::Error), | ||
#[error(transparent)] | ||
LockpadAuth(#[from] lockpad_auth::error::Error), | ||
|
||
#[error("Failed to build server struct")] | ||
ServerBuilder, | ||
} | ||
|
||
pub type Result<T> = std::result::Result<T, Error>; | ||
|
||
impl axum::response::IntoResponse for Error { | ||
fn into_response(self) -> axum::response::Response { | ||
tracing::info!(?self, "error response"); | ||
#[allow(clippy::match_single_binding)] | ||
let status = match self { | ||
_ => axum::http::StatusCode::INTERNAL_SERVER_ERROR, | ||
}; | ||
|
||
(status, self.to_string()).into_response() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#[allow(unused_imports)] | ||
use axum::{ | ||
routing::{get, post}, | ||
Router, | ||
}; | ||
use lockpad_auth::PublicKey; | ||
use std::net::SocketAddr; | ||
|
||
pub mod error; | ||
|
||
use error::Result; | ||
|
||
pub struct Server { | ||
addr: SocketAddr, | ||
|
||
public_keys: Vec<PublicKey>, | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct ServerState { | ||
pub public_key: PublicKey, | ||
} | ||
|
||
impl AsRef<PublicKey> for ServerState { | ||
fn as_ref(&self) -> &PublicKey { | ||
&self.public_key | ||
} | ||
} | ||
|
||
impl Server { | ||
pub fn builder() -> Builder { | ||
Builder::default() | ||
} | ||
|
||
pub async fn run(self) -> Result<()> { | ||
let cors = tower_http::cors::CorsLayer::permissive(); | ||
|
||
let public_key = self.public_keys[0].clone(); | ||
let state = ServerState { public_key }; | ||
|
||
let app = Router::new() | ||
.route("/", get(root)) | ||
.with_state(state) | ||
.layer(cors); | ||
|
||
tracing::info!("Listening on {0}", self.addr); | ||
axum::Server::bind(&self.addr) | ||
.serve(app.into_make_service()) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
pub struct Builder { | ||
addr: Option<SocketAddr>, | ||
public_keys: Option<Vec<PublicKey>>, | ||
} | ||
|
||
impl Builder { | ||
pub fn new() -> Self { | ||
Self { | ||
addr: None, | ||
public_keys: None, | ||
} | ||
} | ||
|
||
pub fn addr(mut self, addr: SocketAddr) -> Self { | ||
self.addr = Some(addr); | ||
self | ||
} | ||
|
||
pub fn public_keys(mut self, public_keys: Vec<PublicKey>) -> Self { | ||
self.public_keys = Some(public_keys); | ||
self | ||
} | ||
|
||
pub fn build(self) -> Result<Server> { | ||
let addr = self.addr.ok_or(error::Error::ServerBuilder)?; | ||
let public_keys = self.public_keys.ok_or(error::Error::ServerBuilder)?; | ||
|
||
Ok(Server { addr, public_keys }) | ||
} | ||
} | ||
|
||
impl Default for Builder { | ||
fn default() -> Self { | ||
Self { | ||
addr: Some(SocketAddr::from(([0, 0, 0, 0], 3000))), | ||
public_keys: None, | ||
} | ||
} | ||
} | ||
|
||
async fn root() -> &'static str { | ||
"Hello, World!" | ||
} |