mod_installer/
weidu_parser.rs

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