1use std::borrow::Cow;
11use std::sync::Arc;
12use std::sync::Mutex;
13use wda::{GeckoDriver, WdaError, WdaSett, WdcError, WebDrvAstn};
14
15use clap::Arg as ClapArg;
16use clap::ArgAction as ClapArgAction;
17use clap::ArgMatches as ClapArgMatches;
18use clap::Command as ClapCommand;
19
20pub mod error;
21
22pub use error::MafaError;
23use error::Result;
24
25#[macro_use]
26mod private_macros;
27
28pub mod mafadata;
29use mafadata::MafaData;
30
31pub mod ev_ntf;
32use ev_ntf::EurKind;
33use ev_ntf::EventNotifier;
34
35#[cfg(any(feature = "twtl", feature = "gtrans", feature = "camd"))]
36mod comm;
37#[cfg(any(feature = "twtl", feature = "gtrans", feature = "camd"))]
38use comm::CacheMechanism;
39
40#[cfg(feature = "twtl")]
41pub mod twtl;
42
43#[cfg(feature = "gtrans")]
44pub mod gtrans;
45
46#[cfg(feature = "camd")]
47pub mod camd;
48
49#[derive(Debug, Default)]
50pub struct MafaInput {
51 pub silent: bool,
52 pub nocolor: bool,
53 pub ascii: bool,
54 pub wrap_width: u16,
55 pub wrap_may_break: bool,
56 pub tout_page_load: u32,
57 pub tout_script: u32,
58 pub socks5: String,
59 pub gui: bool,
60 pub list_profile: bool,
61 pub use_profile: String,
62 cachm: CacheMechanism,
63 pub elap: bool,
64}
65
66impl MafaInput {
67 pub fn from_ca_matched(ca_matched: &ClapArgMatches) -> Result<Self> {
68 let mut mafa_in = MafaInput::default();
69
70 if ca_matched.get_flag(opts::SilentMode::id()) {
72 mafa_in.silent = true;
73 }
74
75 if ca_matched.get_flag(opts::NoColorMode::id()) {
77 mafa_in.nocolor = true;
78 }
79
80 if ca_matched.get_flag(opts::AsciiMode::id()) {
82 mafa_in.ascii = true;
83 }
84
85 if let Ok(Some(optval)) = ca_matched.try_get_one::<String>(opts::WrapWidth::id()) {
87 let intval =
88 u16::from_str_radix(&optval, 10).map_err(|_| MafaError::InvalidWrapWidth)?;
89 mafa_in.wrap_width = intval;
90 }
91
92 if ca_matched.get_flag(opts::WrapMayBreak::id()) {
94 mafa_in.wrap_may_break = true;
95 }
96
97 if let Ok(Some(optval)) = ca_matched.try_get_one::<String>(opts::TimeoutPageLoad::id()) {
99 mafa_in.tout_page_load = u32::from_str_radix(&optval, 10)
100 .or_else(|_| Err(MafaError::InvalidTimeoutPageLoad))?;
101 } else {
102 mafa_in.tout_page_load = u32::from_str_radix(opts::TimeoutPageLoad::def_val(), 10)
103 .or_else(|_| Err(MafaError::Buggy))?;
104 }
105
106 if let Ok(Some(optval)) = ca_matched.try_get_one::<String>(opts::TimeoutScript::id()) {
108 mafa_in.tout_script = u32::from_str_radix(&optval, 10)
109 .or_else(|_| Err(MafaError::InvalidTimeoutScript))?;
110 } else {
111 mafa_in.tout_script = u32::from_str_radix(opts::TimeoutScript::def_val(), 10)
112 .or_else(|_| Err(MafaError::Buggy))?;
113 }
114
115 if let Ok(Some(val)) = ca_matched.try_get_one::<String>(opts::Socks5Proxy::id()) {
117 mafa_in.socks5 = val.clone();
118 }
119
120 if ca_matched.get_flag(opts::GuiMode::id()) {
122 mafa_in.gui = true;
123 }
124
125 if ca_matched.get_flag(opts::Elapsed::id()) {
127 mafa_in.elap = true;
128 }
129
130 if let Ok(Some(optval)) = ca_matched.try_get_one::<String>(opts::CacheMech::id()) {
132 mafa_in.cachm = CacheMechanism::from_str(optval);
133 }
134
135 if ca_matched.get_flag(opts::ListProfile::id()) {
137 mafa_in.list_profile = true;
138 }
139
140 if let Ok(Some(val)) = ca_matched.try_get_one::<String>(opts::UseProfile::id()) {
142 mafa_in.use_profile = val.clone();
143 }
144
145 dbgg!(&mafa_in);
146
147 Ok(mafa_in)
148 }
149}
150
151pub mod opts {
154 use core::ops::Range;
155 #[allow(unused)]
156 use core::ops::RangeFrom;
157
158 pub struct SilentMode;
159 impl SilentMode {
160 #[inline]
161 pub fn id() -> &'static str {
162 "SILENT_MODE"
163 }
164 #[inline]
165 pub fn longopt() -> &'static str {
166 "silent"
167 }
168 #[inline]
169 pub fn helper() -> &'static str {
170 "Enable silent mode"
171 }
172 #[inline]
173 pub fn long_helper() -> String {
174 let bf = "Enable silent mode
175
176Any insignificant output redirected to standard output will be hidden.";
177
178 let mut af_buf = [0u8; 256];
179
180 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
181 .unwrap()
182 .wrap()
183 .unwrap();
184
185 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
186 }
187 }
188
189 pub struct NoColorMode;
190 impl NoColorMode {
191 #[inline]
192 pub fn id() -> &'static str {
193 "NOCOLOR_MODE"
194 }
195 #[inline]
196 pub fn longopt() -> &'static str {
197 "nocolor"
198 }
199 #[inline]
200 pub fn helper() -> &'static str {
201 "Enable non-color mode"
202 }
203 #[inline]
204 pub fn long_helper() -> String {
205 let bf = "Enable non-color mode
206
207Any output will be printed without color. Default is with color.";
208
209 let mut af_buf = [0u8; 256];
210
211 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
212 .unwrap()
213 .wrap()
214 .unwrap();
215
216 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
217 }
218 }
219
220 pub struct AsciiMode;
221 impl AsciiMode {
222 #[inline]
223 pub fn id() -> &'static str {
224 "ASCIIMODE"
225 }
226 #[inline]
227 pub fn longopt() -> &'static str {
228 "ascii"
229 }
230 #[inline]
231 pub fn helper() -> &'static str {
232 "Use classical ASCII style"
233 }
234 #[inline]
235 pub fn long_helper() -> String {
236 let bf = r#"Use classical ASCII style
237
238ASCII style only allows ASCII characters to mafa's meta information displaying. Default is Unicode mode, which allows more distinguishable characters for displaying.
239
240NOTE: the minimum is 18, any value smaller than 18 will fallback to 80."#;
241 let mut af_buf = [0u8; 128];
242
243 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
244 .unwrap()
245 .wrap()
246 .unwrap();
247
248 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
249 }
250 }
251
252 pub struct WrapWidth;
253 impl WrapWidth {
254 #[inline]
255 pub fn id() -> &'static str {
256 "WRAPWIDTH"
257 }
258 #[inline]
259 pub fn n_args() -> Range<usize> {
260 1..2
261 }
262 #[inline]
263 pub fn longopt() -> &'static str {
264 "wrap-width"
265 }
266 #[inline]
267 pub fn def_val() -> &'static str {
268 "80"
269 }
270 #[inline]
271 pub fn helper() -> &'static str {
272 "Wrap output with a width limit"
273 }
274 #[inline]
275 pub fn long_helper() -> String {
276 let bf = r#"Wrap output with a width limit
277
278NOTE: the minimun is 18, any value smaller than 18 will fallback to 80."#;
279 let mut af_buf = [0u8; 128];
280
281 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
282 .unwrap()
283 .wrap()
284 .unwrap();
285
286 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
287 }
288 }
289
290 pub struct WrapMayBreak;
291 impl WrapMayBreak {
292 #[inline]
293 pub fn id() -> &'static str {
294 "WRAPMAYBREAK"
295 }
296 #[inline]
297 pub fn longopt() -> &'static str {
298 "wrap-may-break"
299 }
300 #[inline]
301 pub fn helper() -> &'static str {
302 "Wrap output in MayBreak style"
303 }
304 #[inline]
305 pub fn long_helper() -> String {
306 let bf = r#"Wrap output in MayBreak style
307
308Default is "NoBreak" style. This change the style to "MayBreak".
309
310NOTE: This is a hint option, components may ignore it.
311
312NOTE: "NoBreak" suits for languages that rely om ASCII SPACE to delimit words. "MayBreak" suits for otherwise languages. See more details in Bwrap documentation: https://docs.rs/bwrap/latest/bwrap/enum.WrapStyle.html."#;
313 let mut af_buf = [0u8; 512];
314
315 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
316 .unwrap()
317 .wrap()
318 .unwrap();
319
320 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
321 }
322 }
323
324 pub struct GuiMode;
325 impl GuiMode {
326 #[inline]
327 pub fn id() -> &'static str {
328 "GUI_MODE"
329 }
330 #[inline]
331 pub fn longopt() -> &'static str {
332 "gui"
333 }
334 #[inline]
335 pub fn helper() -> &'static str {
336 "Enable GUI mode"
337 }
338 #[inline]
339 pub fn long_helper() -> String {
340 let bf = "Enable GUI mode
341
342Run the underlying web browser in GUI mode.
343
344NOTE: when GUI mode is on, any user operation on web browser interface MAY affect mafa's correctness, use with caution.";
345
346 let mut af_buf = [0u8; 256];
347
348 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
349 .unwrap()
350 .wrap()
351 .unwrap();
352
353 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
354 }
355 }
356
357 pub struct ListProfile;
358 impl ListProfile {
359 #[inline]
360 pub fn id() -> &'static str {
361 "LIST_PROFILE"
362 }
363 #[inline]
364 pub fn longopt() -> &'static str {
365 "list-p"
366 }
367 #[inline]
368 pub fn helper() -> &'static str {
369 "List all existing browser profiles"
370 }
371 #[inline]
372 pub fn long_helper() -> String {
373 let bf = "List all existing profiles's ID
374
375Profiles' ID is surrounded by a pair of brackets:
376...
377<PROFILE ID>
378<PROFILE ID>
379<PROFILE ID>
380...";
381
382 let mut af_buf = [0u8; 256];
383
384 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
385 .unwrap()
386 .wrap()
387 .unwrap();
388
389 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
390 }
391 }
392
393 pub struct UseProfile;
394 impl UseProfile {
395 #[inline]
396 pub fn id() -> &'static str {
397 "USE_PROFILE"
398 }
399 #[inline]
400 pub fn n_args() -> Range<usize> {
401 1..2
402 }
403 #[inline]
404 pub fn longopt() -> &'static str {
405 "profile"
406 }
407 #[inline]
408 pub fn shortopt() -> char {
409 'p'
410 }
411 #[inline]
412 pub fn helper() -> &'static str {
413 "Use specific browser profile"
414 }
415 #[inline]
416 pub fn long_helper() -> String {
417 let bf = "Use specific profile ID
418
419Profile IDs are strings including ONLY letters, nimbers or hyphens.
420
421NOTE: the profile will be created if not existing. Browser profiles' size is non-trivial, use with caution.
422";
423
424 let mut af_buf = [0u8; 256];
425
426 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
427 .unwrap()
428 .wrap()
429 .unwrap();
430
431 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
432 }
433 }
434
435 pub struct Socks5Proxy;
436 impl Socks5Proxy {
437 #[inline]
438 pub fn id() -> &'static str {
439 "SOCKS5_PROXY"
440 }
441 #[inline]
442 pub fn n_args() -> Range<usize> {
443 1..2
444 }
445 #[inline]
446 pub fn longopt() -> &'static str {
447 "socks5"
448 }
449 #[inline]
450 pub fn helper() -> &'static str {
451 "Fetch data through SOCKS5 praxy "
452 }
453 #[inline]
454 pub fn long_helper() -> String {
455 let bf = "Fetch data through SOCKS5 proxy
456
457The default SOCKS5 proxy used by the underlying web browser to fetch data. This is also used by mafa to fetch webdriver server binaries when initialization.";
458
459 let mut af_buf = [0u8; 256];
460
461 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
462 .unwrap()
463 .wrap()
464 .unwrap();
465
466 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
467 }
468 }
469
470 pub struct TimeoutPageLoad;
471 impl TimeoutPageLoad {
472 #[inline]
473 pub fn id() -> &'static str {
474 "TIMEOUT_PAGE_LOAD"
475 }
476 #[inline]
477 pub fn longopt() -> &'static str {
478 "timeout-pageload"
479 }
480 #[inline]
481 pub fn n_args() -> Range<usize> {
482 1..2
483 }
484 #[inline]
485 pub fn def_val() -> &'static str {
486 "30000"
487 }
488 #[inline]
489 pub fn helper() -> &'static str {
490 "Timeout for page loading(ms)"
491 }
492 #[inline]
493 pub fn long_helper() -> String {
494 let bf = "Timeout for page loading(ms)
495
496The default timeout for loading web page(i.e., opening a website). Refer to WebDriver standard(https://www.w3.org/TR/webdriver2/#timeouts) for more details.
497
498NOTE: customizing this option mostly brings the negative effect for page loading, do not use unless you know what you are doing.";
499 let mut af_buf = [0u8; 512];
500
501 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
502 .unwrap()
503 .wrap()
504 .unwrap();
505
506 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
507 }
508 }
509
510 pub struct TimeoutScript;
511 impl TimeoutScript {
512 #[inline]
513 pub fn id() -> &'static str {
514 "TIMEOUT_SCRIPT"
515 }
516 #[inline]
517 pub fn longopt() -> &'static str {
518 "timeout-script"
519 }
520 #[inline]
521 pub fn n_args() -> Range<usize> {
522 1..2
523 }
524 #[inline]
525 pub fn def_val() -> &'static str {
526 "30000"
527 }
528 #[inline]
529 pub fn helper() -> &'static str {
530 "Timeout for script evaluation(ms)"
531 }
532 #[inline]
533 pub fn long_helper() -> String {
534 let bf = "Timeout for script evaluation(ms)
535
536The default timeout for script evaluation(i.e., evaluating JavaScript synchronously or asynchronously). Refer to WebDriver standard(https://www.w3.org/TR/webdriver2/#timeouts) for more details.
537
538NOTE: customizing this option mostly brings the negative effect for script evaluation, do not use unless you know what you are doing.";
539 let mut af_buf = [0u8; 512];
540
541 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
542 .unwrap()
543 .wrap()
544 .unwrap();
545
546 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
547 }
548 }
549
550 pub struct CacheMech;
551 impl CacheMech {
552 #[inline]
553 pub fn id() -> &'static str {
554 "CACHE_MECHNISM"
555 }
556 #[inline]
557 pub fn n_args() -> Range<usize> {
558 1..2
559 }
560 #[inline]
561 pub fn longopt() -> &'static str {
562 "cache"
563 }
564 #[inline]
565 pub fn def_val() -> &'static str {
566 "LOCAL"
567 }
568 #[inline]
569 pub fn helper() -> &'static str {
570 "The caching mechanism"
571 }
572 #[inline]
573 pub fn long_helper() -> String {
574 let bf = r#"The caching mechanism
575
576Avvilable values are: LOCAL, REMOTE, NO.
577
578LOCAL instructs mafa to use local cache, typically located in mafa's dedicated cache directory; REMOTE instructs mafa to use remote cache, which is stored in a dedicated remote repository, note that this option overrides all existing caches; NO instructs mafa to build cache freshly, this may need more time, compared to other mechanisms.
579
580Performance : LOCAL > REMOTE > NO
581Stability : NO > REMOTE > LOCAL"#;
582 let mut af_buf = [0u8; 512];
583
584 let rl = bwrap::Wrapper::new(bf, 70, &mut af_buf)
585 .unwrap()
586 .wrap()
587 .unwrap();
588
589 String::from_utf8_lossy(&af_buf[0..rl]).to_string()
590 }
591 }
592
593 pub struct Elapsed;
594 impl Elapsed {
595 #[inline]
596 pub fn id() -> &'static str {
597 "ELAPSED"
598 }
599 #[inline]
600 pub fn longopt() -> &'static str {
601 "elap"
602 }
603 #[inline]
604 pub fn helper() -> &'static str {
605 "Report the time cost in major phases"
606 }
607 }
608}
609
610pub fn get_cmd() -> ClapCommand {
611 let opt_silient = {
612 type O = opts::SilentMode;
613 ClapArg::new(O::id())
614 .long(O::longopt())
615 .action(ClapArgAction::SetTrue)
616 .help(O::helper())
617 .long_help(O::long_helper())
618 };
619
620 let opt_nocolor = {
621 type O = opts::NoColorMode;
622 ClapArg::new(O::id())
623 .long(O::longopt())
624 .action(ClapArgAction::SetTrue)
625 .help(O::helper())
626 .long_help(O::long_helper())
627 };
628
629 let opt_ascii = {
630 type O = opts::AsciiMode;
631 ClapArg::new(O::id())
632 .long(O::longopt())
633 .action(ClapArgAction::SetTrue)
634 .help(O::helper())
635 };
636
637 let opt_wrapwidth = {
638 type O = opts::WrapWidth;
639 ClapArg::new(O::id())
640 .long(O::longopt())
641 .default_value(O::def_val())
642 .help(O::helper())
643 .long_help(O::long_helper())
644 };
645
646 let opt_wrapmaybreak = {
647 type O = opts::WrapMayBreak;
648 ClapArg::new(O::id())
649 .long(O::longopt())
650 .action(ClapArgAction::SetTrue)
651 .help(O::helper())
652 .long_help(O::long_helper())
653 };
654
655 let opt_gui = {
656 type O = opts::GuiMode;
657 ClapArg::new(O::id())
658 .long(O::longopt())
659 .action(ClapArgAction::SetTrue)
660 .help(O::helper())
661 .long_help(O::long_helper())
662 };
663
664 let opt_socks5 = {
665 type O = opts::Socks5Proxy;
666 ClapArg::new(O::id())
667 .long(O::longopt())
668 .num_args(O::n_args())
669 .help(O::helper())
670 .long_help(O::long_helper())
671 };
672
673 let opt_tout_pageload = {
674 type O = opts::TimeoutPageLoad;
675 ClapArg::new(O::id())
676 .long(O::longopt())
677 .num_args(O::n_args())
678 .default_value(O::def_val())
679 .help(O::helper())
680 .long_help(O::long_helper())
681 };
682
683 let opt_tout_script = {
684 type O = opts::TimeoutScript;
685 ClapArg::new(O::id())
686 .long(O::longopt())
687 .num_args(O::n_args())
688 .default_value(O::def_val())
689 .help(O::helper())
690 .long_help(O::long_helper())
691 };
692
693 let opt_cachm = {
694 type O = opts::CacheMech;
695 ClapArg::new(O::id())
696 .long(O::longopt())
697 .default_value(O::def_val())
698 .help(O::helper())
699 .long_help(O::long_helper())
700 };
701
702 let opt_elapsed = {
703 type O = opts::Elapsed;
704 ClapArg::new(O::id())
705 .long(O::longopt())
706 .action(ClapArgAction::SetTrue)
707 .help(O::helper())
708 };
709
710 let opt_list_profile = {
711 type O = opts::ListProfile;
712 ClapArg::new(O::id())
713 .long(O::longopt())
714 .action(ClapArgAction::SetTrue)
715 .help(O::helper())
716 .long_help(O::long_helper())
717 };
718
719 let opt_use_profile = {
720 type O = opts::UseProfile;
721 ClapArg::new(O::id())
722 .long(O::longopt())
723 .short(O::shortopt())
724 .num_args(O::n_args())
725 .help(O::helper())
726 .long_help(O::long_helper())
727 };
728
729 static HELPER_TXT: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| {
730 let mut s = format!("{}\ncomponents: ", clap::crate_version!());
731 #[cfg(feature = "imode")]
732 {
733 s += "IMODE ";
734 }
735 #[cfg(feature = "gtrans")]
736 {
737 s += "GTRANS ";
738 }
739 #[cfg(feature = "twtl")]
740 {
741 s += "TWTL ";
742 }
743 #[cfg(feature = "camd")]
744 {
745 s += "CAMD ";
746 }
747
748 s += "\n\n";
749 s += &format!("Copyright (C) 2023 {}.", clap::crate_authors!());
750 s += "
751This is free software. You may redistribute copies of it under the terms of
752the GNU General Public License <https://www.gnu.org/licenses/gpl.html>.
753There is NO WARRANTY, to the extent permitted by law.";
754
755 s
756 });
757
758 let cmd_mafa = ClapCommand::new("mafa")
759 .version(clap::crate_version!())
760 .long_version(HELPER_TXT.as_str())
761 .about(clap::crate_description!());
762
763 #[cfg(feature = "imode")]
764 let cmd_mafa = cmd_mafa.subcommand(
765 ClapCommand::new("i")
766 .about("Enter interactive mode")
767 .long_about(
768 "Enter interactive mode
769
770With interactive mode, mafa's components interact with websites statefully,
771performing tasks without full initializtion of the underlying WebDriver,
772this usually results in faster performance.
773
774Note that under interactive mode, components' options are identical to
775ones under normal mode, i.e., -h for short help, --help for long help.
776",
777 ),
778 );
779
780 #[cfg(feature = "twtl")]
781 let cmd_mafa = cmd_mafa.subcommand(twtl::get_cmd());
782
783 #[cfg(feature = "gtrans")]
784 let cmd_mafa = cmd_mafa.subcommand(gtrans::get_cmd());
785
786 #[cfg(feature = "camd")]
787 let cmd_mafa = cmd_mafa.subcommand(camd::get_cmd());
788
789 let cmd_mafa = cmd_mafa
790 .arg(opt_silient)
791 .arg(opt_nocolor)
792 .arg(opt_ascii)
793 .arg(opt_wrapwidth)
794 .arg(opt_wrapmaybreak)
795 .arg(opt_gui)
796 .arg(opt_socks5)
797 .arg(opt_tout_pageload)
798 .arg(opt_tout_script)
799 .arg(opt_cachm)
800 .arg(opt_elapsed)
801 .arg(opt_list_profile)
802 .arg(opt_use_profile);
803
804 cmd_mafa
805}
806
807#[derive(Debug)]
810pub struct MafaClient<'a, 'b, 'c, I, C> {
811 mafad: &'a MafaData,
812 ntf: Arc<Mutex<EventNotifier>>,
813 input: &'b MafaInput,
814 sub_input: I,
815 wda: &'c WebDrvAstn<GeckoDriver>,
816 caches: Vec<C>,
817}
818
819impl<'a, 'b, 'c, I, C: Default> MafaClient<'a, 'b, 'c, I, C> {
820 pub fn new(
821 mafad: &'a MafaData,
822 ntf: Arc<Mutex<EventNotifier>>,
823 mafa_in: &'b MafaInput,
824 sub_in: I,
825 wda_inst: &'c WebDrvAstn<GeckoDriver>,
826 ) -> Self {
827 MafaClient {
828 mafad,
829 ntf,
830 input: mafa_in,
831 sub_input: sub_in,
832 wda: wda_inst,
833 caches: Default::default(),
834 }
835 }
836
837 pub fn set_sub_input(&mut self, newin: I) {
838 self.sub_input = newin;
839 }
840}
841
842fn get_wda_setts(mafa_in: &MafaInput) -> Vec<WdaSett> {
843 let mut wda_setts = vec![];
844
845 if !mafa_in.gui {
847 wda_setts.push(WdaSett::NoGui);
848 }
849
850 if comm::is_valid_socks5(&mafa_in.socks5) {
852 wda_setts.push(WdaSett::PrepareUseSocksProxy(Cow::Borrowed(
853 &mafa_in.socks5,
854 )));
855 wda_setts.push(WdaSett::Socks5Proxy(Cow::Borrowed(&mafa_in.socks5)));
856 wda_setts.push(WdaSett::ProxyDnsSocks5);
857 }
858
859 wda_setts.push(WdaSett::PageLoadTimeout(mafa_in.tout_page_load));
861
862 wda_setts.push(WdaSett::ScriptTimeout(mafa_in.tout_script));
864
865 if mafa_in.use_profile.len() > 0 {
867 wda_setts.push(WdaSett::BrowserProfileId(Cow::Borrowed(
868 &mafa_in.use_profile,
869 )))
870 }
871
872 dbgg!(&wda_setts);
873
874 wda_setts
875}
876
877pub fn init_wda(mafa_in: &MafaInput) -> Result<WebDrvAstn<GeckoDriver>> {
878 let wda_inst: WebDrvAstn<GeckoDriver>;
879 let wda_setts = get_wda_setts(&mafa_in);
880 dbgg!(&wda_setts);
881 match WebDrvAstn::<GeckoDriver>::new(wda_setts) {
882 Ok(ret) => wda_inst = ret,
883 Err(err_wda) => match err_wda {
884 WdaError::WdcNotReady(WdcError::BadDrvCmd(err, msg), _) => {
885 if msg.contains("socksProxy is not a valid URL") {
886 return Err(MafaError::InvalidSocks5Proxy);
887 } else {
888 return Err(MafaError::WebDrvCmdRejected(err, msg));
889 }
890 }
891 WdaError::InvalidBrowserProfileId => return Err(MafaError::InvalidUseProfile),
892 WdaError::BrowserBinaryNotFound => return Err(MafaError::FirefoxNotFound),
893 _ => {
894 return Err(MafaError::UnexpectedWda(err_wda));
895 }
896 },
897 };
898
899 Ok(wda_inst)
900}