Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Commit 2c22569

Browse files
committed
support extensions
1 parent c2f420f commit 2c22569

File tree

5 files changed

+81
-10
lines changed

5 files changed

+81
-10
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ cld = "0.5"
1717
espresso-types = { git = "https://github.com/EspressoSystems/espresso-sequencer.git", branch = "main", features = [ "testing" ] }
1818
futures = "0.3"
1919
hotshot = { git = "https://github.com/EspressoSystems/HotShot.git", tag = "rc-0.5.61" }
20-
hotshot-events-service = { git = "https://github.com/EspressoSystems/hotshot-events-service.git", branch = "ab/remove-builder-event-types" }
20+
hotshot-events-service = { git = "https://github.com/EspressoSystems/hotshot-events-service.git", branch = "main" }
2121
hotshot-types = { git = "https://github.com/EspressoSystems/HotShot.git", tag = "rc-0.5.61" }
2222
serde = { version = "1.0", features = ["derive"] }
2323
snafu = "0.8"

src/api.rs

+74-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
use std::{
2+
fs,
3+
path::{Path, PathBuf},
4+
};
5+
16
use futures::FutureExt;
27
use serde::{Deserialize, Serialize};
38
use snafu::Snafu;
@@ -6,6 +11,7 @@ use tide_disco::{
611
method::{ReadState, WriteState},
712
Api, StatusCode,
813
};
14+
use toml::{map::Entry, Value};
915
use vbs::version::StaticVersionType;
1016

1117
use crate::state::UpdateSolverState;
@@ -27,18 +33,38 @@ impl tide_disco::Error for SolverError {
2733
}
2834
}
2935

30-
pub fn define_api<State, SolverError, VERSION>(
36+
pub struct ApiOptions {
37+
pub api_path: Option<PathBuf>,
38+
39+
/// Additional API specification files to merge with `availability-api-path`.
40+
///
41+
/// These optional files may contain route definitions for application-specific routes that have
42+
/// been added as extensions to the basic availability API.
43+
pub extensions: Vec<toml::Value>,
44+
}
45+
46+
impl Default for ApiOptions {
47+
fn default() -> Self {
48+
Self {
49+
api_path: None,
50+
extensions: vec![],
51+
}
52+
}
53+
}
54+
55+
pub fn define_api<State, VERSION>(
56+
options: ApiOptions,
3157
) -> Result<Api<State, SolverError, VERSION>, ApiError>
3258
where
3359
VERSION: StaticVersionType + 'static,
3460
State: 'static + Send + Sync + ReadState + WriteState,
3561
<State as ReadState>::State: Send + Sync + UpdateSolverState,
36-
SolverError: 'static,
3762
{
38-
let api_toml = toml::from_str::<toml::Value>(include_str!("../api/solver.toml"))
39-
.expect("API file is not valid toml");
40-
41-
let mut api = Api::new(api_toml)?;
63+
let mut api = load_api::<State, SolverError, VERSION>(
64+
options.api_path.as_ref(),
65+
include_str!("../api/solver.toml"),
66+
options.extensions.clone(),
67+
)?;
4268

4369
// TODO ED: We need to fill these in with the appropriate logic later
4470
api.post("submit_bid", |_req, _state| {
@@ -61,3 +87,45 @@ where
6187
})?;
6288
Ok(api)
6389
}
90+
91+
pub(crate) fn load_api<State: 'static, Error: 'static, Ver: StaticVersionType + 'static>(
92+
path: Option<impl AsRef<Path>>,
93+
default: &str,
94+
extensions: impl IntoIterator<Item = Value>,
95+
) -> Result<Api<State, Error, Ver>, ApiError> {
96+
let mut toml = match path {
97+
Some(path) => load_toml(path.as_ref())?,
98+
None => toml::from_str(default).map_err(|err| ApiError::CannotReadToml {
99+
reason: err.to_string(),
100+
})?,
101+
};
102+
for extension in extensions {
103+
merge_toml(&mut toml, extension);
104+
}
105+
Api::new(toml)
106+
}
107+
108+
fn merge_toml(into: &mut Value, from: Value) {
109+
if let (Value::Table(into), Value::Table(from)) = (into, from) {
110+
for (key, value) in from {
111+
match into.entry(key) {
112+
Entry::Occupied(mut entry) => merge_toml(entry.get_mut(), value),
113+
Entry::Vacant(entry) => {
114+
entry.insert(value);
115+
}
116+
}
117+
}
118+
}
119+
}
120+
121+
fn load_toml(path: &Path) -> Result<Value, ApiError> {
122+
let bytes = fs::read(path).map_err(|err| ApiError::CannotReadToml {
123+
reason: err.to_string(),
124+
})?;
125+
let string = std::str::from_utf8(&bytes).map_err(|err| ApiError::CannotReadToml {
126+
reason: err.to_string(),
127+
})?;
128+
toml::from_str(string).map_err(|err| ApiError::CannotReadToml {
129+
reason: err.to_string(),
130+
})
131+
}

src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub async fn main() {
1717
let mut app = App::<_, SolverError>::with_state(RwLock::new(GlobalState::mock()));
1818
app.with_version(env!("CARGO_PKG_VERSION").parse().unwrap());
1919

20-
let mut api = define_api()
20+
let mut api = define_api(Default::default())
2121
.map_err(|_e| io::Error::new(ErrorKind::Other, "Failed to define api"))
2222
.unwrap();
2323
api.with_version(env!("CARGO_PKG_VERSION").parse().unwrap());

src/options.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ use tide_disco::Url;
88
pub struct Options {
99
#[clap(long, env = "HOTSHOT_EVENTS_API_URL")]
1010
pub events_url: Url,
11+
12+
#[clap(flatten)]
13+
pub database_options: DatabaseOptions,
1114
}
1215

1316
/// Arguments for establishing a database connection
14-
#[derive(Debug, Parser)]
17+
#[derive(Clone, Debug, Parser)]
1518
pub struct DatabaseOptions {
1619
#[clap(long, env = "MARKETPLACE_SOLVER_DATABASE_URL")]
1720
pub url: String,

0 commit comments

Comments
 (0)