new & opt.

- new: ssh discontinuity test
- opt.: server cmds
- opt.: check ssh client status before exec cmds
- new: #124 notify on discontinuity
This commit is contained in:
lollipopkit
2023-08-17 21:36:00 +08:00
parent b78949cf0c
commit 46cffb836c
13 changed files with 141 additions and 98 deletions

View File

@@ -83,6 +83,7 @@ extension EnumX on Enum {
}
enum StatusCmdType {
time,
net,
sys,
cpu,

View File

@@ -88,7 +88,9 @@ List<OneTimeCpuStatus> parseCPU(String raw) {
int.parse(matches[3]),
int.parse(matches[4]),
int.parse(matches[5]),
int.parse(matches[6])));
int.parse(matches[6]),
),
);
}
return cpus;
}

View File

@@ -3,10 +3,11 @@ import 'package:toolbox/core/extension/numx.dart';
import 'time_seq.dart';
class NetSpeedPart extends TimeSeqIface<NetSpeedPart> {
String device;
BigInt bytesIn;
BigInt bytesOut;
BigInt time;
final String device;
final BigInt bytesIn;
final BigInt bytesOut;
final int time;
NetSpeedPart(this.device, this.bytesIn, this.bytesOut, this.time);
@override
@@ -18,7 +19,7 @@ class NetSpeed extends TimeSeq<NetSpeedPart> {
List<String> get devices => now.map((e) => e.device).toList();
BigInt get _timeDiff => now[0].time - pre[0].time;
BigInt get _timeDiff => BigInt.from(now[0].time - pre[0].time);
double _speedIn(int i) => (now[i].bytesIn - pre[i].bytesIn) / _timeDiff;
double _speedOut(int i) => (now[i].bytesOut - pre[i].bytesOut) / _timeDiff;
@@ -96,14 +97,12 @@ class NetSpeed extends TimeSeq<NetSpeedPart> {
/// face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
/// lo: 45929941 269112 0 0 0 0 0 0 45929941 269112 0 0 0 0 0 0
/// eth0: 48481023 505772 0 0 0 0 0 0 36002262 202307 0 0 0 0 0 0
/// 1635752901
List<NetSpeedPart> parseNetSpeed(String raw) {
List<NetSpeedPart> parseNetSpeed(String raw, int time) {
final split = raw.split('\n');
if (split.length < 4) {
return [];
}
final time = BigInt.parse(split[split.length - 1]);
final results = <NetSpeedPart>[];
for (final item in split.sublist(2, split.length - 1)) {
final data = item.trim().split(':');

View File

@@ -15,7 +15,10 @@ class ServerStatusUpdateReq {
Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
final segments = req.segments;
final net = parseNetSpeed(StatusCmdType.net.find(segments));
final time = int.parse(StatusCmdType.time.find(segments));
final net = parseNetSpeed(StatusCmdType.net.find(segments), time);
req.ss.netSpeed.update(net);
final sys = _parseSysVer(

View File

@@ -219,7 +219,7 @@ class ServerProvider extends ChangeNotifier {
return;
}
if (s.state.shouldConnect) {
if (s.state.shouldConnect || (s.client?.isClosed ?? true)) {
_setServerState(s, ServerState.connecting);
final time1 = DateTime.now();

View File

@@ -2,8 +2,8 @@
class BuildData {
static const String name = "ServerBox";
static const int build = 474;
static const int build = 476;
static const String engine = "3.10.6";
static const String buildAt = "2023-08-16 15:42:48.857532";
static const int modifications = 24;
static const String buildAt = "2023-08-17 18:45:06.973608";
static const int modifications = 5;
}

View File

@@ -6,7 +6,8 @@ const serverBoxDir = r'$HOME/.config/server_box';
const shellPath = '$serverBoxDir/mobile_app.sh';
const statusCmds = [
'cat /proc/net/dev && date +%s',
'date +%s',
'cat /proc/net/dev',
'cat /etc/os-release | grep PRETTY_NAME',
'cat /proc/stat | grep cpu',
'uptime',

View File

@@ -31,7 +31,7 @@ NetSpeedPart get _initNetSpeedPart => NetSpeedPart(
'',
BigInt.zero,
BigInt.zero,
BigInt.zero,
0,
);
NetSpeed get initNetSpeed => NetSpeed(
[_initNetSpeedPart],

View File

@@ -309,6 +309,7 @@ class _HomePageState extends State<HomePage>
replace: name,
),
),
height13,
const Text('Participants:'),
...participants.map(
(name) => UrlText(

View File

@@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/navigator.dart';
import 'package:toolbox/core/extension/uint8list.dart';
import 'package:xterm/xterm.dart';
import '../../../core/route.dart';
@@ -54,6 +55,7 @@ class _SSHPageState extends State<SSHPage> {
Timer? _virtKeyLongPressTimer;
SSHClient? _client;
SSHSession? _session;
Timer? _discontinuityTimer;
@override
void initState() {
@@ -74,8 +76,12 @@ class _SSHPageState extends State<SSHPage> {
super.dispose();
_virtKeyLongPressTimer?.cancel();
_terminalController.dispose();
_client?.close();
_session?.close();
if (_client?.isClosed == false) {
try {
_client?.close();
} catch (_) {}
}
_discontinuityTimer?.cancel();
}
@override
@@ -85,7 +91,7 @@ class _SSHPageState extends State<SSHPage> {
_media = MediaQuery.of(context);
_s = S.of(context)!;
_terminalTheme = _isDark ? termDarkTheme : termLightTheme;
// Because the virtual keyboard only displayed on mobile devices
if (isMobile) {
_virtKeyWidth = _media.size.width / 7;
@@ -126,6 +132,7 @@ class _SSHPageState extends State<SSHPage> {
deleteDetection: isIOS,
autofocus: true,
keyboardAppearance: _isDark ? Brightness.dark : Brightness.light,
hideScrollBar: isMobile,
),
),
);
@@ -334,6 +341,20 @@ class _SSHPageState extends State<SSHPage> {
),
);
_discontinuityTimer = Timer.periodic(
const Duration(seconds: 5),
(_) async {
var throwTimeout = true;
Future.delayed(const Duration(seconds: 3), () {
if (throwTimeout) {
_catchTimeout();
}
});
await _client?.run('echo 1').string;
throwTimeout = false;
},
);
if (_session == null) {
showSnackBar(context, const Text('Null session'));
return;
@@ -372,4 +393,27 @@ class _SSHPageState extends State<SSHPage> {
.transform(const Utf8Decoder())
.listen(_terminal.write);
}
void _catchTimeout() {
_discontinuityTimer?.cancel();
if (!mounted) return;
_write('\n\nConnection lost\r\n');
showRoundDialog(
context: context,
title: Text(_s.disconnected),
child: Text('Go back?'),
barrierDismiss: false,
actions: [
TextButton(
onPressed: () {
if (mounted) {
context.pop();
context.pop();
}
},
child: Text(_s.ok),
),
],
);
}
}