Add button to launch SSH session

This commit is contained in:
Mark Johnson 2021-11-12 22:33:55 +00:00
parent f93ae4bfe3
commit fcf1ab92f0
1 changed files with 91 additions and 2 deletions

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:path/path.dart' as path;
@ -24,11 +25,14 @@ class _ManagerState extends State<Manager> with PreferencesMixin {
List<String> _currentVms = [];
Map<String, VmInfo> _activeVms = {};
final List<String> _spicyVms = [];
final List<String> _sshVms = [];
String? _terminalEmulator;
Timer? refreshTimer;
@override
void initState() {
super.initState();
_getTerminalEmulator();
getPreference<String>(prefWorkingDirectory).then((pref) {
setState(() {
if (pref == null) {
@ -38,7 +42,6 @@ class _ManagerState extends State<Manager> with PreferencesMixin {
});
Future.delayed(Duration.zero, () => _getVms(context)); // Reload VM list when we enter the page.
});
refreshTimer = Timer.periodic(const Duration(seconds: 5), (Timer t) {
_getVms(context);
}); // Reload VM list every 5 seconds.
@ -50,6 +53,18 @@ class _ManagerState extends State<Manager> with PreferencesMixin {
super.dispose();
}
void _getTerminalEmulator() async {
ProcessResult result = Process.runSync('x-terminal-emulator', ['-h']);
RegExp pattern = RegExp(r"usage:\s+([^\s]+)", multiLine: true, caseSensitive: false);
RegExpMatch? match = pattern.firstMatch(result.stdout);
if (match != null) {
setState(() {
_terminalEmulator = match.group(1);
});
}
}
VmInfo _parseVmInfo(name) {
VmInfo info = VmInfo();
List<String> lines = File(name + '/' + name + '.ports').readAsLinesSync();
@ -107,6 +122,18 @@ class _ManagerState extends State<Manager> with PreferencesMixin {
});
}
Future<bool> _detectSsh(int port) async {
bool isSSH = false;
try {
Socket socket = await Socket.connect('localhost', port);
isSSH = await socket.any((event) => utf8.decode(event).contains('SSH'));
socket.close();
return isSSH;
} catch (exception) {
return false;
}
}
Widget _buildVmList() {
List<Widget> _widgetList = [];
_widgetList.add(
@ -156,12 +183,24 @@ class _ManagerState extends State<Manager> with PreferencesMixin {
List<Widget> _buildRow(String currentVm) {
final bool active = _activeVms.containsKey(currentVm);
final bool spicy = _spicyVms.contains(currentVm);
final bool sshy = _sshVms.contains(currentVm);
VmInfo vmInfo = VmInfo();
String connectInfo = '';
if (active) {
vmInfo = _activeVms[currentVm]!;
if (vmInfo.sshPort != null) {
if (vmInfo.sshPort != null && _terminalEmulator != null) {
connectInfo += context.t('SSH port') + ': ' + vmInfo.sshPort! + ' ';
_detectSsh(int.parse(vmInfo.sshPort!)).then((sshRunning) {
if (sshRunning && !sshy) {
setState(() {
_sshVms.add(currentVm);
});
} else if (!sshRunning && sshy) {
setState(() {
_sshVms.remove(currentVm);
});
}
});
}
if (vmInfo.spicePort != null) {
connectInfo += context.t('SPICE port') + ': ' + vmInfo.spicePort! + ' ';
@ -259,6 +298,56 @@ class _ManagerState extends State<Manager> with PreferencesMixin {
Process.start('spicy', ['-p', vmInfo.spicePort!]);
},
),
TextButton(
child: Text('SSH'),
onPressed: !sshy ? null : () {
TextEditingController _usernameController = TextEditingController();
showDialog<bool>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text('Launch SSH connection to $currentVm'),
content: TextField(
controller: _usernameController,
decoration: const InputDecoration(hintText: "SSH username"),
),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Connect'),
),
],
),
).then((result) {
result = result ?? false;
if (result) {
List<String> sshArgs = ['ssh', '-p', vmInfo.sshPort!, _usernameController.text + '@localhost'];
switch(_terminalEmulator) {
case 'gnome-terminal':
case 'mate-terminal':
sshArgs.insert(0, '--');
break;
case 'xterm':
case 'konsole':
sshArgs.insert(0, '-e');
break;
case 'terminator':
case 'xfce4-terminal':
sshArgs.insert(0, '-x');
break;
case 'guake':
String command = sshArgs.join(' ');
sshArgs = ['-e', command];
break;
}
Process.start(_terminalEmulator!, sshArgs);
}
});
},
),
]
)
),