v0.0.35: WASM create_call_signal, selectable identity, web sections

FC-P3-T2: WASM create_call_signal() export
- Accepts signal_type string (offer/answer/hangup/etc), payload, target
- Returns bincode WireMessage::CallSignal bytes for WS send

FC-P3-T9: Selectable identity display in web
- ETH address shown in code-style block, click to copy
- addSys() gains rawHtml parameter for rich content

FC-P3-T5: Section navigation comments in web.rs
- 5 section markers: State, Crypto, Network, UI, Commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-29 16:00:43 +04:00
parent 0e7277fb20
commit 0b58ddcee5
5 changed files with 74 additions and 16 deletions

View File

@@ -50,7 +50,7 @@ async fn pwa_manifest() -> impl IntoResponse {
async fn service_worker() -> impl IntoResponse {
([(header::CONTENT_TYPE, "application/javascript")], r##"
const CACHE = 'wz-v16';
const CACHE = 'wz-v17';
const SHELL = ['/', '/wasm/warzone_wasm.js', '/wasm/warzone_wasm_bg.wasm', '/icon.svg', '/manifest.json'];
self.addEventListener('install', e => {
@@ -173,6 +173,8 @@ const WEB_HTML: &str = r##"<!DOCTYPE html>
.msg .ts { color: #333; margin-right: 4px; }
.msg .from-self { color: #4ade80; font-weight: bold; }
.msg .from-sys { color: #5e9ca0; font-style: italic; }
.identity-code { user-select: all; cursor: pointer; background: #1a1a3e; padding: 2px 6px; border-radius: 3px; color: #4ade80; font-family: monospace; }
.identity-code:hover { background: #252550; }
.msg .lock { color: #ff6b9d; }
#bottom { display: flex; padding: 6px; gap: 6px; border-top: 1px solid #222; background: #111;
@@ -244,7 +246,9 @@ const $messages = document.getElementById('messages');
const $input = document.getElementById('msg-input');
const $peerInput = document.getElementById('peer-input');
// ── State ──
// ═══════════════════════════════════════════════
// SECTION: State & Config
// ═══════════════════════════════════════════════
let wasmIdentity = null; // WasmIdentity from WASM
let myFingerprint = '';
let myEthAddress = '';
@@ -255,7 +259,7 @@ let pollTimer = null;
let ws = null; // WebSocket connection
let wasmReady = false;
const VERSION = '0.0.34';
const VERSION = '0.0.35';
let DEBUG = true; // toggle with /debug command
// ── Receipt tracking ──
@@ -343,7 +347,9 @@ function handleAddrClick(addr) {
}
}
// ── WASM-based crypto (same as CLI: X25519 + ChaCha20 + Double Ratchet) ──
// ═══════════════════════════════════════════════
// SECTION: Crypto & Identity
// ═══════════════════════════════════════════════
async function initWasm() {
await init('/wasm/warzone_wasm_bg.wasm');
@@ -488,6 +494,10 @@ async function sendEncrypted(peerFP, plaintext) {
return msgId;
}
// ═══════════════════════════════════════════════
// SECTION: Network & WebSocket
// ═══════════════════════════════════════════════
// URL deep links: /message/@alias, /message/0xABC, /group/#ops
function handleDeepLink() {
const path = window.location.pathname;
@@ -739,7 +749,9 @@ try {
}
} catch(e) {}
// ── UI ──
// ═══════════════════════════════════════════════
// SECTION: UI & Message Display
// ═══════════════════════════════════════════════
function ts() {
return new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
@@ -871,10 +883,14 @@ function addMsg(from, text, isSelf, messageId, rawHtml) {
}
}
function addSys(text) {
function addSys(text, rawHtml) {
const d = document.createElement('div');
d.className = 'msg';
d.innerHTML = '<span class="ts">' + ts() + '</span> <span class="from-sys">' + esc(text) + '</span>';
if (rawHtml) {
d.innerHTML = '<span class="ts">' + ts() + '</span> <span class="from-sys">' + text + '</span>';
} else {
d.innerHTML = '<span class="ts">' + ts() + '</span> <span class="from-sys">' + esc(text) + '</span>';
}
$messages.appendChild(d);
$messages.scrollTop = $messages.scrollHeight;
}
@@ -922,7 +938,7 @@ async function enterChat() {
hdrFp.textContent = (myEthAddress ? myEthAddress.slice(0,12) + '...' : myFingerprint.slice(0,19));
hdrFp.title = myFingerprint;
}
addSys('Identity: ' + (myEthAddress || myFingerprint));
addSys('Identity: <code class="identity-code" onclick="navigator.clipboard.writeText(this.textContent)">' + esc(myEthAddress || myFingerprint) + '</code>', true);
addSys('Key registered with server');
addSys('v' + VERSION + ' | DM: paste peer fingerprint or @alias above');
@@ -1074,7 +1090,9 @@ async function sendToGroup(groupName, text) {
addMsg((myEthAddress ? myEthAddress.slice(0,12) + '...' : myFingerprint.slice(0,19)) + ' [' + groupName + ']', text, true, null);
}
// ── Send handler ──
// ═══════════════════════════════════════════════
// SECTION: Command Handlers
// ═══════════════════════════════════════════════
async function doSend() {
const text = $input.value.trim();