ARCHITECTURE: - Windows: dedicated WSL2 distro with fixed VHDX, Docker inside - macOS: Lima VM with fixed disk, Docker inside - Linux: sparse ext4 loopback image, Docker data-root inside NEW FILES: - vm-provisioner.js: core provisioning engine (create/start/destroy/export) - Disk presets: Minimal(10GB), Balanced(30GB), Power(100GB), Custom - Sparse images that grow on demand (start at ~0 bytes) - Full lifecycle: provision → deploy DashCaddy → destroy (clean removal) - Data export before uninstall for users who want to migrate - vm-ipc.js: Electron IPC handlers connecting wizard to provisioner - vm:provision, vm:destroy, vm:get-status, vm:export-data, vm:get-presets - disk-budget-step.js: wizard UI step with preset cards + custom slider - Real-time free space check against selected disk size - Plain English description of what each tier handles UPDATED: - caddyfile-generator.js: docker-compose now includes disk safety env vars (health retention, stats caps, memory limits) as defense-in-depth even inside the VM sandbox GUARANTEE: DashCaddy physically cannot exceed the storage budget. The OS enforces the limit at the disk/image level, not our code.
113 lines
3.5 KiB
JavaScript
113 lines
3.5 KiB
JavaScript
/**
|
|
* VM Provisioner IPC Handler
|
|
* Wires the Electron wizard to VMDiskProvisioner.
|
|
* Add to src/main/index.js alongside the existing IPC handlers.
|
|
*/
|
|
|
|
const { ipcMain } = require('electron');
|
|
const { VMDiskProvisioner, DISK_PRESETS } = require('./vm-provisioner');
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
|
|
function registerVMHandlers(mainWindow) {
|
|
const provisioner = new VMDiskProvisioner();
|
|
|
|
// --- Get disk presets for wizard UI ---
|
|
ipcMain.handle('vm:get-presets', async () => {
|
|
return DISK_PRESETS;
|
|
});
|
|
|
|
// --- Get current VM status ---
|
|
ipcMain.handle('vm:get-status', async () => {
|
|
try {
|
|
const status = await provisioner.getStatus();
|
|
// Also check for saved vmInfo from previous install
|
|
try {
|
|
const configPath = path.join(getInstallBase(), '.dashcaddy-config.json');
|
|
const config = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
if (config.vmInfo) {
|
|
status.vmInfo = config.vmInfo;
|
|
status.diskSizeGB = config.vmInfo.diskSizeGB;
|
|
}
|
|
} catch {}
|
|
return status;
|
|
} catch (e) {
|
|
return { platform: process.platform, running: false, error: e.message };
|
|
}
|
|
});
|
|
|
|
// --- Provision the VM sandbox ---
|
|
ipcMain.handle('vm:provision', async (event, opts) => {
|
|
try {
|
|
const result = await provisioner.provision({
|
|
...opts,
|
|
onProgress: (msg, pct) => {
|
|
mainWindow.webContents.send('vm:progress', { message: msg, percent: pct });
|
|
},
|
|
});
|
|
|
|
// Save vmInfo for uninstall
|
|
if (result.vmInfo) {
|
|
try {
|
|
const configPath = path.join(opts.installPath || getInstallBase(), '.dashcaddy-config.json');
|
|
let config = {};
|
|
try { config = JSON.parse(await fs.readFile(configPath, 'utf8')); } catch {}
|
|
config.vmInfo = result.vmInfo;
|
|
config.diskBudgetGB = opts.diskSizeGB;
|
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
} catch {}
|
|
}
|
|
|
|
mainWindow.webContents.send('vm:complete', result);
|
|
return result;
|
|
} catch (error) {
|
|
mainWindow.webContents.send('vm:error', { error: error.message });
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
// --- Destroy the VM sandbox (uninstall) ---
|
|
ipcMain.handle('vm:destroy', async (event, opts) => {
|
|
try {
|
|
// Load saved vmInfo
|
|
let vmInfo = opts.vmInfo;
|
|
if (!vmInfo) {
|
|
try {
|
|
const configPath = path.join(opts.installPath || getInstallBase(), '.dashcaddy-config.json');
|
|
const config = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
vmInfo = config.vmInfo;
|
|
} catch {}
|
|
}
|
|
|
|
if (!vmInfo) {
|
|
return { success: false, error: 'No VM info found. Already uninstalled?' };
|
|
}
|
|
|
|
const result = await provisioner.destroy(vmInfo, {
|
|
exportDataPath: opts.exportDataPath || null,
|
|
});
|
|
|
|
return result;
|
|
} catch (error) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
// --- Export data from VM (before uninstall) ---
|
|
ipcMain.handle('vm:export-data', async (event, opts) => {
|
|
try {
|
|
const result = await provisioner._exportData(opts.vmInfo, opts.exportPath);
|
|
return result;
|
|
} catch (error) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
}
|
|
|
|
function getInstallBase() {
|
|
const { getPlatformInfo } = require('../shared/platform-utils');
|
|
return getPlatformInfo().defaultInstallPath;
|
|
}
|
|
|
|
module.exports = { registerVMHandlers };
|