1use handle::handle_request;
2use hyper::service::service_fn;
3use hyper_util::{
4 rt::{TokioExecutor, TokioIo},
5 server::conn::auto::Builder,
6};
7use state::{Config, State, default_port};
8use std::{fs, net::SocketAddr, path::PathBuf, sync::Arc};
9use tokio::net::TcpListener;
10use tracing::{error, info};
11
12pub mod handle;
13pub mod latency;
14pub mod state;
15
16#[derive(Debug, clap::Parser)]
18#[clap(about, name = "subgraph-mock", long_about = None)]
19pub struct Args {
20 #[arg(short, long)]
22 pub config: Option<PathBuf>,
23
24 #[arg(short, long)]
26 pub schema: PathBuf,
27}
28
29impl Args {
30 pub fn init(self) -> anyhow::Result<(u16, State)> {
32 let (port, config) = match self.config {
33 Some(path) => {
34 info!(path=%path.display(), "loading and parsing config file");
35 Config::parse_yaml(serde_yaml::from_slice(&fs::read(path)?)?)?
36 }
37 None => {
38 info!("using default config");
39 (default_port(), Config::default())
40 }
41 };
42
43 Ok((port, State::new(config, self.schema)?))
44 }
45}
46
47pub async fn mock_server_loop(port: u16, state: State) -> anyhow::Result<()> {
49 let listener = TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], port))).await?;
50 info!(%port, "subgraph mock server now listening");
51
52 let state = Arc::new(state);
53 loop {
54 let (stream, _) = listener.accept().await?;
55 let io = TokioIo::new(stream);
56
57 let state = state.clone();
58 tokio::spawn(async move {
59 if let Err(err) = Builder::new(TokioExecutor::new())
60 .serve_connection(io, service_fn(|req| handle_request(req, state.clone())))
61 .await
62 {
63 error!(%err, "server error");
64 }
65 });
66 }
67}