Tech Stack & Architecture - MariooC14/Seraph GitHub Wiki

Tools

  • Electron

    • React
    • Tailwind CSS
    • shadcn ui
    • Redux
  • Terminal

    • Xterm.js
    • node-pty
    • node-ssh

App Architecture

image

As the app is electron based, it is made up of three distinct sections (see electron docs):

  • Main process
  • Preload script
  • Renderer

Main process (src/main)

The main process is the part of the app that runs in a nodeJS environment. It has full access to all node APIs. In our case, we have the ability to access files on the device (for reading / writing user config files and later host information), and to spawn PTY sessions.

The main process has a Terminal Session Manager, which is responsible for creating and storing terminal sessions, including local and ssh sessions. It can also terminate sessions, although it is up to the session itself to handle it.

When the Terminal Session Manager creates a session (by spawning a local PTY or establishing an SSH connection), it creates a TerminalSession instance which has a sessionId (randomly generated) which the renderer process can use to send and receive IO. This is exposed using ipcMain, which the renderer can access via the preload script.

Each session has a window related to it (may be useful if or when we add multiple window support).

Preload (preload.ts)

The preload script is used to allow the main process to expose specific APIs to the renderer process. In our case, we expose our custom terminal session related API and app related APIs like exit, maximize, isMacOS.

Renderer

The renderer is essentially the view that the user sees. It can only access APIs that a regular web page could, plus the extra APIs that we specify in our preload script.

We use Redux for renderer state management, which contains two slices:

  • Config slice - used for storing user config, e.g. default local shell.
  • terminal tabs slice - used for managing terminal tabs.

We initially thought about using react context providers, but the code got too messy and tightly coupled. I believe the potential app complexity will justify the use of redux.

The terminal tabs slice works with the ClientTerminalSessionRegistry to manage the terminal tabs. As terminal sessions are not serializable, they cannot be stored directly in the store. Thus the store only stores the session id and uses it to retrieve the session via the TerminalSessionRegistry.

There is a distinction between client terminal session and terminal sessions (in main process) (TODO: Write doc on this).