Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions rynk/rynk-wasm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ <h1>Rynk web demo</h1>
const v = await fn();
const isObj = v !== null && typeof v === "object";
logLine(`✓ ${pad} ${isObj ? JSON.stringify(v) : v}`, isObj);
return v;
} catch (e) {
const kind = (e && e.name) || "Error";
const glyph = kind === "Unsupported" ? "·" : kind === "Rejected" ? "⚠" : "✗";
log(`${glyph} ${pad} ${kind}: ${e && e.message}`);
return null;
}
}

Expand Down Expand Up @@ -253,13 +255,20 @@ <h1>Rynk web demo</h1>
}

// One live session across both transports.
let port = null, device = null, l = null, core = null, client = null, connected = false;
let port = null, device = null, l = null, core = null, client = null, connected = false, topicsStarted = false;

function startTopicPump() {
if (!client || topicsStarted) return;
topicsStarted = true;
log("\n— listening for topics (type on the keyboard); click to disconnect —");
pumpTopics(client);
}

async function teardown() {
// Closing the link EOFs the transport, ending any parked next_event() pump.
if (l) await l.close();
else if (port) { try { await port.close(); } catch {} }
port = null; device = null; l = null; core = null; client = null; connected = false;
port = null; device = null; l = null; core = null; client = null; connected = false; topicsStarted = false;
serialBtn.textContent = "Connect via Serial (USB)";
bleBtn.textContent = "Connect via BLE (WebHID)";
serialBtn.disabled = false; bleBtn.disabled = false;
Expand Down Expand Up @@ -292,7 +301,7 @@ <h1>Rynk web demo</h1>

// Exercise the typed client surface.
await show("version", () => client.get_version());
await show("lock status", () => client.get_lock_status());
const lockStatus = await show("lock status", () => client.get_lock_status());
await show("default layer", () => client.get_default_layer());
await show("current layer", () => client.get_current_layer());
await show("key L0(0,0)", () => client.get_key(0, 0, 0));
Expand All @@ -310,12 +319,16 @@ <h1>Rynk web demo</h1>
// Gated behind the lock: shows "⚠ Rejected: Locked" until unlocked.
await show("matrix state", () => client.get_matrix_state());

unlockBtn.hidden = false; // offer the unlock ceremony while connected
log("\n— listening for topics (type on the keyboard); click to disconnect —");
thisBtn.textContent = "Disconnect";
thisBtn.disabled = false; // re-enable so it can disconnect
otherBtn.disabled = true; // one transport at a time
pumpTopics(client); // pull topics until the link closes
if (lockStatus?.locked && lockStatus.key_positions.length > 0) {
unlockBtn.hidden = false;
log("\n— unlock before starting the topic listener —");
} else {
unlockBtn.hidden = true;
startTopicPump();
}
} catch (e) {
log("ERROR: " + e);
console.error(e);
Expand Down Expand Up @@ -345,7 +358,12 @@ <h1>Rynk web demo</h1>
unlockBtn.disabled = true;
try {
const start = await client.get_lock_status();
if (!start.locked) { log("· already unlocked"); return; }
if (!start.locked) {
log("· already unlocked");
unlockBtn.hidden = true;
startTopicPump();
return;
}
if (start.key_positions.length === 0) {
log("⚠ permanently locked — set [host].unlock_keys in keyboard.toml");
return;
Expand All @@ -354,7 +372,12 @@ <h1>Rynk web demo</h1>
const deadline = Date.now() + 30000;
for (;;) {
const s = await client.unlock_poll();
if (!s.locked) { log("✓ unlocked — retry the gated action"); break; }
if (!s.locked) {
log("✓ unlocked — retry the gated action");
unlockBtn.hidden = true;
startTopicPump();
break;
}
log(` holding… ${s.remaining_keys} key(s) left`);
if (Date.now() > deadline) { log("✗ unlock timed out"); break; }
await new Promise((r) => setTimeout(r, 150));
Expand Down