small hot-reloading
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
# Config Struct Analysis: cargo run vs Standalone EXE
|
||||
|
||||
## QUICK ANSWER
|
||||
|
||||
**The config.toml modifications work in `cargo run` but not standalone EXE because:**
|
||||
|
||||
1. **Both behave identically** - neither reloads config during runtime
|
||||
2. **The difference is file location** - where config.toml is searched for
|
||||
3. **cargo run appears to work** because users restart the process frequently
|
||||
4. **Standalone EXE appears broken** because users expect live reloading
|
||||
|
||||
The real issue: **Config is frozen at startup and never reloaded.**
|
||||
|
||||
---
|
||||
|
||||
## THE CORE PROBLEM
|
||||
|
||||
### Configuration Loading (One-Time Only)
|
||||
|
||||
**File: `src/main.rs`, Line 54**
|
||||
```rust
|
||||
let app_config = config::load_config(); // Loaded ONCE, never again
|
||||
```
|
||||
|
||||
### Configuration Freezing Points
|
||||
|
||||
**Freeze Point 1: BackgroundRenderer (`src/app.rs:28-34`)**
|
||||
```rust
|
||||
let background_renderer = Some(Arc::new(BackgroundRenderer::new(
|
||||
&cc.egui_ctx,
|
||||
&config.appearance.background_image,
|
||||
config.appearance.background_opacity, // ← COPIED
|
||||
config.appearance.fallback_color, // ← COPIED
|
||||
config.appearance.fallback_color_opacity, // ← COPIED
|
||||
)));
|
||||
```
|
||||
- Appearance values **copied** into struct once
|
||||
- Stored in `Arc<BackgroundRenderer>` (immutable)
|
||||
- **Never updated** during application lifetime
|
||||
|
||||
**Freeze Point 2: Config Field (`src/app.rs:49`)**
|
||||
```rust
|
||||
Self {
|
||||
config, // ← Stored as owned field, never mutated
|
||||
// ...
|
||||
}
|
||||
```
|
||||
- Config struct **stored once** at initialization
|
||||
- Colors, text sizing, window settings **frozen**
|
||||
- **Never reloaded** from disk
|
||||
- **Never updated** at runtime
|
||||
|
||||
---
|
||||
|
||||
## WHY CHANGES DON'T APPEAR
|
||||
|
||||
### Background Changes (opacity, color)
|
||||
|
||||
1. User modifies `config.toml` (e.g., changes `background_opacity`)
|
||||
2. Application still has original value in `BackgroundRenderer` memory
|
||||
3. Every frame, `render_fullscreen()` uses **frozen opacity value**
|
||||
4. No code to reload config or recreate `BackgroundRenderer`
|
||||
5. **Change never takes effect**
|
||||
|
||||
### Color Changes
|
||||
|
||||
1. User modifies `config.toml` (e.g., changes text color)
|
||||
2. Application still has original `Config` struct in memory
|
||||
3. Every frame, `update()` reads from `self.config`
|
||||
4. But `self.config` was never updated
|
||||
5. `ctx.set_visuals()` applies **same frozen colors**
|
||||
6. **Change never takes effect**
|
||||
|
||||
---
|
||||
|
||||
## cargo run vs Standalone: The REAL Story
|
||||
|
||||
### cargo run Process
|
||||
|
||||
```
|
||||
User runs: cargo run
|
||||
├─ New process created
|
||||
├─ load_config() reads config.toml from repo root (fallback path)
|
||||
├─ Application starts with current config
|
||||
├─ User modifies config.toml while app is running
|
||||
│ └─ Change DOESN'T take effect (no reload mechanism)
|
||||
├─ User exits app
|
||||
├─ User runs: cargo run again
|
||||
│ ├─ New process created
|
||||
│ ├─ load_config() reads UPDATED config.toml
|
||||
│ └─ Application shows new values ✓
|
||||
└─ User thinks "config changes work in cargo run!"
|
||||
```
|
||||
|
||||
### Standalone EXE Process
|
||||
|
||||
```
|
||||
User runs: Create-App-Secret.exe
|
||||
├─ Process created
|
||||
├─ load_config() looks in EXE directory
|
||||
│ └─ If config.toml exists there, loads it
|
||||
│ └─ Otherwise falls back to ./config.toml
|
||||
├─ Application starts with current config
|
||||
├─ User modifies config.toml while app is running
|
||||
│ └─ Change DOESN'T take effect (no reload mechanism)
|
||||
├─ User expects changes to appear
|
||||
│ └─ Nothing happens ✗
|
||||
├─ User closes app
|
||||
├─ User runs: Create-App-Secret.exe again
|
||||
│ ├─ New process created
|
||||
│ ├─ load_config() reads UPDATED config.toml
|
||||
│ └─ Application shows new values ✓
|
||||
└─ User thinks "config changes don't work in standalone!"
|
||||
```
|
||||
|
||||
### The Actual Difference
|
||||
|
||||
| Aspect | cargo run | Standalone |
|
||||
|--------|-----------|-----------|
|
||||
| Config loading code | Identical | Identical |
|
||||
| Config freezing | Yes, identical | Yes, identical |
|
||||
| Hot-reload | No | No |
|
||||
| Updates on restart | Yes ✓ | Yes ✓ |
|
||||
| File location | Repo root (fallback) | EXE directory |
|
||||
|
||||
---
|
||||
|
||||
## CODE PATH: From Config Loading to Display
|
||||
|
||||
```
|
||||
main.rs:54
|
||||
↓
|
||||
config::load_config() ← Reads config.toml from disk [ONCE]
|
||||
↓
|
||||
Returns Config struct
|
||||
↓
|
||||
main.rs:76
|
||||
↓
|
||||
Moved into AzureAppManager::new()
|
||||
↓
|
||||
app.rs:28-34: BackgroundRenderer created
|
||||
└─ opacity, fallback_color COPIED from config [FROZEN]
|
||||
└─ Stored in Arc<BackgroundRenderer>
|
||||
↓
|
||||
app.rs:49: Config stored
|
||||
└─ self.config = config [FROZEN]
|
||||
↓
|
||||
eframe event loop (every frame ~60x/sec):
|
||||
├─ app.rs:375-457: update() called
|
||||
│ ├─ app.rs:380: Read colors from self.config [frozen values]
|
||||
│ ├─ app.rs:467: Read text sizing from self.config [frozen values]
|
||||
│ ├─ app.rs:489: Read position offset from self.config [frozen values]
|
||||
│ └─ app.rs:505-507: Render background with frozen renderer
|
||||
│
|
||||
└─ Every frame: Same frozen values used again
|
||||
(Because no code reloads or updates them)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Would Be Needed to Fix
|
||||
|
||||
### 1. File Watching
|
||||
```rust
|
||||
// Add to Cargo.toml
|
||||
notify = "6.0" // File system event watcher
|
||||
```
|
||||
|
||||
### 2. Config Reload Mechanism
|
||||
```rust
|
||||
pub fn reload_config_from_disk() -> Config {
|
||||
config::load_config() // Re-read from disk
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Mutable Config Storage
|
||||
```rust
|
||||
// Change from:
|
||||
config: Config
|
||||
|
||||
// To:
|
||||
config: Arc<Mutex<Config>>
|
||||
```
|
||||
|
||||
### 4. Updatable Background Renderer
|
||||
```rust
|
||||
// Either:
|
||||
// - Store as Arc<Mutex<BackgroundRenderer>>
|
||||
// - Or recreate it every frame with current config values
|
||||
```
|
||||
|
||||
### 5. Hot Reload Trigger
|
||||
```rust
|
||||
if config_file_changed {
|
||||
new_config = reload_config_from_disk();
|
||||
update_background_renderer(&new_config);
|
||||
ctx.request_repaint();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary Table
|
||||
|
||||
| Component | Location | Issue | Status |
|
||||
|-----------|----------|-------|--------|
|
||||
| Config loading | `main.rs:54` | Loaded once | FROZEN |
|
||||
| Config movement | `main.rs:76` | Moved via ownership | FROZEN |
|
||||
| Background values | `app.rs:28-34` | Copied into struct | FROZEN |
|
||||
| Config storage | `app.rs:49` | Stored as owned field | FROZEN |
|
||||
| Color application | `app.rs:380-444` | Reads frozen config | EVERY FRAME |
|
||||
| Background rendering | `background.rs:106` | Uses frozen values | EVERY FRAME |
|
||||
| Reload mechanism | *Not found* | No file watching | ✗ MISSING |
|
||||
|
||||
---
|
||||
|
||||
## Key Insight
|
||||
|
||||
**The application architecture assumes configuration is set once at startup and never changes.** This is a design choice, not a bug. The same frozen-config behavior exists in both `cargo run` and standalone EXE.
|
||||
|
||||
The perceived difference comes from:
|
||||
- **cargo run**: Users frequently restart processes → see updated config
|
||||
- **Standalone EXE**: Users expect live updates → see frozen config
|
||||
|
||||
Both are executing identical code with identical behavior.
|
||||
|
||||
Reference in New Issue
Block a user