@@ -30,64 +30,67 @@ pub async fn get_content<S>(input_source: Option<S>) -> Result<String>
3030where
3131 S : Into < String > ,
3232{
33- get_content_with_reader ( input_source, tokio:: io:: stdin ( ) ) . await
33+ match input_source {
34+ Some ( source) => get_content_from_source ( source. into ( ) ) . await ,
35+ None => get_content_with_stdin ( tokio:: io:: stdin ( ) ) . await ,
36+ }
3437}
3538
36- /// Internal function that accepts a custom reader
37- async fn get_content_with_reader < S , R > ( input_source : Option < S > , mut reader : R ) -> Result < String >
39+ /// Reads network configuration content from the provided reader.
40+ async fn get_content_with_stdin < R > ( mut reader : R ) -> Result < String >
3841where
39- S : Into < String > ,
4042 R : tokio:: io:: AsyncRead + Unpin ,
4143{
42- let input_source = match input_source {
43- Some ( source) => source. into ( ) ,
44- // Read from provided reader when no input source is provided
45- None => {
46- let mut output = String :: new ( ) ;
47- reader
48- . read_to_string ( & mut output)
49- . await
50- . context ( error:: StdinReadSnafu ) ?;
51- return Ok ( output) ;
52- }
53- } ;
44+ let mut output = String :: new ( ) ;
45+ reader
46+ . read_to_string ( & mut output)
47+ . await
48+ . context ( error:: StdinReadSnafu ) ?;
49+ Ok ( output)
50+ }
5451
52+ /// Retrieves network configuration content from a source URI.
53+ ///
54+ /// Supports file:// and base64: URI schemes.
55+ async fn get_content_from_source ( input_source : String ) -> Result < String > {
5556 if let Some ( base64_data) = input_source. strip_prefix ( "base64:" ) {
56- let decoded_bytes = engine:: general_purpose:: STANDARD
57- . decode ( base64_data. as_bytes ( ) )
58- . context ( error:: Base64DecodeSnafu {
59- input_source : & input_source,
60- } ) ?;
61-
62- let decoded_string = String :: from_utf8 ( decoded_bytes) . context ( error:: Base64Utf8Snafu {
63- input_source : & input_source,
64- } ) ?;
65-
66- return Ok ( decoded_string) ;
57+ return get_content_from_base64 ( base64_data, & input_source) ;
6758 }
6859
6960 let uri = Url :: parse ( & input_source) . context ( error:: UriSnafu {
7061 input_source : & input_source,
7162 } ) ?;
7263
73- if uri. scheme ( ) == "file" {
74- let path = uri. to_file_path ( ) . ok ( ) . context ( error:: FileUriSnafu {
75- input_source : & input_source,
76- } ) ?;
77- tokio:: fs:: read_to_string ( path)
78- . await
79- . context ( error:: FileReadSnafu { input_source } )
80- } else {
81- // Only file:// and base64: schemes are supported.
82- // Expect this case to be updated when we expand the support for more schemes.
83- error:: UnsupportedUriSchemeSnafu {
64+ match uri. scheme ( ) {
65+ "file" => get_content_from_file ( uri, & input_source) . await ,
66+ scheme => error:: UnsupportedUriSchemeSnafu {
8467 input_source : & input_source,
85- scheme : uri . scheme ( ) ,
68+ scheme,
8669 }
87- . fail ( )
70+ . fail ( ) ,
8871 }
8972}
9073
74+ /// Decodes and returns content from a base64-encoded string.
75+ fn get_content_from_base64 ( base64_data : & str , input_source : & str ) -> Result < String > {
76+ let decoded_bytes = engine:: general_purpose:: STANDARD
77+ . decode ( base64_data. as_bytes ( ) )
78+ . context ( error:: Base64DecodeSnafu { input_source } ) ?;
79+
80+ String :: from_utf8 ( decoded_bytes) . context ( error:: Base64Utf8Snafu { input_source } )
81+ }
82+
83+ /// Reads content from a file URI.
84+ async fn get_content_from_file ( uri : Url , input_source : & str ) -> Result < String > {
85+ let path = uri
86+ . to_file_path ( )
87+ . ok ( )
88+ . context ( error:: FileUriSnafu { input_source } ) ?;
89+ tokio:: fs:: read_to_string ( path)
90+ . await
91+ . context ( error:: FileReadSnafu { input_source } )
92+ }
93+
9194mod error {
9295 use snafu:: Snafu ;
9396
@@ -162,11 +165,16 @@ mod tests {
162165 use std:: io:: Cursor ;
163166
164167 // Given network config content to simulate stdin input
165- let test_content = "version = 2\n \n [eth0]\n dhcp4 = true\n primary = true\n " ;
168+ let test_content = r"version = 2
169+
170+ [eth0]
171+ dhcp4 = true
172+ primary = true
173+ " ;
166174 let mock_stdin = tokio:: io:: BufReader :: new ( Cursor :: new ( test_content. as_bytes ( ) ) ) ;
167175
168- // When reading from mock stdin (None input source)
169- let result = get_content_with_reader :: < String , _ > ( None , mock_stdin) . await ;
176+ // When reading from mock stdin
177+ let result = get_content_with_stdin ( mock_stdin) . await ;
170178
171179 // Then content should be read successfully
172180 assert ! ( result. is_ok( ) ) ;
@@ -181,7 +189,7 @@ mod tests {
181189 let mock_stdin = tokio:: io:: BufReader :: new ( Cursor :: new ( b"" ) ) ;
182190
183191 // When reading from empty mock stdin
184- let result = get_content_with_reader :: < String , _ > ( None , mock_stdin) . await ;
192+ let result = get_content_with_stdin ( mock_stdin) . await ;
185193
186194 // Then should return empty string successfully
187195 assert ! ( result. is_ok( ) ) ;
@@ -192,13 +200,16 @@ mod tests {
192200 async fn test_stdin_vs_uri_behavior ( ) {
193201 use std:: io:: Cursor ;
194202
195- let content = "version = 2\n \n [eth0]\n dhcp4 = true" ;
203+ let content = r"version = 2
204+
205+ [eth0]
206+ dhcp4 = true" ;
196207 let mock_stdin = tokio:: io:: BufReader :: new ( Cursor :: new ( content. as_bytes ( ) ) ) ;
197208
198- // Test that None input reads from stdin
199- let stdin_result = get_content_with_reader :: < String , _ > ( None , mock_stdin) . await ;
209+ // Test that stdin reader works
210+ let stdin_result = get_content_with_stdin ( mock_stdin) . await ;
200211
201- // Test that Some input ignores stdin and uses URI
212+ // Test that Some input uses URI processing
202213 let uri_result =
203214 get_content ( Some ( "base64:dmVyc2lvbiA9IDIKCltldGgwXQpkaGNwNCA9IHRydWU=" ) ) . await ;
204215
0 commit comments