227 lines
6.5 KiB
Markdown
227 lines
6.5 KiB
Markdown
# 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.
|
|
|