1use crate::arg::CliInput;
2use anyhow::{anyhow, Result};
3use clap::ArgMatches;
4use invoke::CommandInvocation;
5use std::path::PathBuf;
6
7pub mod invoke;
8pub mod metadata;
9
10#[derive(Debug, Clone)]
11pub struct ApiManager {
12 #[allow(dead_code)]
13 path: PathBuf,
14 rps: Vec<String>,
15}
16
17impl ApiManager {
18 pub fn build_invocation(
19 &self,
20 raw_input: &CliInput,
21 matches: &ArgMatches,
22 ) -> Result<CommandInvocation> {
23 let pos_args = raw_input.pos_args();
24 pos_args
25 .first()
26 .ok_or(anyhow!("the rp is not specified"))
27 .and_then(|rp| {
28 let c = self.read_metadata(rp)?.resolve_command(&raw_input)?;
29 Ok(CommandInvocation::new(&c, matches))
30 })
31 }
32}
33
34#[cfg(any(feature = "embed-api", target_arch = "wasm32"))]
35mod embedded {
36 use crate::api::metadata::Metadata;
37 use anyhow::{anyhow, Result};
38 use std::path::PathBuf;
39
40 use rust_embed::RustEmbed;
41
42 #[derive(RustEmbed)]
43 #[folder = "metadata/"]
44 struct Asset;
45
46 impl super::ApiManager {
47 pub fn new(_: PathBuf) -> Result<Self> {
48 let rps: Vec<String> = Asset::names()
49 .map(|name| name.trim_end_matches(".json").to_string())
50 .collect();
51 Ok(Self {
52 path: PathBuf::new(),
53 rps,
54 })
55 }
56
57 pub fn list_rps(&self) -> &Vec<String> {
58 &self.rps
59 }
60
61 pub fn read_metadata(&self, rp: &str) -> Result<Metadata> {
62 let bytes: Vec<u8> = Asset::get(format!("{rp}.json").as_str())
63 .map(|d| d.data.to_vec())
64 .ok_or(anyhow!("{rp}.json doesn't exist"))?;
65 Ok(serde_json::from_slice(&bytes)?)
66 }
67 }
68}
69
70#[cfg(not(any(feature = "embed-api", target_arch = "wasm32")))]
71mod fs {
72 use crate::api::metadata::Metadata;
73 use anyhow::{Context, Result};
74 use std::path::PathBuf;
75
76 use std::fs::read;
77
78 impl super::ApiManager {
79 pub fn new(path: PathBuf) -> Result<Self> {
80 let mut rps = vec![];
82 for entry in path
83 .read_dir()
84 .context(format!("reading dir {}", path.display()))?
85 {
86 let path = entry?.path();
87 if let Some(ext) = path.extension() {
88 if ext == "json" {
89 if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
90 rps.push(stem.to_owned());
91 }
92 }
93 }
94 }
95 Ok(Self { path, rps })
96 }
97
98 pub fn list_rps(&self) -> &Vec<String> {
99 &self.rps
100 }
101
102 pub fn read_metadata(&self, rp: &str) -> Result<Metadata> {
103 let bytes =
104 read(self.path.join(format!("{rp}.json"))).context(format!("reading {rp}.json"))?;
105 Ok(serde_json::from_slice(&bytes)?)
106 }
107 }
108}