@@ -6,6 +6,10 @@ use std::{
6
6
use reqwest:: { Client , Error } ;
7
7
use colored:: * ;
8
8
9
+ use serde_json:: Value ;
10
+ use semver:: { Version } ;
11
+
12
+ /// Reusable function that just prints success messages to the console
9
13
fn print_info ( text : & str , is_secondary : bool ) {
10
14
if is_secondary {
11
15
println ! ( "{}" , text. green( ) . italic( ) . dimmed( ) ) ;
@@ -14,7 +18,7 @@ fn print_info(text: &str, is_secondary: bool) {
14
18
} ;
15
19
}
16
20
17
-
21
+ /// Prints the AdGuardian ASCII art to console
18
22
fn print_ascii_art ( ) {
19
23
let art = r"
20
24
█████╗ ██████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗ ██╗ █████╗ ███╗ ██╗
@@ -30,19 +34,22 @@ fn print_ascii_art() {
30
34
print_info ( "For documentation and support, please visit: https://github.com/lissy93/adguardian-term\n " , true ) ;
31
35
}
32
36
33
- fn print_error ( address : & str , error : Option < & Error > ) {
37
+ /// Print error message, along with (optional) stack trace, then exit
38
+ fn print_error ( message : & str , sub_message : & str , error : Option < & Error > ) {
34
39
eprintln ! (
35
- "{}{}" ,
36
- format!( "Failed to connect to AdGuard at {}" , address ) . red( ) ,
40
+ "{}{}{} " ,
41
+ format!( "{}" , message ) . red( ) ,
37
42
match error {
38
43
Some ( err) => format!( "\n {}" , err) . red( ) . dimmed( ) ,
39
44
None => "" . red( ) . dimmed( ) ,
40
45
} ,
46
+ format!( "\n {}" , sub_message) . yellow( ) ,
41
47
) ;
42
- eprintln ! ( "{}\n {}" , "\n Please check your environmental variables and try again." . yellow( ) , "Exiting..." . blue( ) ) ;
43
- }
44
48
49
+ std:: process:: exit ( 1 ) ;
50
+ }
45
51
52
+ /// Given a key, get the value from the environmental variables, and print it to the console
46
53
fn get_env ( key : & str ) -> Result < String , env:: VarError > {
47
54
env:: var ( key) . map ( |v| {
48
55
println ! (
@@ -58,6 +65,39 @@ fn get_env(key: &str) -> Result<String, env::VarError> {
58
65
} )
59
66
}
60
67
68
+ /// Given a possibly undefined version number, check if it's present and supported
69
+ fn check_version ( version : Option < & str > ) {
70
+ let min_version = Version :: parse ( "0.107.29" ) . unwrap ( ) ;
71
+
72
+ match version {
73
+ Some ( version_str) => {
74
+ let adguard_version = Version :: parse ( & version_str[ 1 ..] ) . unwrap ( ) ;
75
+
76
+ if adguard_version < min_version {
77
+ print_error (
78
+ "AdGuard Home version is too old, and is now unsupported" ,
79
+ format ! ( "You're running AdGuard {}. Please upgrade to v{} or later." , version_str, min_version. to_string( ) ) . as_str ( ) ,
80
+ None ,
81
+ ) ;
82
+ }
83
+ } ,
84
+ None => {
85
+ print_error (
86
+ "Unsupported AdGuard Home version" ,
87
+ format ! (
88
+ concat!(
89
+ "Failed to get the version number of your AdGuard Home instance.\n " ,
90
+ "This usually means you're running an old, and unsupported version.\n " ,
91
+ "Please upgrade to v{} or later."
92
+ ) , min_version. to_string( )
93
+ ) . as_str ( ) ,
94
+ None ,
95
+ ) ;
96
+ }
97
+ }
98
+ }
99
+
100
+ /// With the users specified AdGuard details, verify the connection (exit on fail)
61
101
async fn verify_connection (
62
102
client : & Client ,
63
103
ip : String ,
@@ -82,16 +122,44 @@ async fn verify_connection(
82
122
. send ( )
83
123
. await {
84
124
Ok ( res) if res. status ( ) . is_success ( ) => {
85
- println ! ( "{}" , "AdGuard connection successful!\n " . green( ) ) ;
125
+ // Get version string (if present), and check if valid - exit if not
126
+ let body: Value = res. json ( ) . await ?;
127
+ check_version ( body[ "version" ] . as_str ( ) ) ;
128
+ // All good! Print success message :)
129
+ let safe_version = body[ "version" ] . as_str ( ) . unwrap_or ( "mystery version" ) ;
130
+ println ! ( "{}" , format!( "AdGuard ({}) connection successful!\n " , safe_version) . green( ) ) ;
86
131
Ok ( ( ) )
87
132
}
88
- Ok ( _) | Err ( _) => {
89
- print_error ( & format ! ( "{}:{}" , ip, port) , None ) ;
90
- std:: process:: exit ( 1 ) ;
133
+ // Connection failed to authenticate. Print error and exit
134
+ Ok ( _) => {
135
+ print_error (
136
+ & format ! ( "Authentication with AdGuard at {}:{} failed" , ip, port) ,
137
+ "Please check your environmental variables and try again." ,
138
+ None ,
139
+ ) ;
140
+ Ok ( ( ) )
141
+ } ,
142
+ // Connection failed to establish. Print error and exit
143
+ Err ( e) => {
144
+ print_error (
145
+ & format ! ( "Failed to connect to AdGuard at: {}:{}" , ip, port) ,
146
+ "Please check your environmental variables and try again." ,
147
+ Some ( & e) ,
148
+ ) ;
149
+ Ok ( ( ) )
91
150
}
92
151
}
93
152
}
94
153
154
+ /// Initiate the welcome script
155
+ /// This function will:
156
+ /// - Print the AdGuardian ASCII art
157
+ /// - Check for the required environmental variables
158
+ /// - Prompt the user to enter any missing variables
159
+ /// - Verify the connection to the AdGuard instance
160
+ /// - Verify authentication is successful
161
+ /// - Verify the AdGuard Home version is supported
162
+ /// - Then either print a success message, or show instructions to fix and exit
95
163
pub async fn welcome ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
96
164
print_ascii_art ( ) ;
97
165
println ! ( "{}" , "Starting initialization checks..." . blue( ) ) ;
@@ -138,11 +206,13 @@ pub async fn welcome() -> Result<(), Box<dyn std::error::Error>> {
138
206
}
139
207
}
140
208
209
+ // Grab the values of the (now set) environmental variables
141
210
let ip = get_env ( "ADGUARD_IP" ) ?;
142
211
let port = get_env ( "ADGUARD_PORT" ) ?;
143
212
let protocol = get_env ( "ADGUARD_PROTOCOL" ) ?;
144
213
let username = get_env ( "ADGUARD_USERNAME" ) ?;
145
214
let password = get_env ( "ADGUARD_PASSWORD" ) ?;
146
215
216
+ // Verify that we can connect, authenticate, and that version is supported (exit on failure)
147
217
verify_connection ( & client, ip, port, protocol, username, password) . await
148
218
}
0 commit comments