Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.monolex.ai/llms.txt

Use this file to discover all available pages before exploring further.

Design Patterns in MonoTerm

This document explains the key design patterns used in MonoTerm’s architecture. These patterns are language-independent design solutions, not Rust-specific features.
┌─────────────────────────────────────────────────────────────────┐
│  PATTERN ORIGINS                                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   SessionActor Pattern          ACK Flow Control                │
│   ──────────────────            ────────────────                │
│                                                                 │
│   Origin: Erlang (1986)         Origin: TCP/IP (1974)           │
│   Level: Concurrency Pattern    Level: Network Protocol         │
│                                                                 │
│   Actor Model (1973)            TCP ACK (1974)                  │
│       │                             │                           │
│       ▼                             ▼                           │
│   Erlang/OTP                    Backpressure                    │
│       │                             │                           │
│       ▼                             ▼                           │
│   Akka (Scala), Orleans (C#)    Flow Control                    │
│       │                             │                           │
│       ▼                             ▼                           │
│   Tokio MPSC (Rust)             MonoTerm ACK                    │
│                                                                 │
│   Conclusion: Design pattern level, not system level            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

The Problem: Concurrent Access

Multiple parts of the system need to access session data simultaneously.
┌─────────────────────────────────────────────────────────────────┐
│  THE CONCURRENT ACCESS PROBLEM                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Places that access "sessions" data:                           │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │  1. User creates new tab     Insert new session         │   │
│   │  2. PTY data arrives         Write to session           │   │
│   │  3. User closes tab          Remove session             │   │
│   │  4. Resize event             Modify session             │   │
│   │  5. Tray menu lists tabs     Read all sessions          │   │
│   │                                                         │   │
│   │  These can happen SIMULTANEOUSLY!                       │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Dangerous Situation:                                          │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   Thread A: Processing PTY data...                      │   │
│   │             Get session "tab-1"                         │   │
│   │             Write data...         While writing!        │   │
│   │                                        │                │   │
│   │   Thread B: User closes tab!           ▼                │   │
│   │             Remove "tab-1"     Simultaneous delete!     │   │
│   │                                                         │   │
│   │   Result: Crash!                                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Solution 1: Mutex (Traditional)

The traditional approach uses locks.
┌─────────────────────────────────────────────────────────────────┐
│  MUTEX APPROACH                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Must acquire lock on every access                             │
│                                                                 │
│   Thread A          Thread B          Thread C                  │
│      │                 │                 │                      │
│      ▼                 ▼                 ▼                      │
│   lock()           lock()            lock()                     │
│      │                │ WAIT             │ WAIT                 │
│   working...          │                  │                      │
│      │                │                  │                      │
│   unlock()            │                  │                      │
│                    working...            │                      │
│                       │                  │                      │
│                    unlock()              │                      │
│                                      working...                 │
│                                                                 │
│   Problems:                                                     │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  Lock Contention: Only one can work at a time           │   │
│   │  Deadlock Risk: A waits for B, B waits for A = frozen   │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Solution 2: Actor Pattern (MonoTerm)

MonoTerm uses the Actor pattern - no locks needed.
┌─────────────────────────────────────────────────────────────────┐
│  ACTOR PATTERN                                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Core Idea:                                                    │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  Don't touch data directly                              │   │
│   │  Send a message to the person in charge (Actor)         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│                                                                 │
│   Thread A ──┐                                                  │
│              │     ┌─────────────┐                              │
│   Thread B ──┼────▶│  MPSC       │────▶ SessionActor            │
│              │     │  Channel    │      (single owner)          │
│   Thread C ──┘     └─────────────┘           │                  │
│                                              ▼                  │
│                                          sessions               │
│                                          (data)                 │
│                                                                 │
│   Rules:                                                        │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  Anyone can put messages in Channel (simultaneous OK)   │   │
│   │  Only Actor accesses sessions (1 person = no conflicts) │   │
│   │  No locks needed!                                       │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ═══════════════════════════════════════════════════════════   │
│                                                                 │
│   Analogy:                                                      │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   Mutex = Multiple people trying to open refrigerator   │   │
│   │           Take turns one by one (Lock)                  │   │
│   │           Pushing causes accidents (Deadlock)           │   │
│   │                                                         │   │
│   │   Actor = One refrigerator manager                      │   │
│   │           Leave note "get me a coke please"             │   │
│   │           Manager processes requests in order           │   │
│   │           Conflicts are impossible                      │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

SessionActor Structure

The SessionActor owns all session state.
┌─────────────────────────────────────────────────────────────────┐
│  SESSIONACTOR STRUCTURE                                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Message Types (what requests are possible):                   │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │    CreateSession     Create new tab                     │   │
│   │    CloseSession      Close tab                          │   │
│   │    WriteData         Write to PTY                       │   │
│   │    Resize            Change terminal size               │   │
│   │    GridAck           ACK received from frontend         │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Actor Owns:                                                   │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │    sessions          Session data (Actor only!)         │   │
│   │    grid_workers      Per-session workers                │   │
│   │    rx                Mailbox (receives messages)        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Actor Main Loop:                                              │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │    loop {                                               │   │
│   │        Get message from mailbox                         │   │
│   │                                                         │   │
│   │        Match message type:                              │   │
│   │            CreateSession  Create new session            │   │
│   │            CloseSession   Remove session                │   │
│   │            WriteData      Write to session              │   │
│   │            Resize         Resize session                │   │
│   │            GridAck        Open ACK gate                 │   │
│   │    }                                                    │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Actor Pattern Benefits

┌─────────────────────────────────────────────────────────────────┐
│  ACTOR BENEFITS                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Frontend             Tauri Commands        SessionActor       │
│   (TypeScript)         (multiple threads)    (single owner)     │
│                                                                 │
│   ┌─────────┐                                                   │
│   │ New Tab │────┐                                              │
│   └─────────┘    │                                              │
│                  │      ┌──────────┐       ┌─────────────────┐  │
│   ┌─────────┐    ├─────▶│ MPSC     │──────▶│ SessionActor    │  │
│   │ Resize  │────┤      │ Channel  │       │                 │  │
│   └─────────┘    │      └──────────┘       │ sessions: {...} │  │
│                  │                         │      ↑          │  │
│   ┌─────────┐    │                         │ Only accessible │  │
│   │Close Tab│────┘                         │ from here!      │  │
│   └─────────┘                              └─────────────────┘  │
│                                                                 │
│   ┌─────────┐                                     │             │
│   │PTY Data │─────────────────────────────────────┘             │
│   └─────────┘                                                   │
│                                                                 │
│   ═══════════════════════════════════════════════════════════   │
│                                                                 │
│   Actor Benefits:                                               │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  No lock contention    (single owner)                   │   │
│   │  No deadlocks          (no locks!)                      │   │
│   │  Guaranteed ordering   (MPSC channel)                   │   │
│   │  Easy to reason about  (one thread owns state)          │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Why Rust?

The patterns work in any language, but Rust provides additional benefits.
┌─────────────────────────────────────────────────────────────────┐
│  WHY RUST FOR MONOTERM                                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Patterns work anywhere:                                       │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   JavaScript    Python    Go    Rust                    │   │
│   │       ✓           ✓       ✓       ✓                     │   │
│   │                                                         │   │
│   │   Actor pattern and ACK flow control work in all        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Where Rust matters:                                           │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   1. VTE Parsing (Alacritty)                            │   │
│   │      Called thousands of times per second               │   │
│   │      GC would cause stuttering                          │   │
│   │                                                         │   │
│   │   2. Cell Processing                                    │   │
│   │      120 cols x 40 rows = 4,800 cells                   │   │
│   │      Needs native speed                                 │   │
│   │                                                         │   │
│   │   3. PTY I/O                                            │   │
│   │      Unix socket communication                          │   │
│   │      Needs system-level access                          │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Architecture choice:                                          │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   Option A: VTE(Rust) → IPC → SessionActor(JS) → IPC    │   │
│   │                                                         │   │
│   │   Option B: VTE(Rust) + SessionActor(Rust) → IPC        │   │
│   │             ↑ MonoTerm uses this                        │   │
│   │                                                         │   │
│   │   IPC count: A = 2 times, B = 1 time                    │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Complete Architecture

┌─────────────────────────────────────────────────────────────────┐
│  PATTERNS ACROSS UNIX SOCKET                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   PTY Daemon              Unix Socket            Tauri Backend  │
│   ──────────              ───────────            ─────────────  │
│                                                                 │
│   ┌─────────┐                                   ┌─────────────┐ │
│   │  Shell  │                                   │SessionActor │ │
│   │  bash   │────────────────────────────────▶  │             │ │
│   │  zsh    │           Raw bytes               │  Sessions   │ │
│   │  fish   │                                   │  Workers    │ │
│   └─────────┘                                   └──────┬──────┘ │
│                                                        │        │
│                                                        ▼        │
│                                               ┌─────────────┐   │
│                                               │  VTE Parser │   │
│                                               │ (Alacritty) │   │
│                                               └──────┬──────┘   │
│                                                      │          │
│                                                      ▼          │
│                               Tauri IPC     ┌─────────────┐     │
│   Frontend ◀────────────────────────────────│ Cell Convert│     │
│   (xterm.js WebGL)                          │  + DiffHint │     │
│                                             └─────────────┘     │
│                                                                 │
│   Pattern Summary:                                              │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  SessionActor: Lock-free concurrency via MPSC           │   │
│   │  ACK Flow: Frontend-driven backpressure                 │   │
│   │  Sidecar: PTY daemon survives app crash                 │   │
│   │  DiffHint: Intelligent partial rendering                │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Summary

┌─────────────────────────────────────────────────────────────────┐
│  DESIGN PATTERNS SUMMARY                                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   SessionActor / ACK Flow Control:                              │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  Level: Design Pattern (language-independent)           │   │
│   │  Origin: Erlang (Actor), TCP (ACK)                      │   │
│   │  Rust required? NO                                      │   │
│   │  Works in JS/Python/Go? YES                             │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Where Rust is critical:                                       │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  VTE Parsing (Alacritty)    Performance critical        │   │
│   │  PTY I/O (Unix socket)      System level                │   │
│   │  Cell Processing            Better without GC           │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   Why this architecture:                                        │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  VTE parsing is in Rust anyway                          │   │
│   │  SessionActor in Rust reduces IPC overhead              │   │
│   │  Patterns are high-level, placement determines perf     │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘