Files
rfcp/docs/RFCP-Native-Backend-Research.md

6.2 KiB

RFCP Native Backend Research

Executive Summary

Finding: The production Electron app already supports native Windows operation without WSL2.

The production build uses PyInstaller to bundle the Python backend as a standalone Windows executable (rfcp-server.exe). WSL2 is only used during development. No migration is needed for end users.


Current Architecture

Development Mode

RFCP (Electron dev)
  └── Spawns: python -m uvicorn app.main:app --host 127.0.0.1 --port 8090
      └── Uses system Python (Windows or WSL2)
          └── Requires venv with dependencies

Production Mode (Already Implemented)

RFCP.exe (Electron packaged)
  └── Spawns: rfcp-server.exe (bundled PyInstaller binary)
      └── Self-contained Python + all dependencies
      └── No WSL2 required
      └── No system Python required

Evidence from Codebase

desktop/main.js (Lines 120-145)

function startBackend() {
  // Production: use bundled executable
  if (isProduction) {
    const serverPath = path.join(process.resourcesPath, 'rfcp-server.exe');
    if (fs.existsSync(serverPath)) {
      backendProcess = spawn(serverPath, [], { ... });
      return;
    }
  }

  // Development: use system Python
  backendProcess = spawn('python', ['-m', 'uvicorn', 'app.main:app', ...]);
}

installer/rfcp-server.spec (PyInstaller Config)

# Key configuration
a = Analysis(
    ['run_server.py'],
    pathex=[backend_path],
    binaries=[],
    datas=[
        ('data/terrain', 'data/terrain'),  # Terrain data bundled
    ],
    hiddenimports=[
        'uvicorn.logging', 'uvicorn.loops', 'uvicorn.protocols',
        'motor', 'pymongo', 'numpy', 'scipy', 'shapely',
        # Full list of dependencies
    ],
)

exe = EXE(
    pyz,
    a.scripts,
    name='rfcp-server',
    console=True,  # Shows console for debugging
    icon='rfcp.ico',
)

GPU Acceleration in Production

Current Status

The PyInstaller bundle does not include CuPy by default because:

  1. CuPy requires CUDA runtime (large, ~500MB)
  2. Not all users have NVIDIA GPUs
  3. Binary would be too large for distribution

Solution Options

Option A: Ship CPU-only (Current)

  • Production build uses NumPy (CPU) for calculations
  • GPU acceleration available only in dev mode or manual install
  • Smallest download size (~100MB)

Option B: Separate GPU Installer

  • Main installer: CPU-only (~100MB)
  • Optional GPU addon: Downloads CuPy + CUDA runtime (~600MB)
  • Implemented via install_rfcp.py dependency installer

Option C: CUDA Toolkit Detection

  • Detect if CUDA is already installed on user's system
  • If yes, attempt to load CuPy dynamically
  • Graceful fallback to NumPy if not available

Recommendation

Keep Option A (CPU-only production) with Option B available for power users:

  1. Default production build works everywhere
  2. Users with NVIDIA GPUs can run install_rfcp.py to enable GPU acceleration
  3. No WSL2 required for either path

Terrain Data Handling

Current Implementation

Terrain data (SRTM .hgt files) is bundled inside the PyInstaller executable:

datas=[
    ('data/terrain', 'data/terrain'),
]

Considerations

  • Bundled terrain data increases exe size significantly
  • Alternative: Download terrain on first use (like current region download system)
  • For initial release, bundling common regions is acceptable

Database (MongoDB)

Production Architecture

The Electron app embeds MongoDB or requires MongoDB to be installed separately.

Options:

  1. Embedded MongoDB - Ships mongod.exe with the app
  2. MongoDB Atlas - Cloud database (requires internet)
  3. SQLite - Switch to file-based database (significant refactor)
  4. In-memory + file persistence - No MongoDB required (significant refactor)

Current implementation uses Motor (async MongoDB driver). For true standalone operation, consider SQLite migration in future iteration.


Build Process

Current Build Commands

# Build backend executable
cd /mnt/d/root/rfcp/backend
pyinstaller ../installer/rfcp-server.spec

# Build Electron app with bundled backend
cd /mnt/d/root/rfcp/installer
./build-win.sh

Output

  • rfcp-server.exe - Standalone backend (~80MB)
  • RFCP-Setup-{version}.exe - Full installer with Electron + backend (~150MB)

Testing Native Build

Test Procedure

  1. Build rfcp-server.exe via PyInstaller
  2. Run directly: ./rfcp-server.exe
  3. Verify API responds: curl http://localhost:8090/api/health
  4. Verify coverage calculation works
  5. Check GPU detection in logs

Known Issues

  1. First launch slow: PyInstaller extracts on first run (~5-10 seconds)
  2. Antivirus false positives: Some AV flags PyInstaller executables
  3. Console window: Shows black console (use console=False for windowless)

Conclusions

No Migration Needed

The production Electron app already works without WSL2. The current architecture is:

  • Native Windows executable
  • No Python installation required
  • No WSL2 required
  • Self-contained dependencies

Development vs Production

Aspect Development Production
Python System Python / venv Bundled via PyInstaller
WSL2 Optional (for testing) Not required
GPU CuPy if installed CPU-only (NumPy)
MongoDB Local instance Embedded or Atlas
Terrain Local data/ folder Bundled in exe

Remaining Work

  1. GPU for production: Implement Optional GPU addon installer
  2. Smaller package: On-demand terrain download instead of bundling
  3. Database portability: Consider SQLite migration for offline-first
  4. Installer polish: Signed executables, auto-update support

Appendix: Full PyInstaller Hidden Imports

From installer/rfcp-server.spec:

hiddenimports=[
    'uvicorn.logging',
    'uvicorn.loops',
    'uvicorn.loops.auto',
    'uvicorn.protocols',
    'uvicorn.protocols.http',
    'uvicorn.protocols.http.auto',
    'uvicorn.protocols.websockets',
    'uvicorn.protocols.websockets.auto',
    'uvicorn.lifespan',
    'uvicorn.lifespan.on',
    'motor',
    'pymongo',
    'numpy',
    'scipy',
    'shapely',
    'shapely.geometry',
    'shapely.ops',
    # ... additional imports
]