mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
New Ping, use servers to ping
This commit is contained in:
79
lib/data/model/server/ping_result.dart
Normal file
79
lib/data/model/server/ping_result.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
final parseFailed = Exception('Parse failed');
|
||||
final seqReg = RegExp(r'icmp_seq=(.+) ttl=(.+) time=(.+) ms');
|
||||
final packetReg =
|
||||
RegExp(r'(.+) packets transmitted, (.+) received, (.+)% packet loss');
|
||||
final timeReg = RegExp(r'min/avg/max/mdev = (.+)/(.+)/(.+)/(.+) ms');
|
||||
final ipReg = RegExp(r' \((\S+)\) ');
|
||||
|
||||
class PingResult {
|
||||
String serverName;
|
||||
String? ip;
|
||||
List<PingSeqResult>? results;
|
||||
PingStatistics? statistic;
|
||||
|
||||
PingResult.parse(this.serverName, String raw) {
|
||||
final lines = raw.split('\n');
|
||||
lines.removeWhere((element) => element.isEmpty);
|
||||
final statisticIndex =
|
||||
lines.indexWhere((element) => element.startsWith('---'));
|
||||
if (statisticIndex == -1) {
|
||||
throw parseFailed;
|
||||
}
|
||||
final statisticRaw = lines.sublist(statisticIndex + 1);
|
||||
statistic = PingStatistics.parse(statisticRaw);
|
||||
results = lines
|
||||
.sublist(1, statisticIndex)
|
||||
.map((e) => PingSeqResult.parse(e))
|
||||
.toList();
|
||||
ip = ipReg.firstMatch(lines[0])?.group(1);
|
||||
}
|
||||
}
|
||||
|
||||
class PingSeqResult {
|
||||
int? seq;
|
||||
int? ttl;
|
||||
double? time;
|
||||
|
||||
PingSeqResult.parse(String raw) {
|
||||
final seqMatched = seqReg.firstMatch(raw);
|
||||
if (seqMatched == null) {
|
||||
throw parseFailed;
|
||||
}
|
||||
seq = int.tryParse(seqMatched.group(1)!);
|
||||
ttl = int.tryParse(seqMatched.group(2)!);
|
||||
time = double.tryParse(seqMatched.group(3)!);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'seq: $seq, ttl: $ttl, time: $time';
|
||||
}
|
||||
}
|
||||
|
||||
class PingStatistics {
|
||||
int? total;
|
||||
int? received;
|
||||
double? loss;
|
||||
double? min;
|
||||
double? max;
|
||||
double? avg;
|
||||
double? stddev;
|
||||
|
||||
PingStatistics.parse(List<String> lines) {
|
||||
if (lines.isEmpty || lines.length != 2) {
|
||||
return;
|
||||
}
|
||||
final packetMatched = packetReg.firstMatch(lines[0]);
|
||||
final timeMatched = timeReg.firstMatch(lines[1]);
|
||||
if (packetMatched == null || timeMatched == null) {
|
||||
return;
|
||||
}
|
||||
total = int.tryParse(packetMatched.group(1)!);
|
||||
received = int.tryParse(packetMatched.group(2)!);
|
||||
loss = double.tryParse(packetMatched.group(3)!);
|
||||
min = double.tryParse(timeMatched.group(1)!);
|
||||
avg = double.tryParse(timeMatched.group(2)!);
|
||||
max = double.tryParse(timeMatched.group(3)!);
|
||||
stddev = double.tryParse(timeMatched.group(4)!);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
class BuildData {
|
||||
static const String name = "ServerBox";
|
||||
static const int build = 115;
|
||||
static const int build = 117;
|
||||
static const String engine =
|
||||
"Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision c860cba910 (6 weeks ago) • 2022-03-25 00:23:12 -0500\nEngine • revision 57d3bac3dd\nTools • Dart 2.16.2 • DevTools 2.9.2\n";
|
||||
static const String buildAt = "2022-05-03 08:33:56.199910";
|
||||
static const int modifications = 3;
|
||||
static const String buildAt = "2022-05-03 11:39:22.853075";
|
||||
static const int modifications = 6;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,11 @@ class _AptManagePageState extends State<AptManagePage>
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
locator<AptProvider>().init(si.client!, si.status.sysVer.dist, () => scrollController.jumpTo(scrollController.position.maxScrollExtent));
|
||||
locator<AptProvider>().init(
|
||||
si.client!,
|
||||
si.status.sysVer.dist,
|
||||
() =>
|
||||
scrollController.jumpTo(scrollController.position.maxScrollExtent));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dart_ping/dart_ping.dart';
|
||||
import 'package:dart_ping_ios/dart_ping_ios.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:toolbox/core/extension/uint8list.dart';
|
||||
import 'package:toolbox/core/utils.dart';
|
||||
import 'package:toolbox/data/model/server/ping_result.dart';
|
||||
import 'package:toolbox/data/provider/server.dart';
|
||||
import 'package:toolbox/data/res/color.dart';
|
||||
import 'package:toolbox/locator.dart';
|
||||
import 'package:toolbox/view/widget/input_field.dart';
|
||||
import 'package:toolbox/view/widget/round_rect_card.dart';
|
||||
|
||||
@@ -18,16 +18,13 @@ class PingPage extends StatefulWidget {
|
||||
class _PingPageState extends State<PingPage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
late TextEditingController _textEditingController;
|
||||
Ping? _ping;
|
||||
late MediaQueryData _media;
|
||||
final List<PingResult> _results = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_textEditingController = TextEditingController(text: '');
|
||||
if (Platform.isIOS) {
|
||||
DartPingIOS.register();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -47,25 +44,61 @@ class _PingPageState extends State<PingPage>
|
||||
const SizedBox(height: 13),
|
||||
buildInput(context, _textEditingController, maxLines: 1),
|
||||
_buildControl(),
|
||||
RoundRectCard(ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: double.infinity,
|
||||
minHeight: _media.size.height * 0.6,
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: _media.size.height * 0.6,
|
||||
child: ListView.builder(
|
||||
itemCount: _results.length,
|
||||
itemBuilder: (context, index) {
|
||||
final result = _results[index];
|
||||
return _buildResultItem(result);
|
||||
}),
|
||||
),
|
||||
)),
|
||||
])),
|
||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void doPing() {
|
||||
_ping = Ping(_textEditingController.text.trim());
|
||||
_ping!.stream.listen((event) {
|
||||
final resp = event.response.toString();
|
||||
if (resp == 'null') return;
|
||||
Widget _buildResultItem(PingResult result) {
|
||||
return RoundRectCard(ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
||||
title: Text(result.serverName,
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold, color: primaryColor)),
|
||||
subtitle: Text(_buildPingSummary(result)),
|
||||
trailing: Text(
|
||||
'Avg: ' +
|
||||
(result.statistic?.avg?.toStringAsFixed(2) ?? 'unkown') +
|
||||
' ms',
|
||||
style: TextStyle(fontSize: 14, color: primaryColor)),
|
||||
));
|
||||
}
|
||||
|
||||
String _buildPingSummary(PingResult result) {
|
||||
final ip = result.ip ?? 'unkown';
|
||||
final ttl = result.results?.first.ttl ?? 'unkown';
|
||||
final loss = result.statistic?.loss ?? 'unkown';
|
||||
final min = result.statistic?.min ?? 'unkown';
|
||||
final max = result.statistic?.max ?? 'unkown';
|
||||
return '$ip\nttl: $ttl, loss: $loss%\nmin: $min ms, max: $max ms';
|
||||
}
|
||||
|
||||
Future<void> doPing() async {
|
||||
_results.clear();
|
||||
final target = _textEditingController.text.trim();
|
||||
if (target.isEmpty) {
|
||||
showSnackBar(context, const Text('Please input a target'));
|
||||
return;
|
||||
}
|
||||
for (var si in locator<ServerProvider>().servers) {
|
||||
if (si.client == null) {
|
||||
continue;
|
||||
}
|
||||
final result = await si.client!.run('ping -c 3 $target').string;
|
||||
_results.add(PingResult.parse(si.info.name, result));
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildControl() {
|
||||
@@ -86,11 +119,11 @@ class _PingPageState extends State<PingPage>
|
||||
SizedBox(
|
||||
width: 7,
|
||||
),
|
||||
Text('Stop')
|
||||
Text('Clear')
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
if (_ping != null) _ping!.stop();
|
||||
_results.clear();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
|
||||
30
pubspec.lock
30
pubspec.lock
@@ -117,20 +117,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
dart_ping:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dart_ping
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
dart_ping_ios:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dart_ping_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
dartssh2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -206,13 +192,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
flutter_icmp_ping:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_icmp_ping
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -356,13 +335,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
open_file:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: open_file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -371,7 +343,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
|
||||
@@ -54,12 +54,8 @@ dependencies:
|
||||
r_upgrade: ^0.3.6
|
||||
pull_to_refresh: ^2.0.0
|
||||
marquee: ^2.2.0
|
||||
dart_ping: ^6.1.1
|
||||
dart_ping_ios: ^1.0.0
|
||||
dropdown_button2: ^1.1.1
|
||||
flutter_advanced_drawer: ^1.3.0
|
||||
open_file: ^3.2.1
|
||||
path_provider: ^2.0.9
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
Reference in New Issue
Block a user