Add Rust core wasm preload (#1404)

This commit is contained in:
Leendert de Borst
2025-12-23 13:01:13 +01:00
parent abbb2e5858
commit 6e32c7e2da
3 changed files with 51 additions and 8 deletions

View File

@@ -65,12 +65,16 @@ public class RustCoreService : IAsyncDisposable
/// <summary>
/// Wait for the Rust WASM module to become available with retries.
/// Uses exponential backoff for more robust loading in slow environments (e.g., E2E tests, mobile devices).
/// Default timeout is ~30 seconds to handle slow network conditions.
/// </summary>
/// <param name="maxRetries">Maximum number of retry attempts.</param>
/// <param name="delayMs">Delay between retries in milliseconds.</param>
/// <param name="initialDelayMs">Initial delay between retries in milliseconds.</param>
/// <returns>True if the WASM module became available.</returns>
public async Task<bool> WaitForAvailabilityAsync(int maxRetries = 10, int delayMs = 100)
public async Task<bool> WaitForAvailabilityAsync(int maxRetries = 30, int initialDelayMs = 100)
{
var currentDelay = initialDelayMs;
for (int i = 0; i < maxRetries; i++)
{
if (await IsAvailableAsync())
@@ -78,7 +82,10 @@ public class RustCoreService : IAsyncDisposable
return true;
}
await Task.Delay(delayMs);
await Task.Delay(currentDelay);
// Exponential backoff with cap at 2 seconds
currentDelay = Math.Min(currentDelay * 2, 2000);
}
return false;

View File

@@ -31,6 +31,9 @@
<link rel="manifest" href="manifest.json" />
<link rel="apple-touch-icon" sizes="500x500" href="img/icon-500.png" />
<link rel="apple-touch-icon" sizes="192x192" href="img/icon-192.png" />
<!-- Preload Rust WASM module for faster initialization -->
<link rel="preload" href="/wasm/aliasvault_core_bg.wasm" as="fetch" type="application/wasm" crossorigin />
<link rel="modulepreload" href="/wasm/aliasvault_core.js" />
</head>
<body class="bg-gray-100 dark:bg-gray-900" av-disable="true">
@@ -335,6 +338,13 @@
<script src="js/crypto.js?v=@CacheBuster" async></script>
<script src="js/utilities.js?v=@CacheBuster" async></script>
<script src="js/rustCoreInterop.js?v=@CacheBuster"></script>
<script>
// Start WASM initialization early (non-blocking)
if (typeof window.rustCoreIsAvailable === 'function') {
window.rustCoreIsAvailable().catch(() => {});
}
</script>
<script src="_framework/blazor.webassembly.js?v=@CacheBuster" async></script>
<script src="lib/qrcode.min.js?v=@CacheBuster" defer></script>
<script>

View File

@@ -6,6 +6,34 @@ let wasmModule = null;
let isInitialized = false;
let initPromise = null;
/**
* Fetch with retry for more robust WASM loading.
* @param {string} url - URL to fetch.
* @param {number} maxRetries - Maximum retry attempts.
* @param {number} baseDelay - Base delay in ms for exponential backoff.
* @returns {Promise<Response>} The fetch response.
*/
async function fetchWithRetry(url, maxRetries = 3, baseDelay = 100) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url);
if (response.ok) {
return response;
}
lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);
} catch (error) {
lastError = error;
}
if (i < maxRetries - 1) {
const delay = baseDelay * Math.pow(2, i);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
/**
* Initialize the Rust WASM module.
* @returns {Promise<boolean>} True if initialization succeeded.
@@ -15,17 +43,15 @@ async function initRustCore() {
return true;
}
// If we have a pending promise, wait for it
if (initPromise) {
return initPromise;
}
initPromise = (async () => {
try {
// Fetch the WASM binary first
const wasmResponse = await fetch('/wasm/aliasvault_core_bg.wasm');
if (!wasmResponse.ok) {
throw new Error(`Failed to fetch WASM: ${wasmResponse.status}`);
}
// Fetch the WASM binary with retry
const wasmResponse = await fetchWithRetry('/wasm/aliasvault_core_bg.wasm');
const wasmBytes = await wasmResponse.arrayBuffer();
// Dynamically import the ES module