Implemented server check #13

Merged
Jeremy Kescher merged 1 commit from jeremy/0128/server-check-works-now into master 2020-01-28 14:05:26 +00:00
2 changed files with 131 additions and 39 deletions

View file

@ -1,9 +1,10 @@
enum ServerStatus { unknown, timeout, responding, dnserror }
enum ServerStatus { unknown, ok, notok, timeout, dnserror, toomanyredirects }
class Server {
String uri;
String displayName;
String uri;
ServerStatus status = ServerStatus.unknown;
double ping;
Server(
this.displayName,

View file

@ -5,6 +5,7 @@ import 'dart:io';
import 'package:basic_utils/basic_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:http/src/response.dart';
import 'package:server_pinger/server.dart';
import 'server.dart';
@ -40,7 +41,7 @@ class _ServerListState extends State<ServerList> {
),
new Server(
"My VPS",
"https://vps1.kescher.at",
"http://kescher.at",
),
new Server(
"Raspberry Pi",
@ -66,18 +67,13 @@ class _ServerListState extends State<ServerList> {
}
void _updateServerStatus(Server s) {
checkStatus(s.uri).then((value) {
if (value != s.status)
setState(() {
s.status = value;
});
_checkStatus(s.uri).then((value) {
setState(() {
s.status = value;
});
});
}
void _updateUI() {
setState(() {});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
@ -180,7 +176,8 @@ class _ServerListState extends State<ServerList> {
children: [
info,
Container(
decoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.grey))),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey))),
),
Text('Ping: 1111'),
],
@ -233,41 +230,135 @@ class _ServerListState extends State<ServerList> {
return list;
}
static Future<ServerStatus> checkStatus(String uri) async {
static Future<ServerStatus> _checkStatus(String uri,
{int iterations = 0}) async {
Uri parsedUri;
try {
parsedUri = Uri.parse(uri);
} catch (FormatException) {
print("The URI was invalid, returning DNS_ERROR");
return ServerStatus.dnserror;
}
if (parsedUri.isScheme("http") || parsedUri.isScheme("http")) {}
try {
InternetAddress ia = InternetAddress(parsedUri.host);
//parsedUri.scheme
} catch (ArgumentError) {
List<RRecord> record =
await DnsUtils.lookupRecord(parsedUri.host, RRecordType.ANY);
}
return ServerStatus.responding;
if (parsedUri.isScheme("http") || parsedUri.isScheme("https")) {
InternetAddress ia;
try {
ia = InternetAddress(parsedUri.host);
return await _checkResponse(parsedUri, iterations);
} catch (ArgumentError) /* Host is a DNS name */ {
try {
var v4recs = await DnsUtils.lookupRecord(parsedUri.host, RRecordType.A);
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 await _checkResponse(parsedUri, iterations);
}
} else // non-HTTP scheme
return ServerStatus.unknown;
}
Icon _generateIcon(Server server) {
if (server.status == ServerStatus.unknown)
return new Icon(
Icons.check_box_outline_blank,
color: Colors.yellow,
);
else if (server.status == ServerStatus.responding)
return new Icon(
Icons.check_box,
color: Colors.green,
);
else
return new Icon(
Icons.indeterminate_check_box,
color: Colors.red,
);
switch (server.status) {
case ServerStatus.unknown:
return new Icon(
Icons.sync,
color: Colors.blueGrey.shade400,
);
break;
case ServerStatus.ok:
return new Icon(
Icons.check_box,
color: Colors.green.shade400,
);
break;
case ServerStatus.notok:
return new Icon(
Icons.indeterminate_check_box,
color: Colors.red,
);
break;
case ServerStatus.timeout:
return new Icon(
Icons.timer_off,
color: Colors.yellowAccent.shade700,
);
break;
case ServerStatus.dnserror:
return new Icon(
Icons.dns,
color: Colors.red.shade400,
);
break;
case ServerStatus.toomanyredirects:
return new Icon(
Icons.subdirectory_arrow_right,
color: Colors.red.shade400,
);
break;
}
}
static _getDNS(List<RRecord> records, RRecordType type) {
String _return;
if (records == null) return ServerStatus.dnserror;
records.forEach((record) {
if (record != null) {
return;
}
if (record == null) {
// ignore: unrelated_type_equality_checks
if (record.rType == type) {
_return = record.data;
}
}
});
if (_return == null) _return = "";
return _return;
}
static Future<ServerStatus> _checkResponse(Uri uri, int iterations) async {
var scheme = uri.scheme;
var port = uri.port;
var host = uri.host;
var location = uri.path;
for (int i = 0; i < 5; i++) {
Response response = await HttpUtils.getForFullResponse(
scheme + "://" + host,
headers: <String, String>{"Location": location})
.timeout(new Duration(seconds: 3));
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;
}
}