1mod check;
12mod data;
13mod error;
14mod media;
15
16pub use error::ServiceError;
17
18use yog_data::Schema;
19
20#[derive(Debug, Clone, Schema)]
22pub struct Request {
23 pub method: String,
24 #[data(default)]
25 pub params: yog_data::Value,
26}
27
28pub type Reply = Result<yog_data::Value, ServiceError>;
30
31pub fn run() -> Result<(), String> {
33 let mut input = std::io::stdin().lock();
34 let mut out = std::io::stdout().lock();
35 loop {
36 let reply = match yog_data::io::read_frame_bytes(&mut input) {
37 Ok(None) => return Ok(()),
38 Ok(Some(bytes)) => match yog_data::read_bytes::<Request>(&bytes) {
39 Ok(request) => answer(&request),
40 Err(e) => Err(format!("not a request: {e:?}").into()),
41 },
42 Err(e) => return Err(e.to_string()),
43 };
44 yog_data::io::write_frame(&mut out, &reply).map_err(|e| e.to_string())?;
45 }
46}
47
48pub fn answer(request: &Request) -> Reply {
50 let (method, params) = (request.method.as_str(), &request.params);
51 let reply = data::method(method, params)
52 .or_else(|| media::method(method, params))
53 .or_else(|| crate::design::service::dispatch(method, params))
55 .unwrap_or_else(|| Err(format!("no method `{method}`").into()));
56 reply
57 .map(|v| yog_data::typed::flatten(&v))
58 .map_err(|mut e| {
59 e.file = e.file.take().or_else(|| file_of(params));
60 e
61 })
62}
63
64fn file_of(params: &yog_data::Value) -> Option<String> {
66 let path = |v: &yog_data::Value| {
67 v.get(yog_ids::serve_param::PATH)
68 .and_then(yog_data::Value::as_str)
69 .map(str::to_string)
70 };
71 path(params).or_else(|| params.get(yog_ids::serve_param::ARGS).and_then(path))
72}
73
74#[cfg(test)]
75mod tests;