function bufferToHex(buffer) { return [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, '0')).join(''); } class PacketSource { constructor(pyodide) { this.parser = pyodide.runPython(` from bumble.transport.common import PacketParser class ProxiedPacketParser(PacketParser): def feed_data(self, js_data): super().feed_data(bytes(js_data.to_py())) ProxiedPacketParser() `); } set_packet_sink(sink) { this.parser.set_packet_sink(sink); } data_received(data) { console.log(`HCI[controller->host]: ${bufferToHex(data)}`); this.parser.feed_data(data); } } class PacketSink { constructor(writer) { this.writer = writer; } on_packet(packet) { const buffer = packet.toJs({create_proxies : false}); packet.destroy(); console.log(`HCI[host->controller]: ${bufferToHex(buffer)}`); // TODO: create an async queue here instead of blindly calling write without awaiting this.writer(buffer); } } export async function connectWebSocketTransport(pyodide, hciWsUrl) { return new Promise((resolve, reject) => { let resolved = false; let ws = new WebSocket(hciWsUrl); ws.binaryType = "arraybuffer"; ws.onopen = () => { console.log("WebSocket open"); resolve({ packet_source, packet_sink }); resolved = true; } ws.onclose = () => { console.log("WebSocket close"); if (!resolved) { reject(`Failed to connect to ${hciWsUrl}`) } } ws.onmessage = (event) => { packet_source.data_received(event.data); } const packet_source = new PacketSource(pyodide); const packet_sink = new PacketSink((packet) => ws.send(packet)); }) } export async function loadBumble(pyodide, bumblePackage) { // Load the Bumble module await pyodide.loadPackage("micropip"); await pyodide.runPythonAsync(` import micropip await micropip.install("cryptography") await micropip.install("${bumblePackage}") package_list = micropip.list() print(package_list) `) // Mount a filesystem so that we can persist data like the Key Store let mountDir = "/bumble"; pyodide.FS.mkdir(mountDir); pyodide.FS.mount(pyodide.FS.filesystems.IDBFS, { root: "." }, mountDir); // Sync previously persisted filesystem data into memory pyodide.FS.syncfs(true, () => { console.log("FS synced in") }); }