|
1 |
| -use std::net::SocketAddr; |
| 1 | +mod config; |
2 | 2 |
|
3 |
| -use config::load_config; |
| 3 | +use axum::{ |
| 4 | + body::{Body, Bytes}, |
| 5 | + extract::{Path, Request, State}, |
| 6 | + response::{IntoResponse, Response}, |
| 7 | + routing::any, |
| 8 | + Json, Router, |
| 9 | +}; |
| 10 | +use axum_macros::debug_handler; |
| 11 | +use dotenv::dotenv; |
| 12 | +use http::{header, StatusCode}; |
| 13 | +use reqwest::Method; |
| 14 | +use tokio::net::TcpListener; |
4 | 15 |
|
5 |
| -mod config; |
| 16 | +use crate::config::GatewayConfig; |
6 | 17 |
|
7 | 18 | #[tokio::main]
|
8 | 19 | async fn main() {
|
9 |
| - let config = load_config("gateway_config.toml"); |
10 |
| - let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); |
11 |
| - println!("config:{:?}, addr:{:?}", config, addr); |
| 20 | + dotenv().ok(); |
| 21 | + let config = config::load_config("gateway_config.toml"); |
| 22 | + |
| 23 | + // TODO add middleware to match service name and hit auth middleware if not bypassed for service |
| 24 | + let app = Router::new() |
| 25 | + .route("/:service/*destination", any(handle_inbound_req)) |
| 26 | + .with_state(config); |
| 27 | + |
| 28 | + let host = std::env::var("GATEWAY_HOST").unwrap(); |
| 29 | + let port = std::env::var("GATEWAY_PORT").unwrap(); |
| 30 | + let listener = TcpListener::bind(format!("{}:{}", host, port)) |
| 31 | + .await |
| 32 | + .unwrap(); |
| 33 | + axum::serve(listener, app).await.unwrap(); |
| 34 | +} |
| 35 | + |
| 36 | +#[debug_handler] |
| 37 | +async fn handle_inbound_req( |
| 38 | + State(config): State<GatewayConfig>, |
| 39 | + Path((service_name, dest)): Path<(String, String)>, |
| 40 | + inbound_req: Request, |
| 41 | +) -> Response { |
| 42 | + match config.services.get(&service_name) { |
| 43 | + Some(service) => { |
| 44 | + let client = reqwest::Client::new(); |
| 45 | + let method = Method::from_bytes(inbound_req.method().as_str().as_bytes()) |
| 46 | + .expect("Unable to parse request method"); |
| 47 | + |
| 48 | + let req = client.request( |
| 49 | + method, |
| 50 | + format!("{}:{}/{}", service.host, service.port, dest), |
| 51 | + ); |
| 52 | + |
| 53 | + //TODO get responses right - try to pass the reqwest response straight through |
| 54 | + // TODO figure out best way to return a 404 if service name not found |
| 55 | + // ? Might be better to build a middleware that extracts service name and mounts service on the router and 404s otherwise rather than do it in the handler. That way by the time we get to a handler the service is already in the route state. I think this is the way. |
| 56 | + let res = req.send().await.unwrap(); |
| 57 | + let res_headers = res.headers(); |
| 58 | + let content_type = res_headers.get("Content-Type").unwrap(); |
| 59 | + res.bytes().await.unwrap().into_response() |
| 60 | + } |
| 61 | + None => StatusCode::NOT_FOUND.into_response(), |
| 62 | + } |
12 | 63 | }
|
0 commit comments