@@ -4,8 +4,36 @@ mod engine;
44mod utils;
55
66use colored:: Colorize ;
7+
8+ use rustyline:: config:: Configurer ;
79use rustyline:: error:: ReadlineError ;
8- use rustyline:: { Editor , Result } ;
10+ use rustyline:: highlight:: Highlighter ;
11+ use rustyline:: { ColorMode , Editor , Result } ;
12+ use rustyline_derive:: { Completer , Helper , Hinter , Validator } ;
13+
14+ use std:: borrow:: Cow :: { self , Borrowed , Owned } ;
15+
16+ use engine:: { AuthConfig , RustbaseConfig , TlsConfig } ;
17+
18+ #[ derive( Completer , Helper , Hinter , Validator ) ]
19+ struct MaskingHighlighter {
20+ masking : bool ,
21+ }
22+
23+ impl Highlighter for MaskingHighlighter {
24+ fn highlight < ' l > ( & self , line : & ' l str , _pos : usize ) -> Cow < ' l , str > {
25+ use unicode_width:: UnicodeWidthStr ;
26+ if self . masking {
27+ Owned ( "*" . repeat ( line. width ( ) ) )
28+ } else {
29+ Borrowed ( line)
30+ }
31+ }
32+
33+ fn highlight_char ( & self , _line : & str , _pos : usize ) -> bool {
34+ self . masking
35+ }
36+ }
937
1038/// A CLI for Rustbase Database Server
1139#[ derive( clap_derive:: Parser ) ]
@@ -24,14 +52,33 @@ struct Args {
2452 #[ clap( long, default_value = "" ) ]
2553 ca_file : String ,
2654
55+ /// Use authentication for connection
56+ #[ clap( long, short = 'a' ) ]
57+ use_auth : bool ,
58+
2759 #[ clap( subcommand) ]
2860 commands : Option < Commands > ,
2961}
3062
63+ fn prompt < T > ( prompt : & str , editor : & mut Editor < T > ) -> Result < String >
64+ where
65+ T : rustyline:: Helper ,
66+ {
67+ let result = loop {
68+ let prompt_result = editor. readline ( prompt) ?;
69+
70+ if !prompt_result. is_empty ( ) {
71+ break prompt_result;
72+ }
73+ } ;
74+
75+ Ok ( result)
76+ }
77+
3178#[ derive( clap_derive:: Subcommand , PartialEq ) ]
3279enum Commands {
33- #[ clap( about = "Upgrade Rustbase and Rustbase CLI" ) ]
34- Upgrade ,
80+ #[ clap( about = "Update Rustbase CLI" ) ]
81+ Update ,
3582 #[ clap( about = "Clean repl history" ) ]
3683 Clean ,
3784}
@@ -43,7 +90,7 @@ async fn main() -> Result<()> {
4390 let repl_path = utils:: get_current_path ( ) . join ( "repl.history" ) ;
4491
4592 match args. commands {
46- Some ( Commands :: Upgrade ) => {
93+ Some ( Commands :: Update ) => {
4794 println ! ( "Not implemented yet" ) ;
4895 return Ok ( ( ) ) ;
4996 }
@@ -83,28 +130,51 @@ async fn main() -> Result<()> {
83130 ) ;
84131 println ! ( "Press Ctrl+C to exit." ) ;
85132
86- let mut rl = Editor :: < ( ) > :: new ( ) ?;
133+ let h = MaskingHighlighter { masking : false } ;
134+ let mut rl = Editor :: new ( ) ?;
135+ rl. set_helper ( Some ( h) ) ;
87136
88137 rl. load_history ( repl_path. to_str ( ) . unwrap ( ) ) . ok ( ) ;
89138 println ! ( ) ;
90139
91- let mut database = rl . readline ( "Database: " ) ?;
140+ let mut database = prompt ( "Database: " , & mut rl ) ?;
92141
93- loop {
94- if database . is_empty ( ) {
95- database = rl . readline ( "Database: " ) ? ;
96- continue ;
97- } else {
98- break ;
99- }
100- }
142+ let auth_config = if args . use_auth {
143+ let username = prompt ( "Username: " , & mut rl ) ? ;
144+
145+ rl . helper_mut ( ) . expect ( "No helper" ) . masking = true ;
146+ rl . set_color_mode ( ColorMode :: Forced ) ; // force masking
147+ rl . set_auto_add_history ( false ) ; // make sure password is not added to history
148+
149+ let password = prompt ( "Password: " , & mut rl ) ? ;
101150
102- let mut client = if args. tls {
103- engine:: Rustbase :: connect_tls ( args. host , args. port , database. clone ( ) , args. ca_file ) . await
151+ rl. helper_mut ( ) . expect ( "No helper" ) . masking = false ;
152+ rl. set_color_mode ( ColorMode :: Disabled ) ;
153+ rl. set_auto_add_history ( true ) ;
154+
155+ Some ( AuthConfig { username, password } )
156+ } else {
157+ None
158+ } ;
159+
160+ let tls_config = if args. tls {
161+ let ca_file = args. ca_file ;
162+
163+ Some ( TlsConfig { ca_file } )
104164 } else {
105- engine:: Rustbase :: connect ( args. host , args. port , database. clone ( ) ) . await
165+ None
166+ } ;
167+
168+ let config = RustbaseConfig {
169+ database : database. clone ( ) ,
170+ port : args. port ,
171+ host : args. host ,
172+ auth : auth_config,
173+ tls : tls_config,
106174 } ;
107175
176+ let mut client = engine:: Rustbase :: connect ( config) . await ;
177+
108178 loop {
109179 let readline = rl. readline ( format ! ( "{}> " , database) . as_str ( ) ) ;
110180 match readline {
0 commit comments