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 })
101}
102
103fn validate_stream_type(id: &str) -> SuggestionResult<Validation> {
104 if matches!(
105 id,
106 CONTROL_STREAM | PUSH_STREAM | QPACK_ENCODER | QPACK_DECODER
107 ) {
108 return Ok(Validation::Valid);
109 }
110
111 h3::validate_varint(id)
112}
113
114fn stream_type_suggestor(val: &str) -> SuggestionResult<Vec<String>> {
115 let suggestions = [CONTROL_STREAM, PUSH_STREAM, QPACK_ENCODER, QPACK_DECODER];
116
117 squish_suggester(&suggestions, val)
118}
119
120pub fn prompt_fin_stream() -> InquireResult<bool> {
121 prompt_yes_no("fin stream:")
122}
123
124pub fn prompt_reset_stream() -> InquireResult<Action> {
125 let (stream_id, error_code) = prompt_close_stream()?;
126
127 Ok(Action::ResetStream {
128 stream_id,
129 error_code,
130 })
131}
132
133pub fn prompt_stop_sending() -> InquireResult<Action> {
134 let (stream_id, error_code) = prompt_close_stream()?;
135
136 Ok(Action::StopSending {
137 stream_id,
138 error_code,
139 })
140}
141
142fn prompt_close_stream() -> InquireResult<(u64, u64)> {
143 let id = h3::prompt_stream_id()?;
144
145 let (_, error_code) = prompt_transport_or_app_error()?;
146
147 Ok((id, error_code))
148}