Add button to launch SSH session
This commit is contained in:
parent
f93ae4bfe3
commit
fcf1ab92f0
|
@ -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);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue