|
| 1 | +<table><tr> |
| 2 | +<td colspan="1"> <h3 align="center"> <picture> |
| 3 | +<source media="(prefers-color-scheme: dark)" srcset="https://PlayForm.Cloud/Dark/Image/GitHub/Land.svg"> |
| 4 | +<source media="(prefers-color-scheme: light)" srcset="https://PlayForm.Cloud/Image/GitHub/Land.svg"> |
| 5 | +<img width="28" alt="Land Logo" src="https://PlayForm.Cloud/Image/GitHub/Land.svg"> |
| 6 | +</picture> </h3> </td> <td colspan="3" valign="top"> <h3 align="center"> Mountain ⛰️ |
| 7 | +</h3> </td> |
| 8 | +</tr></table> |
| 9 | + |
| 10 | +# **Mountain** ⛰️ Deep Dive & Architecture |
| 11 | + |
| 12 | +This document provides a detailed technical overview of the **Mountain** project |
| 13 | +for developers. It explores the internal architecture, the flow of control from |
| 14 | +request to execution, and the design patterns used to create a robust, |
| 15 | +effects-based native backend for the Land Code Editor. |
| 16 | + |
| 17 | +## Core Architecture Principles |
| 18 | + |
| 19 | +| Principle | Description | Key Components Involved | |
| 20 | +| :------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------- | |
| 21 | +| **Implementation of Contracts** | Faithfully implement the abstract service `trait`s defined in the `Common` crate, providing the concrete logic for the application's architecture. | `environment/*` providers | |
| 22 | +| **Separation of Concerns** | Isolate business logic in `handlers` modules, keeping the `environment` provider implementations clean and focused on delegation. | `environment/*`, `handlers/*` | |
| 23 | +| **Declarative Logic** | Express all operations as `ActionEffect`s, which are executed by the `AppRuntime`. This makes logic composable, testable, and robust. | `runtime/*`, `track/*`, `Common::effect` | |
| 24 | +| **Centralized State** | Maintain a single, thread-safe `AppState` struct managed by Tauri to ensure data consistency across the entire application. | `app_state/*` | |
| 25 | +| **Secure & Performant IPC** | Utilize gRPC for all communication with the `Cocoon` sidecar, ensuring a well-defined and high-performance API boundary. | `vine/*` | |
| 26 | +| **UI-Backend Decoupling** | Interact with the `Wind` frontend exclusively through asynchronous Tauri commands and events, ensuring the backend is UI-agnostic. | `main.rs` (invoke handler), `handlers/*` (emitters) | |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Deep Dive into `Mountain`'s Components |
| 31 | + |
| 32 | +### 1. The `main.rs` Entry Point and Tauri Setup |
| 33 | + |
| 34 | +- **Role:** This is the application's bootstrap sequence. |
| 35 | +- **Functionality:** |
| 36 | + - Initializes logging (`env_logger`). |
| 37 | + - Creates the `tauri::Builder` and configures the application. |
| 38 | + - Uses the `.setup()` hook as the primary initialization point. Inside this |
| 39 | + hook, it performs the critical task of creating the singleton instances of |
| 40 | + `AppState`, `MountainEnvironment`, and `AppRuntime` and placing them into |
| 41 | + Tauri's managed state (`AppHandle.manage(...)`). |
| 42 | + - Spawns a background `tokio` task for long-running initializations (like |
| 43 | + scanning for extensions and starting the gRPC server) to avoid blocking |
| 44 | + the main thread and allow the UI to appear faster. |
| 45 | + - Registers all Tauri command handlers (e.g., `track::DispatchCommand`), |
| 46 | + which are the entry points for requests coming from the `Wind` UI. |
| 47 | + - Handles application lifecycle events, such as `RunEvent::ExitRequested`. |
| 48 | + |
| 49 | +### 2. The `runtime` and `environment` Modules (The Execution Core) |
| 50 | + |
| 51 | +- **Role:** These two modules work together to form the execution engine for the |
| 52 | + application's logic. |
| 53 | +- **`runtime/`:** |
| 54 | + - `AppRuntime.rs` provides the concrete `AppRuntime` for `Mountain`. It |
| 55 | + holds an instance of the `MountainEnvironment`. |
| 56 | + - Its primary method, `Run`, takes an `ActionEffect` from the `Common` |
| 57 | + crate. It determines the required capability (e.g., `dyn FsReader`), gets |
| 58 | + it from its environment, and then applies the effect, executing the |
| 59 | + wrapped async function. |
| 60 | +- **`environment/`:** |
| 61 | + - `MountainEnvironment.rs` is the central struct that **implements all |
| 62 | + provider `trait`s** from `Common`. For example, it contains |
| 63 | + `impl FsReader for MountainEnvironment`. |
| 64 | + - **Crucially, the `impl` blocks in this module contain no business logic.** |
| 65 | + They are a clean "wiring" layer. Each method is a one-line call that |
| 66 | + delegates to a corresponding function in the `handlers` module (e.g., |
| 67 | + `self.ReadFile(...)` calls `handlers::fs::ReadFileLogic(...)`). |
| 68 | + - `Utils.rs` contains shared helper functions used across multiple provider |
| 69 | + implementations, such as error mapping and security checks. |
| 70 | + |
| 71 | +### 3. The `app_state` Module (The Single Source of Truth) |
| 72 | + |
| 73 | +- **Role:** To provide a single, globally accessible, thread-safe container for |
| 74 | + all of the application's runtime state. |
| 75 | +- **Structure:** |
| 76 | + - The `AppState` struct contains fields like `WorkspaceFolders`, |
| 77 | + `Configuration`, `ActiveTerminals`, and `LanguageProviders`. |
| 78 | + - Every field is wrapped in `Arc<Mutex<...>>` (or `Arc<Atomic...>` for |
| 79 | + simple types) to allow for safe, shared access from any asynchronous task |
| 80 | + or thread in the application (e.g., a gRPC request handler and a Tauri |
| 81 | + command handler can both safely access `AppState`). |
| 82 | + - The `default()` implementation initializes the state, reads initial data |
| 83 | + from disk (like Memento storage), and sets up default values. |
| 84 | + |
| 85 | +### 4. The `handlers` Module (The Business Logic Layer) |
| 86 | + |
| 87 | +- **Role:** This is where the actual work gets done. By isolating logic here, |
| 88 | + the `environment` module remains clean, and the business logic is easy to |
| 89 | + find, read, and test. |
| 90 | +- **Functionality:** |
| 91 | + - Each submodule (`handlers/fs`, `handlers/terminal`, etc.) corresponds to a |
| 92 | + service domain. |
| 93 | + - Functions within these modules (e.g., `ReadFileLogic`, |
| 94 | + `CreateTerminalLogic`) perform the concrete operations. They take the |
| 95 | + `AppHandle` as an argument, which allows them to access `AppState`. |
| 96 | + - They interact with the native OS using crates like `tokio::fs`, |
| 97 | + `portable-pty`, and `keyring`. |
| 98 | + - After performing an operation and updating `AppState`, they are often |
| 99 | + responsible for emitting Tauri events to notify the `Wind` UI of the |
| 100 | + change (e.g., `AppHandle.emit("sky://terminal/data", ...)`). |
| 101 | + |
| 102 | +### 5. The `vine` and `track` Modules (The Communication & Dispatch Layer) |
| 103 | + |
| 104 | +- **Role:** These modules form the application's "front door" for all external |
| 105 | + requests coming from `Cocoon` and `Wind`. |
| 106 | +- **`vine/` (gRPC):** |
| 107 | + - `proto/vine.proto`: Defines the gRPC contract. It is the single source of |
| 108 | + truth for the `Mountain <-> Cocoon` API. |
| 109 | + - `build.rs`: Compiles the `.proto` file into Rust code using `tonic-build`. |
| 110 | + - `server/MountainVineGrpcService.rs`: Implements the `MountainService` |
| 111 | + trait generated by `tonic`. This is the gRPC request handler. When it |
| 112 | + receives a call (e.g., `ProcessCocoonRequest`), its only job is to pass |
| 113 | + the method name and parameters to the `track` dispatcher. |
| 114 | +- **`track/` (Dispatcher):** |
| 115 | + - `TrackLogic.rs` is the central router for the entire application. It |
| 116 | + exposes two primary functions: `DispatchCommand` (for Tauri invokes from |
| 117 | + `Wind`) and `DispatchSidecarRequest` (for gRPC calls from `Cocoon`). |
| 118 | + - **Dispatch Strategy:** When a request comes in, the dispatcher first |
| 119 | + consults `EffectCreation.rs`. It attempts to map the request's method name |
| 120 | + and parameters into a declarative `ActionEffect`. If a mapping exists, it |
| 121 | + passes the `ActionEffect` to the `AppRuntime` for execution. |
| 122 | + - **Fallback:** If no `ActionEffect` mapping is found (for legacy or highly |
| 123 | + specific RPCs), it falls back to a direct RPC handler system (not fully |
| 124 | + detailed in the synthesis, but this is the architectural slot for it). |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## End-to-End Workflow Example: `CreateTerminal` |
| 129 | + |
| 130 | +This demonstrates how all the components work together in a typical flow. |
| 131 | + |
| 132 | +1. **Request Origin:** `Cocoon` sends a `CreateTerminal` gRPC request to |
| 133 | + `Mountain`. |
| 134 | +2. **Vine (gRPC Server):** `MountainVineGrpcService` receives the gRPC call. It |
| 135 | + extracts the method name (`"$createTerminal"`) and parameters. It passes |
| 136 | + these to `track::DispatchSidecarRequest`. |
| 137 | +3. **Track (Dispatcher):** The dispatcher looks up `"$createTerminal"` in |
| 138 | + `EffectCreation`. It finds a match and constructs a |
| 139 | + `Common::terminal::CreateTerminal` `ActionEffect`. |
| 140 | +4. **Runtime:** The dispatcher calls `AppRuntime.Run(effect)`. |
| 141 | +5. **Environment (Execution):** |
| 142 | + - The `AppRuntime` sees that the effect requires the `dyn TerminalProvider` |
| 143 | + capability. |
| 144 | + - It gets the `MountainEnvironment` and calls its `.Require()` method to get |
| 145 | + an `Arc<dyn TerminalProvider>`. |
| 146 | + - It applies the effect, which invokes the |
| 147 | + `TerminalProvider::CreateTerminal` method on the `MountainEnvironment`. |
| 148 | +6. **Provider (Delegation):** The |
| 149 | + `impl TerminalProvider for MountainEnvironment` block immediately delegates |
| 150 | + the call to `handlers::terminal::CreateTerminalLogic`, passing along its |
| 151 | + `AppHandle`. |
| 152 | +7. **Handler (Business Logic):** |
| 153 | + - The `CreateTerminalLogic` function performs the actual work. |
| 154 | + - It gets a new ID from `AppState`. |
| 155 | + - It uses `portable-pty` to spawn a native shell process. |
| 156 | + - It creates a `TerminalStateDto` and stores it in `AppState`. |
| 157 | + - It spawns `tokio` tasks to handle I/O streaming. |
| 158 | + - It sends gRPC notifications (`$acceptTerminalOpened`) back to `Cocoon`. |
| 159 | + - It emits Tauri events (`sky://terminal/create`) to `Wind`. |
| 160 | + - It returns a `Result` indicating success or failure. |
| 161 | +8. **Unwinding:** The `Result` unwinds back up the call stack: from the |
| 162 | + handler, through the environment, out of the `AppRuntime`, through the |
| 163 | + dispatcher, and finally, `MountainVineGrpcService` sends it back to `Cocoon` |
| 164 | + as the gRPC response. |
0 commit comments