Cleanup code #17
3 changed files with 62 additions and 111 deletions
|
@ -1,4 +1,4 @@
|
||||||
enum ServerStatus { unknown, ok, notok, timeout, dnserror, toomanyredirects }
|
enum ServerStatus { unknown, ok, notok, timeout, dnserror }
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
String displayName;
|
String displayName;
|
||||||
|
|
|
@ -11,15 +11,6 @@ import 'server.dart';
|
||||||
class ServerList extends StatefulWidget {
|
class ServerList extends StatefulWidget {
|
||||||
ServerList({Key key, this.title}) : super(key: key);
|
ServerList({Key key, this.title}) : super(key: key);
|
||||||
|
|
||||||
// This widget is the home page of your application. It is stateful, meaning
|
|
||||||
// that it has a State object (defined below) that contains fields that affect
|
|
||||||
// how it looks.
|
|
||||||
|
|
||||||
// This class is the configuration for the state. It holds the values (in this
|
|
||||||
// case the title) provided by the parent (in this case the App widget) and
|
|
||||||
// used by the build method of the State. Fields in a Widget subclass are
|
|
||||||
// always marked "final".
|
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -27,6 +18,7 @@ class ServerList extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ServerListState extends State<ServerList> {
|
class _ServerListState extends State<ServerList> {
|
||||||
|
// Currently expanded server list entry, -1 = no field is expanded
|
||||||
int selectedServer = -1;
|
int selectedServer = -1;
|
||||||
List<Server> servers = [
|
List<Server> servers = [
|
||||||
new Server(
|
new Server(
|
||||||
|
@ -44,7 +36,7 @@ class _ServerListState extends State<ServerList> {
|
||||||
new Server(
|
new Server(
|
||||||
"Raspberry Pi",
|
"Raspberry Pi",
|
||||||
"https://pi.kescher.at/isup",
|
"https://pi.kescher.at/isup",
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
@ -55,9 +47,8 @@ class _ServerListState extends State<ServerList> {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_updateAllServers();
|
_updateAllServers();
|
||||||
timer = new Timer.periodic(new Duration(seconds: 30), (timer) {
|
timer = new Timer.periodic(
|
||||||
_updateAllServers();
|
new Duration(seconds: 30), (_) => _updateAllServers());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateAllServers() async {
|
void _updateAllServers() async {
|
||||||
|
@ -65,11 +56,7 @@ class _ServerListState extends State<ServerList> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateServerStatus(Server s) {
|
void _updateServerStatus(Server s) {
|
||||||
_checkStatus(s.uri).then((value) {
|
_checkStatus(s.uri).then((value) => setState(() => s.status = value));
|
||||||
setState(() {
|
|
||||||
s.status = value;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -263,7 +250,7 @@ class _ServerListState extends State<ServerList> {
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text('Are you shure you want to delete ' +
|
title: Text('Are you sure you want to delete ' +
|
||||||
servers[index].displayName +
|
servers[index].displayName +
|
||||||
'?'),
|
'?'),
|
||||||
content: Form(
|
content: Form(
|
||||||
|
@ -323,9 +310,7 @@ class _ServerListState extends State<ServerList> {
|
||||||
}
|
}
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() => selectedServer = index);
|
||||||
selectedServer = index;
|
|
||||||
});
|
|
||||||
print(index.toString() + " clicked");
|
print(index.toString() + " clicked");
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -368,8 +353,7 @@ class _ServerListState extends State<ServerList> {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ServerStatus> _checkStatus(String uri,
|
static Future<ServerStatus> _checkStatus(String uri) async {
|
||||||
{int iterations = 0}) async {
|
|
||||||
Uri parsedUri;
|
Uri parsedUri;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -378,126 +362,89 @@ class _ServerListState extends State<ServerList> {
|
||||||
return ServerStatus.dnserror;
|
return ServerStatus.dnserror;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsedUri.isScheme("http") || parsedUri.isScheme("https")) {
|
try {
|
||||||
InternetAddress ia;
|
// Check if host is IP address
|
||||||
|
InternetAddress(parsedUri.host);
|
||||||
|
} catch (ArgumentError) /* Host is a DNS name */ {
|
||||||
try {
|
try {
|
||||||
ia = InternetAddress(parsedUri.host);
|
var v4recs = await DnsUtils.lookupRecord(parsedUri.host, RRecordType.A);
|
||||||
return await _checkResponse(parsedUri, iterations);
|
var v6recs =
|
||||||
} catch (ArgumentError) /* Host is a DNS name */ {
|
await DnsUtils.lookupRecord(parsedUri.host, RRecordType.AAAA);
|
||||||
try {
|
var v4 = await _resolveHostname(v4recs, RRecordType.A);
|
||||||
var v4recs =
|
var v6 = await _resolveHostname(v6recs, RRecordType.AAAA);
|
||||||
await DnsUtils.lookupRecord(parsedUri.host, RRecordType.A);
|
if (v4 != "" && v6 != "") {
|
||||||
var v6recs =
|
|
||||||
await DnsUtils.lookupRecord(parsedUri.host, RRecordType.AAAA);
|
|
||||||
var v4 = await _getDNS(v4recs, RRecordType.A);
|
|
||||||
var v6 = await _getDNS(v6recs, RRecordType.AAAA);
|
|
||||||
if (v4 != "" && v6 != "") {
|
|
||||||
return ServerStatus.dnserror;
|
|
||||||
}
|
|
||||||
} catch (SocketException) {
|
|
||||||
return ServerStatus.dnserror;
|
return ServerStatus.dnserror;
|
||||||
}
|
}
|
||||||
|
} catch (SocketException) {
|
||||||
return await _checkResponse(parsedUri, iterations);
|
return ServerStatus.dnserror;
|
||||||
}
|
}
|
||||||
} else // non-HTTP scheme
|
}
|
||||||
return ServerStatus.unknown;
|
try {
|
||||||
|
return await _checkResponse(parsedUri);
|
||||||
|
} catch (TimeoutException) {
|
||||||
|
return ServerStatus.timeout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Icon _generateIcon(Server server) {
|
Icon _generateIcon(Server server) {
|
||||||
|
var icon, color;
|
||||||
switch (server.status) {
|
switch (server.status) {
|
||||||
case ServerStatus.unknown:
|
case ServerStatus.unknown:
|
||||||
return new Icon(
|
icon = Icons.timer;
|
||||||
Icons.sync,
|
color = Colors.blueGrey.shade400;
|
||||||
color: Colors.blueGrey.shade400,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case ServerStatus.ok:
|
case ServerStatus.ok:
|
||||||
return new Icon(
|
icon = Icons.check_box;
|
||||||
Icons.check_box,
|
color = Colors.green.shade400;
|
||||||
color: Colors.green.shade400,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case ServerStatus.notok:
|
case ServerStatus.notok:
|
||||||
return new Icon(
|
icon = Icons.indeterminate_check_box;
|
||||||
Icons.indeterminate_check_box,
|
color = Colors.red;
|
||||||
color: Colors.red,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case ServerStatus.timeout:
|
case ServerStatus.timeout:
|
||||||
return new Icon(
|
icon = Icons.timer_off;
|
||||||
Icons.timer_off,
|
color = Colors.yellowAccent.shade700;
|
||||||
color: Colors.yellowAccent.shade700,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case ServerStatus.dnserror:
|
case ServerStatus.dnserror:
|
||||||
return new Icon(
|
icon = Icons.dns;
|
||||||
Icons.dns,
|
color = Colors.red.shade400;
|
||||||
color: Colors.red.shade400,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case ServerStatus.toomanyredirects:
|
default:
|
||||||
return new Icon(
|
icon = Icons.indeterminate_check_box;
|
||||||
Icons.subdirectory_arrow_right,
|
color = Colors.red;
|
||||||
color: Colors.red.shade400,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return new Icon(icon, color: color);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _getDNS(List<RRecord> records, RRecordType type) {
|
static _resolveHostname(List<RRecord> records, RRecordType type) {
|
||||||
String _return;
|
String ipAddress;
|
||||||
if (records == null) return ServerStatus.dnserror;
|
if (records == null) return ServerStatus.dnserror;
|
||||||
|
|
||||||
records.forEach((record) {
|
records.forEach((record) {
|
||||||
if (record != null) {
|
if (ipAddress != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record == null) {
|
if (ipAddress == null) {
|
||||||
// ignore: unrelated_type_equality_checks
|
// ignore: unrelated_type_equality_checks
|
||||||
if (record.rType == type) {
|
if (record.rType == type) {
|
||||||
_return = record.data;
|
ipAddress = record.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (_return == null) _return = "";
|
if (ipAddress == null) ipAddress = "";
|
||||||
return _return;
|
return ipAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ServerStatus> _checkResponse(Uri uri, int iterations) async {
|
static Future<ServerStatus> _checkResponse(Uri uri) async {
|
||||||
var scheme = uri.scheme;
|
var response = await HttpUtils.getForFullResponse(uri.toString())
|
||||||
var port = uri.port;
|
.timeout(new Duration(seconds: 3));
|
||||||
var host = uri.host;
|
|
||||||
var location = uri.path;
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
if (response.statusCode > 199 && response.statusCode < 300) {
|
||||||
var response = await HttpUtils.getForFullResponse(scheme + "://" + host,
|
return ServerStatus.ok;
|
||||||
headers: <String, String>{"Location": location})
|
} else {
|
||||||
.timeout(new Duration(seconds: 3));
|
return ServerStatus.notok;
|
||||||
|
|
||||||
if (response.statusCode > 199 && response.statusCode < 300) {
|
|
||||||
return ServerStatus.ok;
|
|
||||||
} else if (response.statusCode == HttpStatus.movedPermanently ||
|
|
||||||
response.statusCode == HttpStatus.found ||
|
|
||||||
response.statusCode == HttpStatus.temporaryRedirect ||
|
|
||||||
response.statusCode == HttpStatus.permanentRedirect) {
|
|
||||||
if (iterations < 5) return ServerStatus.toomanyredirects;
|
|
||||||
var responseLocation = response.headers["Location"];
|
|
||||||
if (responseLocation.startsWith("http://") ||
|
|
||||||
responseLocation.startsWith("https://")) {
|
|
||||||
return await _checkStatus(responseLocation,
|
|
||||||
iterations: iterations + 1);
|
|
||||||
}
|
|
||||||
location = responseLocation;
|
|
||||||
return await _checkStatus(
|
|
||||||
scheme + "://" + host + ":" + port.toString() + location,
|
|
||||||
iterations: iterations + 1);
|
|
||||||
} else {
|
|
||||||
return ServerStatus.notok;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Too many redirects
|
|
||||||
return ServerStatus.unknown;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,12 @@ dependencies:
|
||||||
|
|
||||||
# Needed for DNS lookup
|
# Needed for DNS lookup
|
||||||
basic_utils: ^2.4.8
|
basic_utils: ^2.4.8
|
||||||
# Needed for FAB menu
|
|
||||||
flutter_speed_dial: ^1.2.5
|
# Might be needed for FAB menu
|
||||||
|
# flutter_speed_dial: ^1.2.5
|
||||||
|
|
||||||
|
# Server list persistence
|
||||||
|
shared_preferences: ^0.5.6+1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue