Right-Click File Download in WebShell

· 2 min read · 343 Words · -Views -Comments

WebShell recently added right-click download support. Here’s a summary of the implementation.

Notes

  1. Tech stack

Implementation

  1. Text selection

    • xterm.js supports double-click word selection. If a folder name contains a space like hello world, you’ll need to drag to select the full name.
    • The shell output doesn’t directly indicate whether text is a file, directory, or the PS1 prompt. Themes can style colors, but you can’t reliably infer types from colors since themes vary.
  2. Current Working Directory (CWD)

    • Use shell integration via function hooks. After each command finishes, capture the current directory and send it to the client, storing it in hidden escape sequences so it doesn’t render in the terminal. The app can continuously extract and cache the current directory.

      source /usr/local/bash-precmd/bash-preexec.sh
      preexec() { printf "\x1B]1337;PreExec;Timestamp=$(date +%s);\x7"; }
      
      precmd() { printf "\x1B]1337;PostExec;Exit=$?;CurrentDir=$(pwd);Timestamp=$(date +%s);\x7"; }
      
    • With CWD known and text selected, basic download is straightforward.

  3. Directory history

    • If the user selects a file on the latest line, no problem. But each line can come from a different working directory, so you need to track CWD over time.
    • Don’t map CWD one-to-one by xterm’s visual line numbers. For example, ls may span multiple terminal rows. A better approach is to associate the CWD with the N rows written by a single output operation.
  4. File metadata

    • Selected text isn’t guaranteed to be a file. You need to detect type/size/permissions, etc. ssh2-sftp-client exposes stat for this.

    • stat.mode is a number like 33279. Convert it to octal to get rwx bits:

      (rslt.mode & parseInt('777', 8)).toString(8)
      
    • For symlinks, list returns type = 'l', but stat.isSymbolicLink may be false—a discrepancy without a great workaround yet.

  5. Download

    • Once you’ve validated the target, there are multiple ways to download. With ssh2-sftp-client, use get or fastGet. If you’re in an SSH session, sz also works.
    • Empty files are supported by these methods. Note that with get as a stream, the data event may not fire on empty files, but end will.

Final Thoughts

With right-click download, the experience is smoother, though the underlying mechanism is similar to other download paths.

Authors
Developer, digital product enthusiast, tinkerer, sharer, open source lover