1use inquire::error::InquireResult;
28use inquire::validator::Validation;
29use inquire::Text;
30
31use crate::actions::h3::Action;
32use crate::prompts::h3;
33use crate::prompts::h3::errors::prompt_transport_or_app_error;
34use crate::prompts::h3::prompt_yes_no;
35use crate::StreamIdAllocator;
36
37use super::squish_suggester;
38use super::SuggestionResult;
39use super::AUTO_PICK;
40use super::EMPTY_PICKS;
41use super::ESC_TO_RET;
42use super::STREAM_ID_PROMPT;
43
44const CONTROL_STREAM: &str = "Control Stream";
45const PUSH_STREAM: &str = "Push Stream";
46const QPACK_ENCODER: &str = "QPACK Encoder Stream";
47const QPACK_DECODER: &str = "QPACK Decoder Stream";
48
49fn validate_stream_id(id: &str) -> SuggestionResult<Validation> {
50 if id.is_empty() {
51 return Ok(Validation::Valid);
52 }
53
54 h3::validate_varint(id)
55}
56
57pub fn autopick_stream_id(
58 sid_alloc: &mut StreamIdAllocator,
59) -> InquireResult<u64> {
60 let stream_id = Text::new(STREAM_ID_PROMPT)
61 .with_placeholder(EMPTY_PICKS)
62 .with_help_message(ESC_TO_RET)
63 .with_validator(validate_stream_id)
64 .prompt()?;
65
66 Ok(match stream_id.as_str() {
67 "" => {
68 let id = sid_alloc.take_next_id();
69 println!("{AUTO_PICK}={id}");
70 id
71 },
72
73 _ => stream_id.parse::<u64>().unwrap(),
74 })
75}
76
77pub fn prompt_open_uni_stream(
78 sid_alloc: &mut StreamIdAllocator,
79) -> InquireResult<Action> {
80 let stream_id = autopick_stream_id(sid_alloc)?;
81 let stream_type = Text::new("stream type:")
82 .with_validator(validate_stream_type)
83 .with_autocomplete(&stream_type_suggestor)
84 .prompt()?;
85
86 let ty = match stream_type.as_str() {
87 CONTROL_STREAM => 0x0,
88 PUSH_STREAM => 0x1,
89 QPACK_ENCODER => 0x2,
90 QPACK_DECODER => 0x3,
91 _ => stream_type.parse::<u64>().unwrap(),
92 };
93
94 let fin_stream = prompt_fin_stream()?;
95
96 Ok(Action::OpenUniStream {
97 stream_id,
98 fin_stream,
99 stream_type: ty,
100 expected_result: Default::default(),
101 })
102}
103
104fn validate_stream_type(id: &str) -> SuggestionResult<Validation> {
105 if matches!(
106 id,
107 CONTROL_STREAM | PUSH_STREAM | QPACK_ENCODER | QPACK_DECODER
108 ) {
109 return Ok(Validation::Valid);
110 }
111
112 h3::validate_varint(id)
113}
114
115fn stream_type_suggestor(val: &str) -> SuggestionResult<Vec<String>> {
116 let suggestions = [CONTROL_STREAM, PUSH_STREAM, QPACK_ENCODER, QPACK_DECODER];
117
118 squish_suggester(&suggestions, val)
119}
120
121pub fn prompt_fin_stream() -> InquireResult<bool> {
122 prompt_yes_no("fin stream:")
123}
124
125pub fn prompt_reset_stream() -> InquireResult<Action> {
126 let (stream_id, error_code) = prompt_close_stream()?;
127
128 Ok(Action::ResetStream {
129 stream_id,
130 error_code,
131 })
132}
133
134pub fn prompt_stop_sending() -> InquireResult<Action> {
135 let (stream_id, error_code) = prompt_close_stream()?;
136
137 Ok(Action::StopSending {
138 stream_id,
139 error_code,
140 })
141}
142
143fn prompt_close_stream() -> InquireResult<(u64, u64)> {
144 let id = h3::prompt_stream_id()?;
145
146 let (_, error_code) = prompt_transport_or_app_error()?;
147
148 Ok((id, error_code))
149}