ruv-swarm
Version:
High-performance neural network swarm orchestration in WebAssembly
436 lines (365 loc) • 14.5 kB
JavaScript
/**
* WASM Bindings Loader
* Properly loads WASM bindings with the correct import structure
*/
import { promises as fs } from 'node:fs';
import path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
// Get current directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Global wasm instance for wasm-bindgen compatibility
let globalWasm;
// Create a proper WASM bindings loader that matches the expected import structure
class WasmBindingsLoader {
constructor() {
this.initialized = false;
this.exports = {};
this.memory = null;
this.wasm = null;
this.heap = new Array(128).fill(undefined);
this.heap_next = this.heap.length;
// Initialize heap with special values
this.heap.push(undefined, null, true, false);
}
async initialize() {
if (this.initialized) return this;
try {
// Paths to WASM files
const wasmJsPath = path.join(__dirname, 'ruv_swarm_wasm.js');
const wasmBinaryPath = path.join(__dirname, 'ruv_swarm_wasm_bg.wasm');
// Check if files exist
try {
await fs.access(wasmJsPath);
await fs.access(wasmBinaryPath);
} catch (error) {
console.warn(`WASM files not found: ${error.message}`);
return this.initializePlaceholder();
}
// Import the wasm-bindgen generated module
const wasmJsUrl = pathToFileURL(wasmJsPath).href;
const wasmModule = await import(wasmJsUrl);
// Read the WASM binary directly
const wasmBinary = await fs.readFile(wasmBinaryPath);
// Initialize using the wasm-bindgen module with the binary data
if (typeof wasmModule.__wbg_init === 'function') {
// Pass the binary data in the expected format to avoid deprecation warning
await wasmModule.__wbg_init({ module_or_path: wasmBinary.buffer });
} else if (typeof wasmModule.default === 'function') {
await wasmModule.default({ module_or_path: wasmBinary.buffer });
} else if (typeof wasmModule.init === 'function') {
await wasmModule.init(wasmBinary.buffer);
} else if (typeof wasmModule.initSync === 'function') {
// Some versions have a sync init
wasmModule.initSync(wasmBinary.buffer);
} else {
// Fallback to manual instantiation
const imports = wasmModule.__wbg_get_imports ? wasmModule.__wbg_get_imports() : this.createImports();
const { instance } = await WebAssembly.instantiate(wasmBinary, imports);
// Call finalize if it exists
if (wasmModule.__wbg_finalize_init) {
wasmModule.__wbg_finalize_init(instance, wasmModule);
}
}
// Copy all exports from the wasm module to this object
for (const key in wasmModule) {
if (key.startsWith('__wbg_')) continue; // Skip internal wasm-bindgen functions
const value = wasmModule[key];
if (typeof value === 'function') {
this[key] = value.bind(wasmModule);
} else if (value !== undefined) {
Object.defineProperty(this, key, {
get: () => wasmModule[key],
configurable: true
});
}
}
// Store reference to the wasm module
this.wasm = wasmModule.wasm || wasmModule;
this.memory = wasmModule.memory || (wasmModule.wasm && wasmModule.wasm.memory);
globalWasm = this.wasm;
this.initialized = true;
console.log('✅ WASM bindings loaded successfully (actual WASM)');
return this;
} catch (error) {
console.error('❌ Failed to initialize WASM bindings:', error);
return this.initializePlaceholder();
}
}
// Create the imports object that the WASM module expects
createImports() {
const imports = {};
imports.wbg = {};
// Helper functions for memory management
const getObject = (idx) => this.heap[idx];
const addHeapObject = (obj) => {
if (this.heap_next === this.heap.length) this.heap.push(this.heap.length + 1);
const idx = this.heap_next;
this.heap_next = this.heap[idx];
this.heap[idx] = obj;
return idx;
};
// Drop an object from the heap
const dropObject = (idx) => {
if (idx < 36) return;
this.heap[idx] = this.heap_next;
this.heap_next = idx;
};
// Take an object from the heap (and drop it)
const takeObject = (idx) => {
const ret = getObject(idx);
dropObject(idx);
return ret;
};
// String handling for WASM
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
let cachedUint8Memory0 = null;
const getUint8Memory0 = () => {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
const wasm = globalWasm || this.wasm;
if (wasm && wasm.memory) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
} else {
cachedUint8Memory0 = new Uint8Array(1024);
}
}
return cachedUint8Memory0;
};
const getStringFromWasm0 = (ptr, len) => {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
};
// Error handling function
const handleError = (f, args) => {
try {
return f.apply(null, args);
} catch (e) {
if (this.wasm && this.wasm.__wbindgen_export_0) {
this.wasm.__wbindgen_export_0(addHeapObject(e));
}
throw e;
}
};
// Check if value is undefined or null
const isLikeNone = (x) => x === undefined || x === null;
// Add all the required import functions
imports.wbg.__wbg_buffer_609cc3eee51ed158 = function(arg0) {
return addHeapObject(getObject(arg0).buffer);
};
imports.wbg.__wbg_call_672a4d21634d4a24 = function() {
return handleError(function (arg0, arg1) {
return addHeapObject(getObject(arg0).call(getObject(arg1)));
}, arguments);
};
imports.wbg.__wbg_error_524f506f44df1645 = function(arg0) {
console.error(getObject(arg0));
};
imports.wbg.__wbg_error_7534b8e9a36f1ab4 = function(arg0, arg1) {
var v0 = getStringFromWasm0(arg0, arg1).slice();
if (this.wasm && this.wasm.__wbindgen_export_1) {
this.wasm.__wbindgen_export_1(arg0, arg1 * 1, 1);
}
console.error(v0);
}.bind(this);
imports.wbg.__wbg_from_2a5d3e218e67aa85 = function(arg0) {
return addHeapObject(Array.from(getObject(arg0)));
};
imports.wbg.__wbg_get_67b2ba62fc30de12 = function() {
return handleError(function(arg0, arg1) {
return addHeapObject(Reflect.get(getObject(arg0), getObject(arg1)));
}, arguments);
};
imports.wbg.__wbg_get_b9b93047fe3cf45b = function(arg0, arg1) {
return addHeapObject(getObject(arg0)[arg1 >>> 0]);
};
imports.wbg.__wbg_instanceof_Error_4d54113b22d20306 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof Error;
} catch {
result = false;
}
return result;
};
imports.wbg.__wbg_instanceof_Window_def73ea0955fc569 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof Window;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_length_e2d2a49132c1b256 = function(arg0) {
return getObject(arg0).length;
};
imports.wbg.__wbg_log_c222819a41e063d3 = function(arg0) {
console.log(getObject(arg0));
};
imports.wbg.__wbg_message_97a2af9b89d693a3 = function(arg0) {
return addHeapObject(getObject(arg0).message);
};
imports.wbg.__wbg_new_780abee5c1739fd7 = function(arg0) {
try {
return addHeapObject(new Function(getObject(arg0)));
} catch (e) {
console.error("Error creating function:", e);
return addHeapObject(() => {});
}
};
imports.wbg.__wbg_new_8a6f238a6ece86ea = function() {
return addHeapObject(new Object());
};
imports.wbg.__wbg_newnoargs_105ed471475aaf50 = function(arg0, arg1) {
try {
const str = getStringFromWasm0(arg0, arg1);
return addHeapObject(new Function(str));
} catch (e) {
console.error("Error creating function:", e);
return addHeapObject(() => {});
}
};
imports.wbg.__wbg_newwithbyteoffsetandlength_e6b7e69acd4c7354 = function(arg0, arg1, arg2) {
return addHeapObject(new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0));
};
imports.wbg.__wbg_now_807e54c39636c349 = function() {
return Date.now();
};
imports.wbg.__wbg_random_3ad904d98382defe = function() {
return Math.random();
};
imports.wbg.__wbg_static_accessor_GLOBAL_88a902d13a557d07 = function() {
return addHeapObject(globalThis);
};
imports.wbg.__wbg_static_accessor_GLOBAL_THIS_56578be7e9f832b0 = function() {
return addHeapObject(globalThis);
};
imports.wbg.__wbg_static_accessor_SELF_37c5d418e4bf5819 = function() {
return addHeapObject(globalThis);
};
imports.wbg.__wbg_static_accessor_WINDOW_5de37043a91a9c40 = function() {
return addHeapObject(globalThis);
};
imports.wbg.__wbg_warn_4ca3906c248c47c4 = function(arg0) {
console.warn(getObject(arg0));
};
imports.wbg.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) {
const ret = getObject(arg1).stack;
const ptr1 = this.wasm && this.wasm.__wbindgen_malloc ? this.wasm.__wbindgen_malloc(ret.length * 1, 1) : 0;
const len1 = ret.length;
if (ptr1 && getUint8Memory0()) {
getUint8Memory0().subarray(ptr1, ptr1 + len1).set(new TextEncoder().encode(ret));
getUint8Memory0()[ptr1 + len1] = 0;
}
const dataView = new DataView(getUint8Memory0().buffer);
dataView.setInt32(arg0 + 4 * 1, len1, true);
dataView.setInt32(arg0 + 4 * 0, ptr1, true);
}.bind(this);
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
const obj = getObject(arg1);
const debugStr = String(obj);
const ptr = this.wasm && this.wasm.__wbindgen_malloc ? this.wasm.__wbindgen_malloc(debugStr.length * 1, 1) : 0;
const len = debugStr.length;
if (ptr && getUint8Memory0()) {
getUint8Memory0().subarray(ptr, ptr + len).set(new TextEncoder().encode(debugStr));
getUint8Memory0()[ptr + len] = 0;
}
const dataView = new DataView(getUint8Memory0().buffer);
dataView.setInt32(arg0 + 4 * 1, len, true);
dataView.setInt32(arg0 + 4 * 0, ptr, true);
}.bind(this);
imports.wbg.__wbindgen_is_undefined = function(arg0) {
return getObject(arg0) === undefined;
};
imports.wbg.__wbindgen_memory = function() {
const wasm = globalWasm || this.wasm;
return addHeapObject(wasm.memory);
}.bind(this);
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
const obj = getObject(arg1);
const val = typeof(obj) === 'number' ? obj : undefined;
if (!isLikeNone(val)) {
getObject(arg0).value = val;
return 1;
}
return 0;
};
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
return addHeapObject(getObject(arg0));
};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
const val = typeof(obj) === 'string' ? obj : undefined;
if (!isLikeNone(val)) {
const ptr = this.wasm && this.wasm.__wbindgen_malloc ? this.wasm.__wbindgen_malloc(val.length * 1, 1) : 0;
const len = val.length;
if (ptr && getUint8Memory0()) {
getUint8Memory0().subarray(ptr, ptr + len).set(new TextEncoder().encode(val));
getUint8Memory0()[ptr + len] = 0;
}
const dataView = new DataView(getUint8Memory0().buffer);
dataView.setInt32(arg0 + 4 * 1, len, true);
dataView.setInt32(arg0 + 4 * 0, ptr, true);
return 1;
}
return 0;
}.bind(this);
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
const ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
return imports;
}
// Initialize placeholder functionality when actual WASM can't be loaded
initializePlaceholder() {
console.warn('⚠️ Using placeholder WASM functionality');
// Create placeholder memory
this.memory = new WebAssembly.Memory({ initial: 1, maximum: 10 });
// Add placeholder functions
this.addNeuralNetworkFunctions();
this.addForecastingFunctions();
this.initialized = true;
return this;
}
// Add neural network specific functions
addNeuralNetworkFunctions() {
this.create_neural_network = (layers, neurons_per_layer) => {
console.log(`Creating neural network with ${layers} layers and ${neurons_per_layer} neurons per layer`);
return 1; // Network ID
};
this.train_network = (network_id, data, epochs) => {
console.log(`Training network ${network_id} for ${epochs} epochs`);
return true;
};
this.forward_pass = (network_id, input) => {
console.log(`Forward pass on network ${network_id}`);
return new Float32Array([0.5, 0.5, 0.5]); // Placeholder output
};
}
// Add forecasting specific functions
addForecastingFunctions() {
this.create_forecasting_model = (type) => {
console.log(`Creating forecasting model of type ${type}`);
return 1; // Model ID
};
this.forecast = (model_id, data, horizon) => {
console.log(`Forecasting with model ${model_id} for horizon ${horizon}`);
return new Float32Array([0.1, 0.2, 0.3]); // Placeholder forecast
};
}
// Get total memory usage
getTotalMemoryUsage() {
if (!this.memory) return 0;
return this.memory.buffer.byteLength;
}
}
// Create singleton instance
const loader = new WasmBindingsLoader();
export default loader;