mod_installer/
weidu_parser.rs1use std::{
2 sync::{
3 atomic::{AtomicUsize, Ordering},
4 mpsc::{Receiver, Sender, TryRecvError},
5 Arc, RwLock,
6 },
7 thread,
8};
9
10use crate::{config::parser_config::ParserConfig, state::State, utils::sleep};
11
12#[derive(Debug)]
13enum ParserState {
14 CollectingQuestion,
15 WaitingForMoreQuestionContent,
16 LookingForInterestingOutput,
17}
18
19pub(crate) fn parse_raw_output(
20 sender: Sender<State>,
21 receiver: Receiver<String>,
22 parser_config: Arc<ParserConfig>,
23 wait_count: Arc<AtomicUsize>,
24 log: Arc<RwLock<String>>,
25 timeout: usize,
26 tick: u64,
27) {
28 let mut current_state = ParserState::LookingForInterestingOutput;
29 let mut question = String::new();
30 sender
31 .send(State::InProgress)
32 .expect("Failed to send process start event");
33 thread::spawn(move || loop {
34 match receiver.try_recv() {
35 Ok(string) => match current_state {
36 ParserState::CollectingQuestion | ParserState::WaitingForMoreQuestionContent => {
37 if let Ok(mut writer) = log.write() {
38 writer.push_str(&string);
39 }
40 if parser_config.useful_status_words.contains(&string) {
41 log::debug!(
42 "Weidu seems to know an answer for the last question, ignoring it"
43 );
44 current_state = ParserState::LookingForInterestingOutput;
45 question.clear();
46 } else {
47 log::debug!("Appending line '{string}' to user question");
48 question.push_str(&string);
49 current_state = ParserState::CollectingQuestion;
50 }
51 }
52 ParserState::LookingForInterestingOutput => {
53 if let Ok(mut writer) = log.write() {
54 writer.push_str(&string);
55 }
56 let installer_state = parser_config.detect_weidu_finished_state(&string);
57 if installer_state != State::InProgress {
58 sender
59 .send(installer_state)
60 .expect("Failed to send process error event");
61 break;
62 } else if parser_config.string_looks_like_question(&string) {
63 log::debug!(
64 "Changing parser state to '{:?}' due to line {}",
65 ParserState::CollectingQuestion,
66 string
67 );
68 current_state = ParserState::CollectingQuestion;
69 question.push_str(string.as_str());
70 }
71 if !string.trim().is_empty() {
72 log::trace!("{string}");
73 }
74 }
75 },
76 Err(TryRecvError::Empty) => {
77 match current_state {
78 ParserState::CollectingQuestion => {
79 log::debug!(
80 "Changing parser state to '{:?}'",
81 ParserState::WaitingForMoreQuestionContent
82 );
83 current_state = ParserState::WaitingForMoreQuestionContent;
84 }
85 ParserState::WaitingForMoreQuestionContent => {
86 log::debug!("No new weidu output, sending question to user");
87 sender
88 .send(State::RequiresInput { question })
89 .expect("Failed to send question");
90 current_state = ParserState::LookingForInterestingOutput;
91 question = String::new();
92 }
93 _ => {
94 if wait_count.load(Ordering::Relaxed) >= timeout {
95 sender
96 .send(State::TimedOut)
97 .expect("Could send timeout error");
98 }
99 }
101 }
102 sleep(tick);
103 }
104 Err(TryRecvError::Disconnected) => {
105 sender
106 .send(State::Completed)
107 .expect("Failed to send process end event");
108 break;
109 }
110 }
111 });
112}