Skip to content

Commit 3ed95f1

Browse files
ghubertpaloDamien LACHAUME / PALO-IT
authored andcommitted
add statistics route
1 parent 1042b46 commit 3ed95f1

File tree

5 files changed

+89
-15
lines changed

5 files changed

+89
-15
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-fake-aggregator/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ tokio = { version = "1.35.0", features = ["full"] }
2323
tower-http = { version = "0.5.0", features = ["trace"] }
2424
tracing = "0.1.40"
2525
tracing-subscriber = "0.3.18"
26+
27+
[dev-dependencies]
28+
mithril-common = { path = "../mithril-common", features = ["full"] }
29+
reqwest = "0.11.23"

mithril-fake-aggregator/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Mithril Fake Aggregator
2+
3+
This software is made to test Mithril Client nodes in isolated situations where no real Mithril Aggregator can be reached. It serves a static set of data that can be loaded at start time.
4+
5+
## Fake API
6+
7+
For now, the following routes are implemented:
8+
9+
* GET /aggregator/epoch-settings
10+
* GET /aggregator/certificates
11+
* GET /aggregator/certificate/:hash
12+
* GET /aggregator/artifact/snapshots
13+
* GET /aggregator/artifact/snapshot/:digest
14+
* GET /aggregator/artifact/mithril-stake-distributions/
15+
* GET /aggregator/artifact/mithril-stake-distribution/:hash
16+
17+
## Data fixtures
18+
19+
It is either possible to use default data provided with the binary or to load a static set of data at start up using the `-d` or `--data-dir` option. When set the given directory is scanned for the following files:
20+
21+
* certificates.json
22+
* snapshots.json
23+
* mithril-stake-distributions.json
24+
25+
For each file, the identifiers of the corresponding artifacts are extracted and the following files are read:
26+
27+
* certificate-{hash}.json
28+
* snapshot-{digest}.json
29+
* mithril-stake-distribution-{hash}.json
30+
31+
If a file is missing or incomplete, the software will stop with an error message.
32+
33+
## Command line synopsis
34+
35+
Usage: `mithril-fake-aggregator [OPTIONS]`
36+
37+
Options:
38+
39+
```
40+
-d, --data-directory <DATA_DIRECTORY> Directory where the response files are located
41+
-v, --verbose... Verbose mode (-q, -v, -vv, -vvv, etc)
42+
-p, --tcp-port <TCP_PORT> TCP port to listen on [default: 80]
43+
-i, --ip-address <IP_ADDRESS> IP Address to bind server to [default: 127.0.0.1]
44+
-h, --help Print help
45+
-V, --version Print version
46+
```

mithril-fake-aggregator/src/handlers.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use axum::{
22
body::Body,
33
extract::{Path, State},
4-
http::Response,
4+
http::{Response, StatusCode},
55
response::IntoResponse,
66
};
77

@@ -74,3 +74,9 @@ pub async fn certificate(
7474
.map(|s| s.into_response())
7575
.ok_or_else(|| AppError::NotFound(format!("certificate hash={key}")))
7676
}
77+
78+
pub async fn statistics() -> Result<Response<Body>, AppError> {
79+
let response = Response::builder().status(StatusCode::CREATED);
80+
81+
response.body(String::new().into()).map_err(|e| e.into())
82+
}

mithril-fake-aggregator/src/main.rs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use axum::{
1010
http::{HeaderValue, Response, StatusCode},
1111
middleware::{self, Next},
1212
response::IntoResponse,
13-
routing::get,
13+
routing::{get, post},
1414
Router,
1515
};
1616
use clap::Parser;
@@ -35,7 +35,7 @@ pub struct CliArguments {
3535
#[arg(short, long)]
3636
data_directory: Option<PathBuf>,
3737

38-
/// Verbose mode (-q, -v, -vv, -vvv, etc)
38+
/// Verbosity level (-v WARN, -vv INFO, -vvv DEBUG, etc)
3939
#[arg(short, long, action = clap::ArgAction::Count)]
4040
verbose: u8,
4141

@@ -46,16 +46,24 @@ pub struct CliArguments {
4646
/// IP Address to bind server to
4747
#[arg(short, long, default_value = "127.0.0.1")]
4848
ip_address: String,
49+
50+
/// Quiet mode, no log will be emitted. Critical error messages will still pop on STDERR
51+
#[arg(short, long, default_value_t = false)]
52+
quiet: bool,
4953
}
5054

5155
impl CliArguments {
52-
pub fn get_verbosity_level(&self) -> Level {
53-
match self.verbose {
54-
0 => Level::ERROR,
55-
1 => Level::WARN,
56-
2 => Level::INFO,
57-
3 => Level::DEBUG,
58-
_ => Level::TRACE,
56+
pub fn get_verbosity_level(&self) -> Option<Level> {
57+
if self.quiet {
58+
None
59+
} else {
60+
match self.verbose {
61+
0 => Some(Level::ERROR),
62+
1 => Some(Level::WARN),
63+
2 => Some(Level::INFO),
64+
3 => Some(Level::DEBUG),
65+
_ => Some(Level::TRACE),
66+
}
5967
}
6068
}
6169
}
@@ -121,9 +129,10 @@ impl OsSignalHandler {
121129
#[tokio::main]
122130
async fn main() -> StdResult<()> {
123131
let params = CliArguments::parse();
124-
tracing_subscriber::fmt()
125-
.with_max_level(params.get_verbosity_level())
126-
.init();
132+
133+
if let Some(level) = params.get_verbosity_level() {
134+
tracing_subscriber::fmt().with_max_level(level).init();
135+
}
127136

128137
let result = Application::run(params).await;
129138

@@ -180,13 +189,17 @@ impl Application {
180189
)
181190
.route("/aggregator/certificates", get(handlers::certificates))
182191
.route("/aggregator/certificate/:hash", get(handlers::certificate))
192+
.route(
193+
"/aggregator/statistics/snapshot",
194+
post(handlers::statistics),
195+
)
183196
.with_state(shared_state.clone())
184197
.layer(middleware::from_fn(set_json_app_header))
185198
.layer(
186199
TraceLayer::new_for_http()
187200
.make_span_with(
188201
DefaultMakeSpan::new()
189-
.include_headers(true)
202+
.include_headers(false)
190203
.level(Level::DEBUG),
191204
)
192205
.on_request(DefaultOnRequest::new().level(Level::DEBUG))
@@ -199,7 +212,7 @@ impl Application {
199212
);
200213
let listener = {
201214
let connection_string = format!("{}:{}", params.ip_address, params.tcp_port);
202-
info!("binding on {connection_string}");
215+
debug!("binding on {connection_string}");
203216
tokio::net::TcpListener::bind(&connection_string)
204217
.await
205218
.with_context(|| format!("Could not listen on '{}'.", connection_string))?
@@ -234,3 +247,6 @@ async fn set_json_app_header(
234247

235248
Ok(res)
236249
}
250+
251+
#[cfg(test)]
252+
mod tests {}

0 commit comments

Comments
 (0)