hotshot_query_service/
api.rs1use std::{fs, path::Path};
14
15use tide_disco::api::{Api, ApiError};
16use toml::{map::Entry, Value};
17use vbs::version::StaticVersionType;
18
19pub(crate) fn load_api<State: 'static, Error: 'static, Ver: StaticVersionType + 'static>(
20 path: Option<impl AsRef<Path>>,
21 default: &str,
22 extensions: impl IntoIterator<Item = Value>,
23) -> Result<Api<State, Error, Ver>, ApiError> {
24 let mut toml = match path {
25 Some(path) => load_toml(path.as_ref())?,
26 None => toml::from_str(default).map_err(|err| ApiError::CannotReadToml {
27 reason: err.to_string(),
28 })?,
29 };
30 for extension in extensions {
31 merge_toml(&mut toml, extension);
32 }
33 Api::new(toml)
34}
35
36fn merge_toml(into: &mut Value, from: Value) {
37 if let (Value::Table(into), Value::Table(from)) = (into, from) {
38 for (key, value) in from {
39 match into.entry(key) {
40 Entry::Occupied(mut entry) => merge_toml(entry.get_mut(), value),
41 Entry::Vacant(entry) => {
42 entry.insert(value);
43 },
44 }
45 }
46 }
47}
48
49fn load_toml(path: &Path) -> Result<Value, ApiError> {
50 let bytes = fs::read(path).map_err(|err| ApiError::CannotReadToml {
51 reason: err.to_string(),
52 })?;
53 let string = std::str::from_utf8(&bytes).map_err(|err| ApiError::CannotReadToml {
54 reason: err.to_string(),
55 })?;
56 toml::from_str(string).map_err(|err| ApiError::CannotReadToml {
57 reason: err.to_string(),
58 })
59}