196 lines
6.7 KiB
JavaScript
196 lines
6.7 KiB
JavaScript
(function () {
|
|
const statusEl = document.getElementById('status');
|
|
const topicEl = document.getElementById('topic');
|
|
const btnJoin = document.getElementById('btnJoin');
|
|
const btnLeave = document.getElementById('btnLeave');
|
|
const peersEl = document.getElementById('peers');
|
|
const publicKeyEl = document.getElementById('publicKey');
|
|
const connStatusEl = document.getElementById('connStatus');
|
|
const rawMsgEl = document.getElementById('rawMsg');
|
|
const btnRawSend = document.getElementById('btnRawSend');
|
|
const protoMsgEl = document.getElementById('protoMsg');
|
|
const btnProtoSend = document.getElementById('btnProtoSend');
|
|
const protoStatusEl = document.getElementById('protoStatus');
|
|
const logEl = document.getElementById('log');
|
|
|
|
function setStatus(msg, className) {
|
|
statusEl.textContent = msg;
|
|
statusEl.className = 'status ' + (className || 'ok');
|
|
}
|
|
|
|
function log(msg, type) {
|
|
const line = document.createElement('div');
|
|
line.className = type || 'sys';
|
|
line.textContent = '[' + new Date().toLocaleTimeString() + '] ' + msg;
|
|
logEl.appendChild(line);
|
|
logEl.scrollTop = logEl.scrollHeight;
|
|
}
|
|
|
|
(function initWhenReady(attempts) {
|
|
if (attempts >= 50) {
|
|
setStatus('BridgeSwarm extension not detected. Install it and reload.', 'error');
|
|
return;
|
|
}
|
|
if (typeof window.BridgeSwarm === 'undefined') {
|
|
setStatus('Waiting for extension…', 'warn');
|
|
setTimeout(function () { initWhenReady(attempts + 1); }, 100);
|
|
return;
|
|
}
|
|
window.BridgeSwarm.ready().then(function () {
|
|
setStatus('Ready. Join a topic to start.');
|
|
}).catch(function () {
|
|
setStatus('BridgeSwarm extension not detected.', 'error');
|
|
});
|
|
})(0);
|
|
|
|
let swarm = null;
|
|
const connectionEntries = [];
|
|
|
|
function updatePeers() {
|
|
peersEl.textContent = 'Peers: ' + connectionEntries.length;
|
|
if (connectionEntries.length > 0) connStatusEl.style.display = '';
|
|
}
|
|
|
|
function enableConnected() {
|
|
rawMsgEl.disabled = false;
|
|
btnRawSend.disabled = false;
|
|
protoMsgEl.disabled = false;
|
|
btnProtoSend.disabled = false;
|
|
}
|
|
|
|
function disableConnected() {
|
|
rawMsgEl.disabled = true;
|
|
btnRawSend.disabled = true;
|
|
protoMsgEl.disabled = true;
|
|
btnProtoSend.disabled = true;
|
|
}
|
|
|
|
btnJoin.addEventListener('click', async function () {
|
|
if (typeof window.BridgeSwarm === 'undefined') {
|
|
setStatus('Extension not ready.', 'error');
|
|
return;
|
|
}
|
|
const topic = topicEl.value.trim() || 'sdk-demo';
|
|
if (swarm) return;
|
|
try {
|
|
setStatus('Joining "' + topic + '"…');
|
|
swarm = new window.BridgeSwarm({ appName: 'bridge-swarm-sdk-demo' });
|
|
|
|
swarm.on('connection', function (conn, peerInfo) {
|
|
const keyShort = (peerInfo.publicKey || '').slice(0, 16) + '…';
|
|
log('Connection: peer ' + keyShort + ', topics: ' + (peerInfo.topics ? peerInfo.topics.length : 0), 'peer');
|
|
conn.on('end', function () {
|
|
const i = connectionEntries.findIndex(function (e) { return e.conn === conn; });
|
|
if (i !== -1) connectionEntries.splice(i, 1);
|
|
updatePeers();
|
|
if (connectionEntries.length === 0) disableConnected();
|
|
log('Peer left', 'sys');
|
|
});
|
|
conn.on('error', function (err) { log('Peer error: ' + err.message, 'err'); });
|
|
|
|
conn.on('data', function (data) {
|
|
const text = new TextDecoder().decode(data);
|
|
log('Raw received: ' + text, 'raw');
|
|
});
|
|
|
|
const entry = { conn, peerInfo, mux: null, channel: null };
|
|
connectionEntries.push(entry);
|
|
updatePeers();
|
|
enableConnected();
|
|
|
|
const mux = swarm.createProtomux(conn);
|
|
if (mux && window.BridgeSwarmProtomux) {
|
|
entry.mux = mux;
|
|
const c = window.BridgeSwarmProtomux.c;
|
|
const ch = mux.createChannel({
|
|
protocol: 'sdk-demo/v1',
|
|
onopen: function () { log('Protomux channel opened', 'protomux'); protoStatusEl.style.display = ''; },
|
|
onclose: function () { log('Protomux channel closed', 'protomux'); }
|
|
});
|
|
entry.stringMsg = ch.addMessage({
|
|
encoding: c.string,
|
|
onmessage: function (m) { log('Protomux (string): ' + m, 'protomux'); }
|
|
});
|
|
ch.addMessage({
|
|
encoding: c.binary,
|
|
onmessage: function (buf) {
|
|
const str = new TextDecoder().decode(buf);
|
|
log('Protomux (binary): ' + str, 'protomux');
|
|
}
|
|
});
|
|
ch.open();
|
|
entry.channel = ch;
|
|
} else {
|
|
log('Protomux not available (ensure protomux-bundle.js is loaded)', 'err');
|
|
}
|
|
});
|
|
|
|
await swarm.join(topic);
|
|
const pubKey = await swarm.getPublicKey();
|
|
publicKeyEl.textContent = 'Your public key: ' + pubKey;
|
|
setStatus('Joined "' + topic + '". Connect another tab to try raw and Protomux messages.');
|
|
btnJoin.disabled = true;
|
|
btnLeave.disabled = false;
|
|
log('Joined topic: ' + topic, 'sys');
|
|
} catch (err) {
|
|
setStatus('Error: ' + err.message, 'error');
|
|
log('Error: ' + err.message, 'err');
|
|
}
|
|
});
|
|
|
|
btnLeave.addEventListener('click', async function () {
|
|
if (!swarm) return;
|
|
try {
|
|
const topic = topicEl.value.trim() || 'sdk-demo';
|
|
await swarm.leave(topic);
|
|
await swarm.destroy();
|
|
connectionEntries.length = 0;
|
|
updatePeers();
|
|
disableConnected();
|
|
swarm = null;
|
|
setStatus('Left topic. You can join again.');
|
|
btnJoin.disabled = false;
|
|
btnLeave.disabled = true;
|
|
log('Left topic and destroyed swarm', 'sys');
|
|
} catch (err) {
|
|
log('Error: ' + err.message, 'err');
|
|
}
|
|
});
|
|
|
|
function sendRaw() {
|
|
const text = rawMsgEl.value.trim();
|
|
if (!text || !swarm || connectionEntries.length === 0) return;
|
|
const data = new TextEncoder().encode(text);
|
|
connectionEntries.forEach(function (e) {
|
|
try { e.conn.write(data); } catch (_) {}
|
|
});
|
|
log('Sent raw: ' + text, 'raw');
|
|
rawMsgEl.value = '';
|
|
}
|
|
|
|
function sendProtomux() {
|
|
const text = protoMsgEl.value.trim();
|
|
if (!text || connectionEntries.length === 0) return;
|
|
let sent = 0;
|
|
connectionEntries.forEach(function (e) {
|
|
if (e.stringMsg) {
|
|
try {
|
|
e.stringMsg.send(text);
|
|
sent++;
|
|
} catch (_) {}
|
|
}
|
|
});
|
|
if (sent > 0) {
|
|
log('Sent via Protomux: ' + text, 'protomux');
|
|
protoMsgEl.value = '';
|
|
} else {
|
|
log('No Protomux channel ready', 'err');
|
|
}
|
|
}
|
|
|
|
btnRawSend.addEventListener('click', sendRaw);
|
|
rawMsgEl.addEventListener('keydown', function (e) { if (e.key === 'Enter') sendRaw(); });
|
|
btnProtoSend.addEventListener('click', sendProtomux);
|
|
protoMsgEl.addEventListener('keydown', function (e) { if (e.key === 'Enter') sendProtomux(); });
|
|
})();
|