1use percent_encoding::percent_decode_str;
2use std::{
3 borrow::Cow,
4 collections::{BTreeMap, HashMap},
5 future::Future,
6 path::PathBuf,
7 pin::Pin,
8 str::Utf8Error,
9 sync::Arc,
10};
11use tiny_web_macro::fnv1a_64;
12
13use tokio::{
14 fs::remove_file,
15 sync::{mpsc::Sender, Mutex},
16 task::{yield_now, JoinHandle},
17};
18
19#[cfg(debug_assertions)]
20use tokio::sync::RwLock;
21
22use crate::{fnv1a_64, StrOrI64};
23
24use super::{
25 cache::{Cache, CacheSys},
26 data::Data,
27 dbs::adapter::DB,
28 html::{Html, Nodes},
29 init::Addr,
30 lang::{Lang, LangItem},
31 log::Log,
32 mail::{Mail, MailMessage},
33 request::{Request, WebFile},
34 response::{Redirect, Response},
35 route::Route,
36 session::{Flash, Session},
37 tool::Tool,
38 worker::{MessageWrite, Worker},
39};
40
41pub type Act = fn(&mut Action) -> Pin<Box<dyn Future<Output = Answer> + Send + '_>>;
43
44pub type ActMap = BTreeMap<i64, BTreeMap<i64, BTreeMap<i64, Act>>>;
52
53#[derive(Debug)]
61pub enum Answer {
62 None,
64 String(String),
66 Raw(Vec<u8>),
68}
69
70#[derive(Debug)]
72pub(crate) struct ActionData {
73 pub engine: Arc<ActMap>,
75 #[cfg(not(debug_assertions))]
77 pub lang: Arc<Lang>,
78 #[cfg(debug_assertions)]
80 pub lang: Arc<RwLock<Lang>>,
81 #[cfg(not(debug_assertions))]
83 pub html: Arc<Html>,
84 #[cfg(debug_assertions)]
86 pub html: Arc<RwLock<Html>>,
87 pub cache: Arc<Mutex<CacheSys>>,
89 pub db: Arc<DB>,
91 pub session_key: Arc<String>,
93 pub salt: Arc<String>,
95 pub mail: Arc<Mutex<Mail>>,
97 pub request: Request,
99 pub session: Option<String>,
101 pub(crate) tx: Arc<Sender<MessageWrite>>,
103 pub(crate) action_index: Arc<Route>,
105 pub(crate) action_not_found: Arc<Route>,
107 pub(crate) action_err: Arc<Route>,
109 pub(crate) stop: Option<(Arc<Addr>, i64)>,
111 pub(crate) root: Arc<String>,
113}
114
115#[derive(Debug)]
143pub struct Action {
144 pub request: Request,
146 pub response: Response,
148 pub session: Session,
150 pub salt: Arc<String>,
152 data: BTreeMap<i64, Data>,
154 pub module: String,
156 pub class: String,
158 pub action: String,
160 pub param: Option<String>,
162 module_id: i64,
164 class_id: i64,
166 action_id: i64,
168 current_module_id: i64,
170 current_class_id: i64,
172 html: Option<Arc<BTreeMap<i64, Nodes>>>,
174 lang: Option<Arc<BTreeMap<i64, String>>>,
176
177 engine: Arc<ActMap>,
179 #[cfg(not(debug_assertions))]
181 language: Arc<Lang>,
182 #[cfg(debug_assertions)]
184 language: Arc<RwLock<Lang>>,
185 #[cfg(not(debug_assertions))]
187 template: Arc<Html>,
188 #[cfg(debug_assertions)]
190 template: Arc<RwLock<Html>>,
191 pub cache: Cache,
193 pub db: Arc<DB>,
195 mail: Arc<Mutex<Mail>>,
197
198 pub internal: bool,
200
201 pub(crate) tx: Arc<Sender<MessageWrite>>,
203 pub(crate) header_send: bool,
205
206 not_found: Arc<Route>,
208 pub tool: Tool,
210}
211
212impl Action {
213 pub(crate) async fn new(data: ActionData) -> Result<Action, (Redirect, HashMap<String, Vec<WebFile>>)> {
220 let response = Response {
221 redirect: None,
222 content_type: None,
223 headers: Vec::new(),
224 http_code: None,
225 css: Vec::new(),
226 js: Vec::new(),
227 meta: Vec::new(),
228 };
229 #[cfg(not(debug_assertions))]
230 let lang_id = data.lang.default as i64;
231 #[cfg(debug_assertions)]
232 let lang_id = data.lang.read().await.default as i64;
233
234 let mut session = if let Some(session) = data.session {
235 Session::load_session(session.clone(), Arc::clone(&data.db), lang_id, data.session_key).await
236 } else {
237 Session::new(lang_id, &data.salt, &data.request.ip, &data.request.agent, &data.request.host, data.session_key)
238 };
239 let route = match Action::extract_route(
241 &data.request,
242 Arc::clone(&data.cache),
243 Arc::clone(&data.db),
244 Arc::clone(&data.action_index),
245 Arc::clone(&data.action_err),
246 )
247 .await
248 {
249 Ok(r) => r,
250 Err(redirect) => return Err((redirect, data.request.input.file)),
251 };
252 let module = route.module;
253 let class = route.class;
254 let action = route.action;
255 let module_id = route.module_id;
256 let class_id = route.class_id;
257 let action_id = route.action_id;
258 if let Some(lang_id) = route.lang_id {
259 session.set_lang_id(lang_id);
260 }
261 let param = route.param;
262 #[cfg(not(debug_assertions))]
264 let html = data.html.list.get(&module_id).and_then(|module| module.get(&class_id).cloned());
265 #[cfg(debug_assertions)]
266 let html = data.html.read().await.list.get(&module_id).and_then(|module| module.get(&class_id).cloned());
267 #[cfg(not(debug_assertions))]
269 let lang = data
270 .lang
271 .list
272 .get(&session.get_lang_id())
273 .and_then(|langs| langs.get(&module_id))
274 .and_then(|module| module.get(&class_id).cloned());
275 #[cfg(debug_assertions)]
276 let lang = data
277 .lang
278 .read()
279 .await
280 .list
281 .get(&session.get_lang_id())
282 .and_then(|langs| langs.get(&module_id))
283 .and_then(|module| module.get(&class_id).cloned());
284
285 Ok(Action {
286 request: data.request,
287 response,
288 session,
289 salt: data.salt,
290 data: BTreeMap::new(),
291
292 module,
293 class,
294 action,
295 param,
296 module_id,
297 class_id,
298 action_id,
299 current_module_id: module_id,
300 current_class_id: class_id,
301 html,
302 lang,
303
304 engine: data.engine,
305 language: data.lang,
306 template: data.html,
307 cache: Cache::new(data.cache),
308 db: Arc::clone(&data.db),
309 mail: data.mail,
310
311 internal: false,
312
313 tx: data.tx,
314 header_send: false,
315 not_found: data.action_not_found,
316 tool: Tool::new(data.db, data.stop, data.root),
317 })
318 }
319
320 pub async fn load(
322 &mut self,
323 key: impl StrOrI64,
324 module: impl StrOrI64,
325 class: impl StrOrI64,
326 action: impl StrOrI64,
327 param: Option<String>,
328 ) {
329 let res = self.start_route(module.to_i64(), class.to_i64(), action.to_i64(), param, true).await;
330 if let Answer::String(value) = res {
331 self.data.insert(key.to_i64(), Data::String(value));
332 }
333 }
334
335 pub fn lang(&self, text: impl StrOrI64) -> String {
337 if let Some(l) = &self.lang {
338 if let Some(str) = l.get(&text.to_i64()) {
339 return str.to_owned();
340 }
341 }
342 text.to_str().to_owned()
343 }
344
345 pub async fn lang_current(&self) -> Arc<LangItem> {
347 #[cfg(not(debug_assertions))]
348 {
349 Arc::clone(unsafe { self.language.langs.get_unchecked(self.session.get_lang_id() as usize) })
350 }
351 #[cfg(debug_assertions)]
352 {
353 Arc::clone(unsafe { self.language.read().await.langs.get_unchecked(self.session.get_lang_id() as usize) })
354 }
355 }
356
357 pub async fn lang_list(&self) -> Arc<Vec<Arc<LangItem>>> {
359 #[cfg(not(debug_assertions))]
360 {
361 Arc::clone(&self.language.langs)
362 }
363 #[cfg(debug_assertions)]
364 {
365 Arc::clone(&self.language.read().await.langs)
366 }
367 }
368
369 pub async fn all_lang_list(&self) -> Vec<LangItem> {
371 Lang::get_all_langs(Arc::clone(&self.db)).await
372 }
373
374 pub fn set<T>(&mut self, key: impl StrOrI64, value: T)
376 where
377 T: Into<Data>,
378 {
379 self.data.insert(key.to_i64(), value.into());
380 }
381
382 pub fn get<T>(&self, key: impl StrOrI64) -> Option<&T>
384 where
385 for<'a> &'a T: From<&'a Data>,
386 {
387 self.data.get(&key.to_i64()).map(|value| value.into())
388 }
389
390 pub fn take<T>(&mut self, key: impl StrOrI64) -> Option<T>
392 where
393 T: From<Data>,
394 {
395 self.data.remove(&key.to_i64()).map(|value| value.into())
396 }
397
398 pub fn set_flash(&mut self, kind: Flash, value: String) {
400 self.session.set_flash(kind, value);
401 }
402
403 pub fn take_flash(&mut self) -> Option<Vec<(Flash, String)>> {
405 self.session.take_flash()
406 }
407
408 pub fn set_lang(&mut self, key: impl StrOrI64) {
410 let idkey = key.to_i64();
411 if let Some(l) = &self.lang {
412 if let Some(str) = l.get(&idkey) {
413 self.data.insert(idkey, Data::String(str.to_owned()));
414 return;
415 }
416 }
417 let str = key.to_str();
418 if !str.is_empty() {
419 self.data.insert(idkey, Data::String(key.to_str().to_owned()));
420 } else {
421 #[cfg(not(debug_assertions))]
422 self.data.insert(idkey, Data::String("".to_owned()));
423 #[cfg(debug_assertions)]
424 self.data.insert(idkey, Data::String(key.to_i64().to_string().to_owned()));
425 }
426 }
427
428 pub fn set_lang_arr(&mut self, keys: &[impl StrOrI64]) {
430 for key in keys {
431 let idkey = key.to_i64();
432 if let Some(l) = &self.lang {
433 if let Some(str) = l.get(&idkey) {
434 self.data.insert(idkey, Data::String(str.to_owned()));
435 continue;
436 }
437 }
438 let str = key.to_str();
439 if !str.is_empty() {
440 self.data.insert(idkey, Data::String(key.to_str().to_owned()));
441 } else {
442 #[cfg(not(debug_assertions))]
443 self.data.insert(idkey, Data::String("".to_owned()));
444 #[cfg(debug_assertions)]
445 self.data.insert(idkey, Data::String(key.to_i64().to_string().to_owned()));
446 }
447 }
448 }
449
450 pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
457 where
458 F: Future + Send + 'static,
459 F::Output: Send + 'static,
460 {
461 tokio::spawn(future)
462 }
463
464 pub async fn write(&mut self, answer: Answer) {
466 let vec = match answer {
467 Answer::None => return,
468 Answer::String(str) => str.as_bytes().to_vec(),
469 Answer::Raw(raw) => raw,
470 };
471 Worker::write(self, vec).await;
472 self.header_send = true;
473 yield_now().await;
474 }
475
476 pub async fn get_access(&mut self, module: impl StrOrI64, class: impl StrOrI64, action: impl StrOrI64) -> bool {
478 if !self.db.in_use() {
479 return true;
480 }
481 let module_id = module.to_i64();
482 let class_id = class.to_i64();
483 let action_id = action.to_i64();
484 let key = vec![fnv1a_64!("auth"), self.session.role_id, module_id, class_id, action_id];
486 let (data, key) = self.cache.get(key).await;
487 if let Some(Data::Bool(a)) = data {
488 return a;
489 };
490 match self
492 .db
493 .query_prepare(
494 fnv1a_64!("lib_get_auth"),
495 &[&self.session.role_id, &module_id, &module_id, &module_id, &class_id, &class_id, &action_id],
496 false,
497 )
498 .await
499 {
500 Some(rows) => {
501 if rows.len() == 1 {
502 let access = if let Data::Vec(row) = unsafe { rows.get_unchecked(0) } {
503 if row.is_empty() {
504 return false;
505 }
506 if let Data::I32(val) = unsafe { row.get_unchecked(0) } {
507 *val != 0
508 } else {
509 return false;
510 }
511 } else {
512 return false;
513 };
514
515 self.cache.set(key, Data::Bool(access)).await;
516 access
517 } else {
518 self.cache.set(key, Data::Bool(false)).await;
519 false
520 }
521 }
522 None => false,
523 }
524 }
525
526 pub fn render(&mut self, template: impl StrOrI64) -> Answer {
532 match &self.html {
533 Some(h) => match h.get(&template.to_i64()) {
534 Some(vec) => {
535 if !self.response.css.is_empty() {
536 let mut vec = Vec::with_capacity(self.response.css.len());
537 for css in self.response.css.drain(..) {
538 vec.push(Data::String(css));
539 }
540 self.data.insert(fnv1a_64!("css"), Data::Vec(vec));
541 }
542 if !self.response.js.is_empty() {
543 let mut vec = Vec::with_capacity(self.response.js.len());
544 for js in self.response.js.drain(..) {
545 vec.push(Data::String(js));
546 }
547 self.data.insert(fnv1a_64!("js"), Data::Vec(vec));
548 }
549 if !self.response.meta.is_empty() {
550 let mut vec = Vec::with_capacity(self.response.meta.len());
551 for meta in self.response.meta.drain(..) {
552 vec.push(Data::String(meta));
553 }
554 self.data.insert(fnv1a_64!("meta"), Data::Vec(vec));
555 }
556 Html::render(&self.data, vec)
557 }
558 #[cfg(not(debug_assertions))]
559 None => Answer::None,
560 #[cfg(debug_assertions)]
561 None => Answer::String(format!("{{{}}}", template.to_str())),
562 },
563 #[cfg(not(debug_assertions))]
564 None => Answer::None,
565 #[cfg(debug_assertions)]
566 None => Answer::String(format!("{{{}}}", template.to_str())),
567 }
568 }
569
570 pub async fn route(&mut self, module: &str, class: &str, action: &str, param: Option<&str>, lang_id: Option<i64>) -> String {
572 if self.db.in_use() {
573 let key = match (param, lang_id) {
575 (Some(p), Some(l)) => vec![
576 fnv1a_64!("route"),
577 fnv1a_64(module.as_bytes()),
578 fnv1a_64(class.as_bytes()),
579 fnv1a_64(action.as_bytes()),
580 fnv1a_64(p.as_bytes()),
581 l,
582 ],
583 (Some(p), None) => vec![
584 fnv1a_64!("route"),
585 fnv1a_64(module.as_bytes()),
586 fnv1a_64(class.as_bytes()),
587 fnv1a_64(action.as_bytes()),
588 fnv1a_64(p.as_bytes()),
589 -1,
590 ],
591 (None, Some(l)) => {
592 vec![fnv1a_64!("route"), fnv1a_64(module.as_bytes()), fnv1a_64(class.as_bytes()), fnv1a_64(action.as_bytes()), 0, l]
593 }
594 (None, None) => {
595 vec![fnv1a_64!("route"), fnv1a_64(module.as_bytes()), fnv1a_64(class.as_bytes()), fnv1a_64(action.as_bytes()), 0, -1]
596 }
597 };
598 let (data, key) = self.cache.get(key).await;
599 if let Some(Data::String(s)) = data {
600 return s;
601 };
602 match self
604 .db
605 .query_prepare(
606 fnv1a_64!("lib_get_url"),
607 &[&fnv1a_64(module.as_bytes()), &fnv1a_64(class.as_bytes()), &fnv1a_64(action.as_bytes()), ¶m, &lang_id],
608 false,
609 )
610 .await
611 {
612 Some(rows) => {
613 if rows.len() == 1 {
614 let row = if let Data::Vec(vec) = unsafe { rows.get_unchecked(0) } {
615 vec
616 } else {
617 return Action::format_route(module, class, action, param);
618 };
619 if row.is_empty() {
620 return Action::format_route(module, class, action, param);
621 }
622
623 let url = if let Data::String(url) = unsafe { row.get_unchecked(0) } {
624 url.clone()
625 } else {
626 return Action::format_route(module, class, action, param);
627 };
628 self.cache.set(key, Data::String(url.clone())).await;
629 url
630 } else {
631 let url = Action::format_route(module, class, action, param);
632 self.cache.set(key, Data::String(url.clone())).await;
633 url
634 }
635 }
636 None => Action::format_route(module, class, action, param),
637 }
638 } else {
639 Action::format_route(module, class, action, param)
640 }
641 }
642
643 pub async fn mail(&self, message: MailMessage) -> bool {
645 let provider = {
646 let mail = self.mail.lock().await;
647 mail.provider.clone()
648 };
649 Mail::send(provider, Arc::clone(&self.db), message, self.session.user_id, self.request.host.clone()).await
650 }
651
652 pub fn percent_decode<'a>(&self, url: &'a str) -> Result<Cow<'a, str>, Utf8Error> {
654 percent_decode_str(url).decode_utf8()
655 }
656
657 pub async fn not_found(&mut self) -> String {
659 if !self.db.in_use() {
660 let install = Route::default_install();
661 return format!("/{}/{}/not_found", install.module, install.class);
662 }
663 let key = vec![fnv1a_64!("404"), self.session.get_lang_id()];
664 let (data, key) = self.cache.get(key).await;
665 match data {
666 Some(d) => match d {
667 Data::String(url) => url,
668 _ => match &self.not_found.param {
669 Some(param) => {
670 format!("/{}/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action, param)
671 }
672 None => {
673 format!("/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action)
674 }
675 },
676 },
677 None => {
678 match self.db.query_prepare(fnv1a_64!("lib_get_not_found"), &[&self.session.get_lang_id()], false).await {
680 Some(v) => {
681 if v.is_empty() {
682 self.cache.set(key, Data::None).await;
683 match &self.not_found.param {
684 Some(param) => {
685 format!("/{}/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action, param)
686 }
687 None => format!("/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action),
688 }
689 } else if let Data::Vec(row) = unsafe { v.get_unchecked(0) } {
690 if !row.is_empty() {
691 if let Data::String(url) = unsafe { row.get_unchecked(0) } {
692 self.cache.set(key, Data::String(url.clone())).await;
693 url.clone()
694 } else {
695 self.cache.set(key, Data::None).await;
696 match &self.not_found.param {
697 Some(param) => format!(
698 "/{}/{}/{}/{}",
699 self.not_found.module, self.not_found.class, self.not_found.action, param
700 ),
701 None => {
702 format!("/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action)
703 }
704 }
705 }
706 } else {
707 self.cache.set(key, Data::None).await;
708 match &self.not_found.param {
709 Some(param) => {
710 format!("/{}/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action, param)
711 }
712 None => {
713 format!("/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action)
714 }
715 }
716 }
717 } else {
718 self.cache.set(key, Data::None).await;
719 match &self.not_found.param {
720 Some(param) => {
721 format!("/{}/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action, param)
722 }
723 None => format!("/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action),
724 }
725 }
726 }
727 None => match &self.not_found.param {
728 Some(param) => {
729 format!("/{}/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action, param)
730 }
731 None => format!("/{}/{}/{}", self.not_found.module, self.not_found.class, self.not_found.action),
732 },
733 }
734 }
735 }
736 }
737
738 pub(crate) async fn run(action: &mut Action) -> Answer {
740 action.start_route(action.module_id, action.class_id, action.action_id, action.param.clone(), false).await
741 }
742
743 pub(crate) async fn end(mut action: Action) {
745 Session::save_session(action.db, &action.session, &action.request).await;
747 for val in action.request.input.file.values() {
749 for f in val {
750 if let Err(e) = remove_file(&f.tmp).await {
751 Log::warning(1103, Some(format!("filename={}. Error={}", &f.tmp.display(), e)));
752 };
753 }
754 }
755 if action.tool.install_end {
756 action.tool.stop();
757 }
758 }
759
760 pub(crate) async fn clean_file(file: Vec<PathBuf>) {
762 for f in file {
763 if let Err(e) = remove_file(&f).await {
764 Log::warning(1103, Some(format!("filename={}. Error={}", f.display(), e)));
765 };
766 }
767 }
768
769 async fn start_route(&mut self, module_id: i64, class_id: i64, action_id: i64, param: Option<String>, internal: bool) -> Answer {
771 if self.get_access(module_id, class_id, action_id).await {
773 if let Some(answer) = self.invoke(module_id, class_id, action_id, param, internal).await {
774 return answer;
775 };
776 }
777 if internal {
778 return Answer::None;
779 }
780 if self.request.ajax {
781 self.response.http_code = Some(404);
782 return Answer::None;
783 }
784
785 if !(module_id == self.not_found.module_id && class_id == self.not_found.class_id && class_id == self.not_found.action_id) {
787 self.response.redirect = Some(Redirect {
788 url: self.not_found().await,
789 permanently: false,
790 });
791 }
792 Answer::None
793 }
794
795 async fn invoke(&mut self, module_id: i64, class_id: i64, action_id: i64, param: Option<String>, internal: bool) -> Option<Answer> {
797 if let Some(m) = self.engine.get(&module_id) {
798 if let Some(c) = m.get(&class_id) {
799 if let Some(a) = c.get(&action_id) {
800 if self.current_module_id == module_id && self.current_class_id == class_id {
801 let i = self.internal;
803 let p = match param {
804 Some(str) => self.param.replace(str),
805 None => self.param.take(),
806 };
807 self.internal = internal;
808 let res = a(self).await;
809 self.internal = i;
810 self.param = p;
811 return Some(res);
812 } else {
813 #[cfg(not(debug_assertions))]
817 let h = match self.template.list.get(&module_id) {
818 Some(h) => match h.get(&class_id) {
819 Some(h) => self.html.replace(Arc::clone(h)),
820 None => self.html.take(),
821 },
822 None => self.html.take(),
823 };
824 #[cfg(debug_assertions)]
825 let h = match self.template.read().await.list.get(&module_id) {
826 Some(h) => match h.get(&class_id) {
827 Some(h) => self.html.replace(Arc::clone(h)),
828 None => self.html.take(),
829 },
830 None => self.html.take(),
831 };
832 #[cfg(not(debug_assertions))]
834 let l = match self.language.list.get(&self.session.get_lang_id()) {
835 Some(l) => match l.get(&module_id) {
836 Some(l) => match l.get(&class_id) {
837 Some(l) => self.lang.replace(Arc::clone(l)),
838 None => self.lang.take(),
839 },
840 None => self.lang.take(),
841 },
842 None => self.lang.take(),
843 };
844 #[cfg(debug_assertions)]
845 let l = match self.language.read().await.list.get(&self.session.get_lang_id()) {
846 Some(l) => match l.get(&module_id) {
847 Some(l) => match l.get(&class_id) {
848 Some(l) => self.lang.replace(Arc::clone(l)),
849 None => self.lang.take(),
850 },
851 None => self.lang.take(),
852 },
853 None => self.lang.take(),
854 };
855 let i = self.internal;
856 let p = match param {
857 Some(str) => self.param.replace(str),
858 None => self.param.take(),
859 };
860 let m = self.current_module_id;
861 self.current_module_id = module_id;
862 let c = self.current_class_id;
863 self.current_class_id = class_id;
864
865 self.internal = internal;
866
867 let res = a(self).await;
869
870 self.current_module_id = m;
871 self.current_class_id = c;
872 self.html = h;
873 self.lang = l;
874 self.internal = i;
875 self.param = p;
876 return Some(res);
877 }
878 }
879 }
880 }
881 None
882 }
883
884 fn error_route(action_err: Arc<Route>) -> Route {
885 Route::clone(&action_err)
886 }
887
888 async fn extract_route(
890 request: &Request,
891 cache: Arc<Mutex<CacheSys>>,
892 db: Arc<DB>,
893 action_index: Arc<Route>,
894 action_err: Arc<Route>,
895 ) -> Result<Route, Redirect> {
896 if db.in_use() {
897 let key = vec![fnv1a_64!("redirect"), fnv1a_64(request.url.as_bytes())];
899 match CacheSys::get(Arc::clone(&cache), &key).await {
900 Some(d) => match d {
901 Data::None => {}
902 Data::Redirect(r) => return Err(r),
903 _ => {
904 Log::warning(3000, Some(format!("{:?}", d)));
905 }
906 },
907 None => {
908 match db.query_prepare(fnv1a_64!("lib_get_redirect"), &[&request.url], false).await {
910 Some(v) => {
911 if v.is_empty() {
912 CacheSys::set(Arc::clone(&cache), &key, Data::None).await;
913 } else {
914 let row = if let Data::Vec(row) = unsafe { v.get_unchecked(0) } {
915 row
916 } else {
917 return Ok(Action::error_route(action_err));
918 };
919 if row.len() != 2 {
920 return Ok(Action::error_route(action_err));
921 }
922 let url = if let Data::String(url) = unsafe { row.get_unchecked(0) } {
923 url.to_owned()
924 } else {
925 return Ok(Action::error_route(action_err));
926 };
927 let permanently = if let Data::Bool(permanently) = unsafe { row.get_unchecked(1) } {
928 *permanently
929 } else {
930 return Ok(Action::error_route(action_err));
931 };
932 let r = Redirect { url, permanently };
933 CacheSys::set(Arc::clone(&cache), &key, Data::Redirect(r.clone())).await;
934 return Err(r);
935 }
936 }
937 None => return Ok(Action::error_route(action_err)),
938 }
939 }
940 }
941
942 let key = vec![fnv1a_64!("route"), fnv1a_64(request.url.as_bytes())];
944 match CacheSys::get(Arc::clone(&cache), &key[..]).await {
945 Some(d) => match d {
946 Data::None => {}
947 Data::Route(r) => return Ok(r),
948 _ => {
949 Log::warning(3001, Some(format!("{:?}", d)));
950 }
951 },
952 None => {
953 match db.query_prepare(fnv1a_64!("lib_get_route"), &[&request.url], false).await {
955 Some(v) => {
956 if v.is_empty() {
957 CacheSys::set(Arc::clone(&cache), &key, Data::None).await;
958 } else {
959 let row = if let Data::Vec(row) = unsafe { v.get_unchecked(0) } {
960 row
961 } else {
962 return Ok(Action::error_route(action_err));
963 };
964 if row.len() != 8 {
965 return Ok(Action::error_route(action_err));
966 }
967 let module = if let Data::String(module) = unsafe { row.get_unchecked(0) } {
968 module.to_owned()
969 } else {
970 return Ok(Action::error_route(action_err));
971 };
972 let class = if let Data::String(class) = unsafe { row.get_unchecked(1) } {
973 class.to_owned()
974 } else {
975 return Ok(Action::error_route(action_err));
976 };
977 let action = if let Data::String(action) = unsafe { row.get_unchecked(2) } {
978 action.to_owned()
979 } else {
980 return Ok(Action::error_route(action_err));
981 };
982 let param = match unsafe { row.get_unchecked(6) } {
983 Data::None => None,
984 Data::String(param) => {
985 if param.is_empty() {
986 None
987 } else {
988 Some(param.to_owned())
989 }
990 }
991 _ => return Ok(Action::error_route(action_err)),
992 };
993 let module_id = if let Data::I64(module_id) = unsafe { row.get_unchecked(3) } {
994 *module_id
995 } else {
996 return Ok(Action::error_route(action_err));
997 };
998 let class_id = if let Data::I64(class_id) = unsafe { row.get_unchecked(4) } {
999 *class_id
1000 } else {
1001 return Ok(Action::error_route(action_err));
1002 };
1003 let action_id = if let Data::I64(action_id) = unsafe { row.get_unchecked(5) } {
1004 *action_id
1005 } else {
1006 return Ok(Action::error_route(action_err));
1007 };
1008 let lang_id = match unsafe { row.get_unchecked(7) } {
1009 Data::None => None,
1010 Data::I64(lang_id) => Some(*lang_id),
1011 _ => return Ok(Action::error_route(action_err)),
1012 };
1013 let r = Route {
1014 module,
1015 class,
1016 action,
1017 module_id,
1018 class_id,
1019 action_id,
1020 param,
1021 lang_id,
1022 };
1023 CacheSys::set(Arc::clone(&cache), &key, Data::Route(r.clone())).await;
1024 return Ok(r);
1025 }
1026 }
1027 None => return Ok(Action::error_route(action_err)),
1028 }
1029 }
1030 }
1031 }
1032
1033 if request.url != "/" {
1034 let mut load: Vec<&str> = request.url.splitn(5, '/').collect();
1035 load.retain(|&x| !x.is_empty());
1036 let r = match load.len() {
1037 1 => {
1038 if db.in_use() {
1039 let module = unsafe { *load.get_unchecked(0) };
1040 Route {
1041 module: module.to_owned(),
1042 class: action_index.class.clone(),
1043 action: action_index.action.clone(),
1044 module_id: fnv1a_64(module.as_bytes()),
1045 class_id: action_index.class_id,
1046 action_id: action_index.action_id,
1047 param: None,
1048 lang_id: None,
1049 }
1050 } else {
1051 Route::default_install()
1052 }
1053 }
1054 2 => {
1055 if db.in_use() {
1056 let module = unsafe { *load.get_unchecked(0) };
1057 let class = unsafe { *load.get_unchecked(1) };
1058 Route {
1059 module: module.to_owned(),
1060 class: class.to_owned(),
1061 action: action_index.action.clone(),
1062 module_id: fnv1a_64(module.as_bytes()),
1063 class_id: fnv1a_64(class.as_bytes()),
1064 action_id: action_index.action_id,
1065 param: None,
1066 lang_id: None,
1067 }
1068 } else {
1069 Route::default_install()
1070 }
1071 }
1072 3 => {
1073 if db.in_use() {
1074 let module = unsafe { *load.get_unchecked(0) };
1075 let class = unsafe { *load.get_unchecked(1) };
1076 let action = unsafe { *load.get_unchecked(2) };
1077 Route {
1078 module: module.to_owned(),
1079 class: class.to_owned(),
1080 action: action.to_owned(),
1081 module_id: fnv1a_64(module.as_bytes()),
1082 class_id: fnv1a_64(class.as_bytes()),
1083 action_id: fnv1a_64(action.as_bytes()),
1084 param: None,
1085 lang_id: None,
1086 }
1087 } else {
1088 let install = Route::default_install();
1089 let action = unsafe { *load.get_unchecked(2) };
1090 Route {
1091 module: install.module.to_owned(),
1092 class: install.class.to_owned(),
1093 action: action.to_owned(),
1094 module_id: install.module_id,
1095 class_id: install.class_id,
1096 action_id: fnv1a_64(action.as_bytes()),
1097 param: None,
1098 lang_id: None,
1099 }
1100 }
1101 }
1102 4 => {
1103 if db.in_use() {
1104 let module = unsafe { *load.get_unchecked(0) };
1105 let class = unsafe { *load.get_unchecked(1) };
1106 let action = unsafe { *load.get_unchecked(2) };
1107 let param = unsafe { *load.get_unchecked(3) };
1108 Route {
1109 module: module.to_owned(),
1110 class: class.to_owned(),
1111 action: action.to_owned(),
1112 module_id: fnv1a_64(module.as_bytes()),
1113 class_id: fnv1a_64(class.as_bytes()),
1114 action_id: fnv1a_64(action.as_bytes()),
1115 param: Some(param.to_owned()),
1116 lang_id: None,
1117 }
1118 } else {
1119 let install = Route::default_install();
1120 let action = unsafe { *load.get_unchecked(2) };
1121 let param = unsafe { *load.get_unchecked(3) };
1122 Route {
1123 module: install.module.to_owned(),
1124 class: install.class.to_owned(),
1125 action: action.to_owned(),
1126 module_id: install.module_id,
1127 class_id: install.class_id,
1128 action_id: fnv1a_64(action.as_bytes()),
1129 param: Some(param.to_owned()),
1130 lang_id: None,
1131 }
1132 }
1133 }
1134 _ => {
1135 if db.in_use() {
1136 Route::clone(&action_index)
1137 } else {
1138 Route::default_install()
1139 }
1140 }
1141 };
1142 Ok(r)
1143 } else if db.in_use() {
1144 Ok(Route::clone(&action_index))
1145 } else {
1146 Ok(Route::default_install())
1147 }
1148 }
1149
1150 fn format_route(module: &str, class: &str, action: &str, param: Option<&str>) -> String {
1151 match param {
1152 Some(s) => {
1153 format!("/{}/{}/{}/{}", module, class, action, s)
1154 }
1155 None => format!("/{}/{}/{}", module, class, action),
1156 }
1157 }
1158}