From edaffb736c8acbd4c5a64caf335bf5e6e55492c4 Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Sun, 28 May 2023 18:58:38 +0800 Subject: [PATCH] new: open `sftp` in `ssh` --- lib/data/res/server_cmd.dart | 2 ++ lib/view/page/sftp/view.dart | 8 ++++--- lib/view/page/ssh.dart | 41 +++++++++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/lib/data/res/server_cmd.dart b/lib/data/res/server_cmd.dart index 0ca92c17..7ad6d0f8 100644 --- a/lib/data/res/server_cmd.dart +++ b/lib/data/res/server_cmd.dart @@ -4,6 +4,8 @@ const seperator = 'SrvBox'; const serverBoxDir = r'$HOME/.config/server_box'; const shellPath = '$serverBoxDir/mobile_app.sh'; +const echoPWD = 'echo \$PWD'; + enum CmdType { export, net, diff --git a/lib/view/page/sftp/view.dart b/lib/view/page/sftp/view.dart index 370acd19..feebdc57 100644 --- a/lib/view/page/sftp/view.dart +++ b/lib/view/page/sftp/view.dart @@ -32,7 +32,8 @@ import 'downloading.dart'; class SFTPPage extends StatefulWidget { final ServerPrivateInfo spi; - const SFTPPage(this.spi, {Key? key}) : super(key: key); + final String? initPath; + const SFTPPage(this.spi, {Key? key, this.initPath}) : super(key: key); @override _SFTPPageState createState() => _SFTPPageState(); @@ -184,8 +185,9 @@ class _SFTPPageState extends State { } if (_status.files == null) { - _status.path = AbsolutePath('/'); - _listDir(path: '/', client: _client); + final p_ = widget.initPath ?? '/'; + _status.path = AbsolutePath(p_); + _listDir(path: p_, client: _client); return centerLoading; } else { return RefreshIndicator( diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index 45f17be2..842d54f4 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -7,8 +7,10 @@ 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/data/res/server_cmd.dart'; import 'package:xterm/xterm.dart'; +import '../../core/route.dart'; import '../../core/utils/platform.dart'; import '../../core/utils/misc.dart'; import '../../core/utils/ui.dart'; @@ -21,6 +23,7 @@ import '../../data/res/terminal.dart'; import '../../data/res/virtual_key.dart'; import '../../data/store/setting.dart'; import '../../locator.dart'; +import 'sftp/view.dart'; class SSHPage extends StatefulWidget { final ServerPrivateInfo spi; @@ -34,6 +37,7 @@ class SSHPage extends StatefulWidget { class _SSHPageState extends State { late final _terminal = Terminal(inputHandler: _keyboard); SSHClient? _client; + late SSHSession _session; final _keyboard = locator(); final _setting = locator(); late MediaQueryData _media; @@ -205,7 +209,7 @@ class _SSHPageState extends State { } } - void _doVirtualKeyFunc(VirtualKeyFunc type) { + Future _doVirtualKeyFunc(VirtualKeyFunc type) async { switch (type) { case VirtualKeyFunc.toggleIME: FocusScope.of(context).requestFocus(FocusNode()); @@ -229,8 +233,29 @@ class _SSHPageState extends State { }); break; case VirtualKeyFunc.file: - // TODO - showRoundDialog(context: context, child: const Text('TODO')); + // get $PWD from SSH session + _terminal.textInput(echoPWD); + _terminal.keyInput(TerminalKey.enter); + final cmds = _terminal.buffer.lines.toList(); + // wait for the command to finish + await Future.delayed(const Duration(milliseconds: 777)); + // the line below `echo $PWD` is the current path + final idx = cmds.lastIndexWhere((e) => e.toString().contains(echoPWD)); + final initPath = cmds[idx + 1].toString(); + if (initPath.isEmpty || !initPath.startsWith('/')) { + showRoundDialog( + context: context, + child: const Text('Failed to get current path'), + ); + return; + } + AppRoute( + SFTPPage( + widget.spi, + initPath: initPath, + ), + 'SSH SFTP') + .go(context); } } @@ -321,7 +346,7 @@ class _SSHPageState extends State { _write('Terminal size: ${_terminal.viewWidth}x${_terminal.viewHeight}\r\n'); _write('Starting shell...\r\n'); - final session = await _client!.shell( + _session = await _client!.shell( pty: SSHPtyConfig( width: _terminal.viewWidth, height: _terminal.viewHeight, @@ -332,18 +357,18 @@ class _SSHPageState extends State { _terminal.buffer.setCursor(0, 0); _terminal.onOutput = (data) { - session.write(utf8.encode(data) as Uint8List); + _session.write(utf8.encode(data) as Uint8List); }; - _listen(session.stdout); - _listen(session.stderr); + _listen(_session.stdout); + _listen(_session.stderr); if (widget.initCmd != null) { _terminal.textInput(widget.initCmd!); _terminal.keyInput(TerminalKey.enter); } - await session.done; + await _session.done; if (mounted) { context.pop(); }