1use std::any::Any;
2use std::collections::HashMap;
3use std::env::args;
4use std::fmt::Debug;
5use std::ops::{Deref, DerefMut};
6use std::sync::Arc;
7use dce_router::protocol::{HEAD_PATH_NAME, Meta, RoutableProtocol};
8use dce_router::request::{Request, Context, Response};
9use dce_router::router::Router;
10use dce_router::serializer::Serialized;
11use dce_util::mixed::DceResult;
12#[cfg(feature = "async")]
13use async_trait::async_trait;
14
15pub type CliRaw<'a> = Request<'a, CliProtocol, (), ()>;
16pub type CliGet<'a, Resp> = Request<'a, CliProtocol, (), Resp>;
17
18const PASS_SEPARATOR: &str = "--";
19
20enum ArgType {
21 AssignExpr(String, String), PrefixName, DownFlowSeparator, Path, }
26
27#[derive(Debug)]
28pub struct CliProtocol {
29 meta: Meta<Vec<String>, String>,
30 pass: Vec<String>,
31 args: HashMap<String, String>,
32}
33
34impl CliProtocol {
35 pub fn pass(&self) -> &Vec<String> {
36 &self.pass
37 }
38
39 pub fn args(&self) -> &HashMap<String, String> {
40 &self.args
41 }
42
43 pub fn args_mut(&mut self) -> &mut HashMap<String, String> {
44 &mut self.args
45 }
46
47 #[cfg(feature = "async")]
48 pub async fn route(self, router: Arc<Router<Self>>, context_data: HashMap<String, Box<dyn Any + Send>>) {
49 if let Some(resp) = Self::handle(self, router, context_data).await {
50 println!("{resp}");
51 }
52 }
53
54 #[cfg(not(feature = "async"))]
55 pub fn route(self, router: Arc<Router<Self>>, context_data: HashMap<String, Box<dyn Any + Send>>) {
56 if let Some(resp) = Self::handle(self, router, context_data) {
57 println!("{resp}");
58 }
59 }
60
61 pub fn new(base: usize) -> Self {
62 let raw = args().collect::<Vec<_>>();
63 let mut cli = Self::from(raw.iter().skip(base).map(|a| a.clone()).collect::<Vec<_>>());
64 *cli.req_mut() = Some(raw);
65 cli
66 }
67
68 fn parse_type(arg: &str) -> ArgType {
69 return if let Some((left, right)) = arg.split_once("=") {
70 ArgType::AssignExpr(left.to_string(), right.to_string())
71 } else if arg.starts_with("-") {
72 if arg == PASS_SEPARATOR { return ArgType::DownFlowSeparator }
73 ArgType::PrefixName
74 } else {
75 ArgType::Path
76 }
77 }
78}
79
80impl From<Vec<String>> for CliProtocol {
81 fn from(mut value: Vec<String>) -> Self {
82 let mut pass = vec![];
83 let mut paths = vec![];
84 let mut args = HashMap::<String, String>::new();
85
86 while ! value.is_empty() {
87 let arg = value.remove(0);
88 match Self::parse_type(&arg) {
89 ArgType::AssignExpr(name, value) => { args.insert(name, value); },
90 ArgType::PrefixName => {
91 args.insert(arg, match value.get(0) {
92 Some(next) if matches!(Self::parse_type(next), ArgType::Path) => value.remove(0),
93 _ => String::new(),
94 });
95 },
96 ArgType::DownFlowSeparator => while ! value.is_empty() {
97 pass.push(value.remove(0));
98 },
99 _ => paths.push(arg),
100 }
101 }
102
103 CliProtocol { meta: Meta::new(vec![], HashMap::from([(HEAD_PATH_NAME.to_string(), paths.join("/"))])), pass, args }
104 }
105}
106
107impl Into<String> for CliProtocol {
108 fn into(mut self) -> String {
109 #[allow(unused_mut)]
110 let mut resp = match self.resp_mut().take() {
111 Some(Response::Serialized(sd)) => self.pack_resp(sd),
112 Some(Response::Raw(resp)) => resp,
113 _ => "".to_string(),
114 };
115 #[cfg(feature = "session")]
116 if let Some(resp_sid) = self.get_resp_sid() {
117 resp.push_str(format!("\n\nNew sid: {}", resp_sid).as_str());
118 }
119 resp
120 }
121}
122
123impl Deref for CliProtocol {
124 type Target = Meta<Vec<String>, String>;
125
126 fn deref(&self) -> &Self::Target {
127 &self.meta
128 }
129}
130
131impl DerefMut for CliProtocol {
132 fn deref_mut(&mut self) -> &mut Self::Target {
133 &mut self.meta
134 }
135}
136
137#[cfg_attr(feature = "async", async_trait)]
138impl RoutableProtocol for CliProtocol {
139 type Req = Vec<String>;
140 type Resp = String;
141
142 #[cfg(feature = "async")]
143 async fn body(&mut self) -> DceResult<Serialized> {
144 unreachable!("not support cli body yet")
145 }
146
147 #[cfg(not(feature = "async"))]
148 fn body(&mut self) -> DceResult<Serialized> {
149 unreachable!("not support cli body yet")
150 }
151
152 fn pack_resp(&self, serialized: Serialized) -> Self::Resp {
153 match serialized {
154 Serialized::String(str) => str,
155 Serialized::Bytes(bytes) => String::from_utf8_lossy(bytes.as_ref()).to_string(),
156 }
157 }
158
159 fn handle_result(self, result: DceResult<()>, context: &mut Context<Self>) -> Option<Self::Resp> {
160 Self::try_print_err(&result);
161 if ! result.is_err() && ! context.api().map_or(false, |a| a.unresponsive()) {
162 return Some(self.into());
163 }
164 None
165 }
166
167 #[cfg(feature = "session")]
168 fn sid(&self) -> Option<&str> {
169 self.args.get("--sid").map(|a| a.as_str())
170 }
171}