Skip to content

2.5.0 #62

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

Merged
merged 4 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 47 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "apimock"
version = "2.4.3"
version = "2.5.0"
edition = "2021"
authors = ["nabbisen <[email protected]>"]
license = "ISC"
Expand All @@ -19,12 +19,14 @@ strip = true

[dependencies]
tokio = { version = "1", features = ["full"] }
hyper = { version = "0.14", features = ["server", "http1", "http2", "tcp"] }
hyper = { version = "1", features = ["server", "http1", "http2"] }
hyper-util = { version = "^0.1", features = ["server", "http1", "http2", "tokio"] }
http-body-util = "^0.1"
toml = "^0.8"
serde = "1"
serde_json = "1"
json5 = "^0.4"
console = "^0.15"

[dev-dependencies]
hyper = { version = "0.14", features = ["client"] }
hyper = { version = "1", features = ["client"] }
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

Mocking helper to develop microservices and APIs. [hyper](https://hyper.rs/)-based HTTP server generating REST responses containing JSON ones. Written in [Rust](https://www.rust-lang.org/).

With small single native binary, just run `./apimock` or `./apimock -c apimock.toml` to start the server !
With small native binary, just run `./apimock` or `./apimock -c apimock.toml` to start the server !

- [Install and usage](docs/INSTALL.md)

Expand Down
4 changes: 2 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use console::style;
use hyper::StatusCode;
use hyper::http::StatusCode;
use json5;
use serde_json;
use std::collections::HashMap;
Expand Down Expand Up @@ -81,7 +81,7 @@ impl Config {
} else {
config_path
};

let mut config = Self::default_config();

if config_path.is_empty() && !exists_default_config {
Expand Down
58 changes: 43 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,76 @@
use console::style;
use hyper::service::{make_service_fn, service_fn};
use hyper::Server;
use hyper::{body, body::Bytes, service::service_fn, Request, Response};
use hyper_util::{
rt::{TokioExecutor, TokioIo},
server::conn::auto::Builder,
};
use std::convert::Infallible;
use std::env;
use std::net::ToSocketAddrs;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::{net::TcpListener, sync::Mutex};

pub mod config;
mod server;
mod util;
use crate::config::Config;
use crate::server::handle;

type BoxBody = http_body_util::combinators::BoxBody<Bytes, Infallible>;

const APP_NAME: &str = "API mock";

/// start hyper http server
pub async fn start_server(config_path: String) -> Result<(), hyper::Error> {
pub async fn start_server(
config_path: String,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
println!("\nGreetings from {APP_NAME} !!\n");

let config = Config::new(&config_path);

let app_state = Arc::new(Mutex::new(config.clone()));
let make_svc = make_service_fn(|_| {
let app_state = Arc::clone(&app_state);
async move {
let service = service_fn(move |req| handle(req, Arc::clone(&app_state)));
Ok::<_, Infallible>(service)
}
});

let addr = config
.listen_address()
.to_socket_addrs()
.expect("invalid listend address or port")
.next()
.expect("failed to resolve address");
let server = Server::bind(&addr).serve(make_svc);
println!(
"\nListening on {} ...\n",
style(format!("http://{}", &addr)).cyan()
);
let app_state = Arc::new(Mutex::new(config.clone()));
let listener = TcpListener::bind(addr)
.await
.expect("tcp listener failed to bind address");
loop {
let (stream, _) = listener
.accept()
.await
.expect("tcp listener failed to accept");
let io = TokioIo::new(stream);

let app_state = app_state.clone();
tokio::task::spawn(async move {
// Finally, we bind the incoming connection to our `hello` service
if let Err(err) = Builder::new(TokioExecutor::new())
// `service_fn` converts our function in a `Service`
.serve_connection(
io,
service_fn(move |req: Request<body::Incoming>| service(req, app_state.clone())),
)
.await
{
eprintln!("error serving connection: {:?}", err);
}
});
}
}

server.await
async fn service(
req: Request<body::Incoming>,
app_state: Arc<Mutex<Config>>,
) -> Result<Response<BoxBody>, hyper::http::Error> {
handle(req, Arc::clone(&app_state)).await
}

/// app config path
Expand Down
Loading
Loading