1use std::collections::HashMap;
2use std::sync::Arc;
3
4use serde::{Deserialize, Serialize};
5
6use cosmic_macros_primitive::Autobox;
7
8use crate::command::Command;
9use crate::err::StatusErr;
10use crate::loc::ToSurface;
11use crate::substance::FormErrs;
12use crate::util::{ValueMatcher, ValuePattern};
13use crate::wave::core::cmd::CmdMethod;
14use crate::wave::core::ext::ExtMethod;
15use crate::wave::core::http2::{HttpMethod, StatusCode};
16use crate::wave::core::hyp::HypMethod;
17use crate::wave::{Bounce, Ping, Pong, ToRecipients, WaveId};
18use crate::{Bin, SpaceErr, Substance, Surface, ToSubstance};
19use url::Url;
20
21pub mod cmd;
22pub mod ext;
23pub mod http2;
24pub mod hyp;
25
26impl From<Result<ReflectedCore, SpaceErr>> for ReflectedCore {
27 fn from(result: Result<ReflectedCore, SpaceErr>) -> Self {
28 match result {
29 Ok(response) => response,
30 Err(err) => err.into(),
31 }
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
36pub struct ReflectedCore {
37 pub headers: HeaderMap,
38 pub status: StatusCode,
39 pub body: Substance,
40}
41
42impl<S> ToSubstance<S> for ReflectedCore
43where
44 Substance: ToSubstance<S>,
45{
46 fn to_substance(self) -> Result<S, SpaceErr> {
47 self.body.to_substance()
48 }
49
50 fn to_substance_ref(&self) -> Result<&S, SpaceErr> {
51 self.body.to_substance_ref()
52 }
53}
54
55impl ReflectedCore {
56 pub fn to_err(&self) -> SpaceErr {
57 if self.status.is_success() {
58 "cannot convert a success into an error".into()
59 } else {
60 if let Substance::FormErrs(errors) = &self.body {
61 errors.to_cosmic_err()
62 } else {
63 self.status.to_string().into()
64 }
65 }
66 }
67
68 pub fn ok_html(html: &str) -> Self {
69 let bin = Arc::new(html.to_string().into_bytes());
70 ReflectedCore::ok_body(Substance::Bin(bin))
71 }
72
73 pub fn new() -> Self {
74 ReflectedCore {
75 headers: HeaderMap::new(),
76 status: StatusCode::from_u16(200u16).unwrap(),
77 body: Substance::Empty,
78 }
79 }
80
81 pub fn result(result: Result<ReflectedCore, SpaceErr>) -> ReflectedCore {
82 match result {
83 Ok(core) => core,
84 Err(err) => {
85 let mut core = ReflectedCore::status(err.status());
86 core.body = Substance::FormErrs(FormErrs::from(err));
87 core
88 }
89 }
90 }
91
92 pub fn ok() -> Self {
93 Self::ok_body(Substance::Empty)
94 }
95
96 pub fn ok_body(body: Substance) -> Self {
97 Self {
98 headers: HeaderMap::new(),
99 status: StatusCode::from_u16(200u16).unwrap(),
100 body,
101 }
102 }
103
104 pub fn timeout() -> Self {
105 Self {
106 headers: HeaderMap::new(),
107 status: StatusCode::from_u16(408u16).unwrap(),
108 body: Substance::Empty,
109 }
110 }
111
112 pub fn server_error() -> Self {
113 Self {
114 headers: HeaderMap::new(),
115 status: StatusCode::from_u16(500u16).unwrap(),
116 body: Substance::Empty,
117 }
118 }
119
120 pub fn status(status: u16) -> Self {
121 Self {
122 headers: HeaderMap::new(),
123 status: StatusCode::from_u16(status).unwrap_or(StatusCode::from_u16(500).unwrap()),
124 body: Substance::Empty,
125 }
126 }
127
128 pub fn not_found() -> Self {
129 Self {
130 headers: HeaderMap::new(),
131 status: StatusCode::from_u16(404u16).unwrap(),
132 body: Substance::Empty,
133 }
134 }
135
136 pub fn forbidden() -> Self {
137 Self {
138 headers: HeaderMap::new(),
139 status: StatusCode::from_u16(403u16).unwrap(),
140 body: Substance::Empty,
141 }
142 }
143
144 pub fn bad_request() -> Self {
145 Self {
146 headers: HeaderMap::new(),
147 status: StatusCode::from_u16(400u16).unwrap(),
148 body: Substance::Empty,
149 }
150 }
151
152 pub fn fail<S: ToString>(status: u16, message: S) -> Self {
153 let errors = FormErrs::default(message);
154 Self {
155 headers: HeaderMap::new(),
156 status: StatusCode::from_u16(status)
157 .or_else(|_| StatusCode::from_u16(500u16))
158 .unwrap(),
159 body: Substance::FormErrs(errors),
160 }
161 }
162
163 pub fn err(err: SpaceErr) -> Self {
164 let errors = FormErrs::default(err.to_string().as_str());
165 Self {
166 headers: HeaderMap::new(),
167 status: StatusCode::from_u16(err.status())
168 .unwrap_or(StatusCode::from_u16(500u16).unwrap()),
169 body: Substance::FormErrs(errors),
170 }
171 }
172
173 pub fn with_new_substance(self, substance: Substance) -> Self {
174 Self {
175 headers: self.headers,
176 status: self.status,
177 body: substance,
178 }
179 }
180
181 pub fn is_ok(&self) -> bool {
182 self.status.is_success()
183 }
184
185 pub fn into_reflection<P>(self, intended: Surface, to: P, reflection_of: WaveId) -> Pong
186 where
187 P: ToSurface,
188 {
189 Pong {
190 to: to.to_surface(),
191 intended: intended.to_recipients(),
192 core: self,
193 reflection_of: reflection_of,
194 }
195 }
196}
197
198impl ReflectedCore {
199 pub fn as_result<E: From<&'static str>, P: TryFrom<Substance>>(self) -> Result<P, E> {
200 if self.status.is_success() {
201 match P::try_from(self.body) {
202 Ok(substance) => Ok(substance),
203 Err(err) => Err(E::from("error")),
204 }
205 } else {
206 Err(E::from("error"))
207 }
208 }
209
210 pub fn ok_or(&self) -> Result<(), SpaceErr> {
211 if self.is_ok() {
212 Ok(())
213 } else if let Substance::Err(err) = &self.body {
214 Err(err.clone())
215 }
216 else
217 {
218 Err(SpaceErr::new(self.status.as_u16(), "error"))
219 }
220 }
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Autobox)]
266pub enum Method {
267 Hyp(HypMethod),
268 Cmd(CmdMethod),
269 Http(HttpMethod),
270 Ext(ExtMethod),
271}
272
273impl Method {
274 pub fn to_deep_string(&self) -> String {
275 match self {
276 Method::Hyp(x) => format!("Hyp<{}>", x.to_string()),
277 Method::Cmd(x) => format!("Cmd<{}>", x.to_string()),
278 Method::Http(x) => format!("Http<{}>", x.to_string()),
279 Method::Ext(x) => format!("Ext<{}>", x.to_string()),
280 }
281 }
282}
283
284#[derive(Debug, Clone, Eq, PartialEq)]
285pub enum MethodPattern {
286 Hyp(ValuePattern<HypMethod>),
287 Cmd(ValuePattern<CmdMethod>),
288 Http(ValuePattern<HttpMethod>),
289 Ext(ValuePattern<ExtMethod>),
290}
291
292impl ToString for MethodPattern {
293 fn to_string(&self) -> String {
294 match self {
295 MethodPattern::Cmd(c) => {
296 format!("Cmd<{}>", c.to_string())
297 }
298 MethodPattern::Http(c) => {
299 format!("Http<{}>", c.to_string())
300 }
301 MethodPattern::Ext(c) => {
302 format!("Ext<{}>", c.to_string())
303 }
304 MethodPattern::Hyp(c) => {
305 format!("Hyp<{}>", c.to_string())
306 }
307 }
308 }
309}
310
311impl ValueMatcher<Method> for MethodPattern {
312 fn is_match(&self, x: &Method) -> Result<(), ()> {
313 match self {
314 MethodPattern::Hyp(pattern) => {
315 if let Method::Hyp(v) = x {
316 pattern.is_match(v)
317 } else {
318 Err(())
319 }
320 }
321 MethodPattern::Cmd(pattern) => {
322 if let Method::Cmd(v) = x {
323 pattern.is_match(v)
324 } else {
325 Err(())
326 }
327 }
328 MethodPattern::Http(pattern) => {
329 if let Method::Http(v) = x {
330 pattern.is_match(v)
331 } else {
332 Err(())
333 }
334 }
335 MethodPattern::Ext(pattern) => {
336 if let Method::Ext(v) = x {
337 pattern.is_match(v)
338 } else {
339 Err(())
340 }
341 }
342 }
343 }
344}
345
346impl ValueMatcher<Method> for Method {
347 fn is_match(&self, x: &Method) -> Result<(), ()> {
348 if x == self {
349 Ok(())
350 } else {
351 Err(())
352 }
353 }
354}
355
356impl Method {
357 pub fn kind(&self) -> MethodKind {
358 match self {
359 Method::Cmd(_) => MethodKind::Cmd,
360 Method::Http(_) => MethodKind::Http,
361 Method::Ext(_) => MethodKind::Ext,
362 Method::Hyp(_) => MethodKind::Hyp,
363 }
364 }
365}
366
367impl ToString for Method {
368 fn to_string(&self) -> String {
369 match self {
370 Method::Cmd(cmd) => format!("Cmd<{}>", cmd.to_string()),
371 Method::Http(method) => format!("Http<{}>", method.to_string()),
372 Method::Ext(msg) => format!("Ext<{}>", msg.to_string()),
373 Method::Hyp(sys) => format!("Hyp<{}>", sys.to_string()),
374 }
375 }
376}
377
378impl Into<DirectedCore> for Method {
379 fn into(self) -> DirectedCore {
380 DirectedCore {
381 headers: Default::default(),
382 method: self,
383 uri: Url::parse("http://localhost/").unwrap(),
384 body: Substance::Empty,
385 }
386 }
387}
388
389#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
390pub struct DirectedCore {
391 pub headers: HeaderMap,
392 pub method: Method,
393 pub uri: Url,
394 pub body: Substance,
395}
396
397impl<S> ToSubstance<S> for DirectedCore
398where
399 Substance: ToSubstance<S>,
400{
401 fn to_substance(self) -> Result<S, SpaceErr> {
402 self.body.to_substance()
403 }
404
405 fn to_substance_ref(&self) -> Result<&S, SpaceErr> {
406 self.body.to_substance_ref()
407 }
408}
409
410impl DirectedCore {
411 pub fn new(method: Method) -> Self {
412 Self {
413 method,
414 headers: HeaderMap::new(),
415 uri: Url::parse("http://localhost/").unwrap(),
416 body: Default::default(),
417 }
418 }
419
420 pub fn to_selection_str(&self) -> String {
421 format!(
422 "{}{} -[{}]->",
423 self.method.to_deep_string(),
424 self.uri.path(),
425 self.body.kind().to_string()
426 )
427 }
428
429 pub fn ext<M: Into<ExtMethod>>(method: M) -> Self {
430 let method: ExtMethod = method.into();
431 let method: Method = method.into();
432 Self::new(method)
433 }
434
435 pub fn http<M: Into<HttpMethod>>(method: M) -> Self {
436 let method: HttpMethod = method.into();
437 let method: Method = method.into();
438 Self::new(method)
439 }
440
441 pub fn cmd<M: Into<CmdMethod>>(method: M) -> Self {
442 let method: CmdMethod = method.into();
443 let method: Method = method.into();
444 Self::new(method)
445 }
446}
447
448impl TryFrom<Ping> for DirectedCore {
449 type Error = SpaceErr;
450
451 fn try_from(request: Ping) -> Result<Self, Self::Error> {
452 Ok(request.core)
453 }
454}
455
456impl DirectedCore {
457 pub fn kind(&self) -> MethodKind {
458 self.method.kind()
459 }
460}
461
462impl Into<DirectedCore> for Command {
463 fn into(self) -> DirectedCore {
464 DirectedCore {
465 body: Substance::Command(Box::new(self)),
466 method: Method::Cmd(CmdMethod::Command),
467 ..Default::default()
468 }
469 }
470}
471
472impl Default for DirectedCore {
512 fn default() -> Self {
513 Self {
514 headers: Default::default(),
515 method: Method::Http(HttpMethod::Get),
516 uri: Url::parse("http://localhost/").unwrap(),
517 body: Substance::Empty,
518 }
519 }
520}
521
522impl DirectedCore {
523 pub fn with_body(self, body: Substance) -> Self {
524 Self {
525 headers: self.headers,
526 uri: self.uri,
527 method: self.method,
528 body,
529 }
530 }
531
532 pub fn server_error(&self) -> ReflectedCore {
533 ReflectedCore {
534 headers: Default::default(),
535 status: StatusCode::from_u16(500u16).unwrap(),
536 body: Substance::Empty,
537 }
538 }
539
540 pub fn timeout(&self) -> ReflectedCore {
541 ReflectedCore {
542 headers: Default::default(),
543 status: StatusCode::from_u16(408u16).unwrap(),
544 body: Substance::Empty,
545 }
546 }
547
548 pub fn not_found(&self) -> ReflectedCore {
549 ReflectedCore {
550 headers: Default::default(),
551 status: StatusCode::from_u16(404u16).unwrap(),
552 body: Substance::Empty,
553 }
554 }
555
556 pub fn forbidden(&self) -> ReflectedCore {
557 ReflectedCore {
558 headers: Default::default(),
559 status: StatusCode::from_u16(403u16).unwrap(),
560 body: Substance::Empty,
561 }
562 }
563
564 pub fn bad_request(&self) -> ReflectedCore {
565 ReflectedCore {
566 headers: Default::default(),
567 status: StatusCode::from_u16(400u16).unwrap(),
568 body: Substance::Empty,
569 }
570 }
571
572 pub fn substance(method: Method, body: Substance) -> DirectedCore {
573 DirectedCore {
574 method,
575 body,
576 ..Default::default()
577 }
578 }
579
580 pub fn ok(&self) -> ReflectedCore {
581 ReflectedCore {
582 headers: Default::default(),
583 status: StatusCode::from_u16(200u16).unwrap(),
584 body: Substance::Empty,
585 }
586 }
587
588 pub fn ok_body(&self, body: Substance) -> ReflectedCore {
589 ReflectedCore {
590 headers: Default::default(),
591 status: StatusCode::from_u16(200u16).unwrap(),
592 body,
593 }
594 }
595
596 pub fn fail<M: ToString>(&self, status: u16, message: M) -> ReflectedCore {
597 let errors = FormErrs::default(message.to_string().as_str());
598 ReflectedCore {
599 headers: Default::default(),
600 status: StatusCode::from_u16(status)
601 .or_else(|_| StatusCode::from_u16(500u16))
602 .unwrap(),
603 body: Substance::FormErrs(errors),
604 }
605 }
606
607 pub fn err<E: StatusErr>(&self, error: E) -> ReflectedCore {
608 let errors = FormErrs::default(error.message().as_str());
609 let status = match StatusCode::from_u16(error.status()) {
610 Ok(status) => status,
611 Err(_) => StatusCode::from_u16(500u16).unwrap(),
612 };
613 println!("-----> returning STATUS of {}", status.to_string());
614 ReflectedCore {
615 headers: Default::default(),
616 status,
617 body: Substance::FormErrs(errors),
618 }
619 }
620}
621
622impl From<()> for ReflectedCore {
623 fn from(_: ()) -> Self {
624 ReflectedCore::ok()
625 }
626}
627
628impl Into<ReflectedCore> for Surface {
629 fn into(self) -> ReflectedCore {
630 ReflectedCore::ok_body(Substance::Surface(self))
631 }
632}
633
634impl TryFrom<ReflectedCore> for Surface {
635 type Error = SpaceErr;
636
637 fn try_from(core: ReflectedCore) -> Result<Self, Self::Error> {
638 if !core.status.is_success() {
639 Err(SpaceErr::new(core.status.as_u16(), "error"))
640 } else {
641 match core.body {
642 Substance::Surface(surface) => Ok(surface),
643 substance => Err(format!(
644 "expecting Surface received {}",
645 substance.kind().to_string()
646 )
647 .into()),
648 }
649 }
650 }
651}
652
653pub type CoreBounce = Bounce<ReflectedCore>;
654
655#[derive(
656 Debug,
657 Clone,
658 Serialize,
659 Deserialize,
660 strum_macros::Display,
661 strum_macros::EnumString,
662 Eq,
663 PartialEq,
664)]
665pub enum MethodKind {
666 Hyp,
667 Cmd,
668 Ext,
669 Http,
670}
671
672impl ValueMatcher<MethodKind> for MethodKind {
673 fn is_match(&self, x: &MethodKind) -> Result<(), ()> {
674 if self == x {
675 Ok(())
676 } else {
677 Err(())
678 }
679 }
680}
681
682pub type HeaderMap = HashMap<String, String>;