mirror of
https://github.com/SrIzan10/vdo.ninja.git
synced 2026-05-01 11:05:24 +00:00
312 lines
9.4 KiB
HTML
312 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Simple IFRAME Replacement Example</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
.example {
|
|
border: 2px solid #ddd;
|
|
padding: 20px;
|
|
margin: 20px 0;
|
|
border-radius: 8px;
|
|
}
|
|
.old-way {
|
|
background: #fff3e0;
|
|
}
|
|
.new-way {
|
|
background: #e8f5e9;
|
|
}
|
|
pre {
|
|
background: #f5f5f5;
|
|
padding: 15px;
|
|
border-radius: 4px;
|
|
overflow-x: auto;
|
|
}
|
|
button {
|
|
padding: 10px 20px;
|
|
font-size: 16px;
|
|
margin: 5px;
|
|
cursor: pointer;
|
|
}
|
|
.messages {
|
|
border: 1px solid #ddd;
|
|
padding: 10px;
|
|
height: 200px;
|
|
overflow-y: auto;
|
|
margin: 10px 0;
|
|
background: white;
|
|
}
|
|
h2 {
|
|
margin-top: 0;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Simple IFRAME Replacement with VDO.Ninja DataChannel SDK</h1>
|
|
|
|
<div class="example old-way">
|
|
<h2>❌ Old Way: Hidden IFRAME</h2>
|
|
<pre><code>// HTML
|
|
<iframe id="vdo-iframe"
|
|
src="https://vdo.ninja/?room=myroom&push=sender&view=receiver&datachannel=true"
|
|
style="display:none"></iframe>
|
|
|
|
// JavaScript
|
|
const iframe = document.getElementById('vdo-iframe');
|
|
|
|
// Send message
|
|
iframe.contentWindow.postMessage({
|
|
action: 'send-data',
|
|
data: 'Hello from parent'
|
|
}, '*');
|
|
|
|
// Receive messages
|
|
window.addEventListener('message', (event) => {
|
|
if (event.origin !== 'https://vdo.ninja') return;
|
|
console.log('Received:', event.data);
|
|
});</code></pre>
|
|
|
|
<p><strong>Problems:</strong></p>
|
|
<ul>
|
|
<li>Hidden IFRAME still loads full VDO.Ninja UI</li>
|
|
<li>Cross-origin communication limitations</li>
|
|
<li>No direct control over connections</li>
|
|
<li>Hard to debug</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="example new-way">
|
|
<h2>✅ New Way: DataChannel SDK</h2>
|
|
<pre><code>// JavaScript only - no hidden IFRAME needed!
|
|
const node = new VDONinjaDataChannel();
|
|
|
|
// Connect and join room
|
|
await node.joinRoom({
|
|
room: 'myroom',
|
|
streamID: 'sender',
|
|
label: 'my-device'
|
|
});
|
|
|
|
// Send message
|
|
node.publish({ data: 'Hello from SDK' });
|
|
|
|
// Receive messages
|
|
node.addEventListener('data', (event) => {
|
|
console.log('Received:', event.detail.data);
|
|
});</code></pre>
|
|
|
|
<p><strong>Benefits:</strong></p>
|
|
<ul>
|
|
<li>No hidden IFRAME overhead</li>
|
|
<li>Direct DataChannel control</li>
|
|
<li>Label-based routing</li>
|
|
<li>Mesh networking support</li>
|
|
<li>Better debugging</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="example">
|
|
<h2>🚀 Live Demo</h2>
|
|
<p>Try it out! This demo shows two nodes communicating without any IFRAMEs.</p>
|
|
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
|
<div>
|
|
<h3>Node A</h3>
|
|
<button onclick="connectNodeA()">Connect</button>
|
|
<button onclick="sendFromA()">Send Message</button>
|
|
<div class="messages" id="messagesA"></div>
|
|
</div>
|
|
|
|
<div>
|
|
<h3>Node B</h3>
|
|
<button onclick="connectNodeB()">Connect</button>
|
|
<button onclick="sendFromB()">Send Message</button>
|
|
<div class="messages" id="messagesB"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="example">
|
|
<h2>📝 Common Use Cases</h2>
|
|
|
|
<h3>1. IoT Sensor Network</h3>
|
|
<pre><code>// Sensor publishes data
|
|
const sensor = new VDONinjaDataChannel();
|
|
await sensor.joinRoom({ room: 'iot', label: 'temperature-sensor' });
|
|
|
|
setInterval(() => {
|
|
sensor.publish({
|
|
temp: Math.random() * 30 + 20,
|
|
unit: 'celsius',
|
|
timestamp: Date.now()
|
|
});
|
|
}, 5000);</code></pre>
|
|
|
|
<h3>2. Remote Control</h3>
|
|
<pre><code>// Controller subscribes to specific device
|
|
const controller = new VDONinjaDataChannel();
|
|
await controller.joinRoom({ room: 'iot', label: 'controller' });
|
|
|
|
// Subscribe to all temperature sensors
|
|
controller.subscribe('temperature-sensor');
|
|
|
|
controller.addEventListener('data', (e) => {
|
|
if (e.detail.data.temp > 25) {
|
|
// Send command back
|
|
controller.publish(
|
|
{ command: 'turn-on-fan' },
|
|
{ toLabel: e.detail.label }
|
|
);
|
|
}
|
|
});</code></pre>
|
|
|
|
<h3>3. Multi-User Chat</h3>
|
|
<pre><code>// Each user joins with unique ID but same label
|
|
const chat = new VDONinjaDataChannel();
|
|
await chat.joinRoom({
|
|
room: 'chatroom',
|
|
streamID: `user-${Date.now()}`,
|
|
label: 'chat-user'
|
|
});
|
|
|
|
// Subscribe to all chat users
|
|
chat.subscribe('chat-user');
|
|
|
|
// Send message to all
|
|
chat.publish({
|
|
message: 'Hello everyone!',
|
|
user: 'John'
|
|
});</code></pre>
|
|
</div>
|
|
|
|
<script src="../vdoninja-datachannel-sdk.js"></script>
|
|
<script>
|
|
let nodeA = null;
|
|
let nodeB = null;
|
|
let messageCount = { A: 0, B: 0 };
|
|
|
|
async function connectNodeA() {
|
|
if (nodeA) nodeA.disconnect();
|
|
|
|
nodeA = new VDONinjaDataChannel({
|
|
wss: 'wss://apibackup.vdo.ninja:443'
|
|
});
|
|
|
|
nodeA.addEventListener('data', (e) => {
|
|
addMessage('messagesA', `Received: ${JSON.stringify(e.detail.data)}`);
|
|
});
|
|
|
|
nodeA.addEventListener('peer-connected', (e) => {
|
|
addMessage('messagesA', '🔗 Peer connected!');
|
|
});
|
|
|
|
try {
|
|
await nodeA.joinRoom({
|
|
room: `demo-${window.location.hostname}`,
|
|
streamID: 'node-a',
|
|
label: 'demo-node'
|
|
});
|
|
addMessage('messagesA', '✅ Connected to room');
|
|
|
|
// Auto-discover and connect to peers
|
|
setTimeout(async () => {
|
|
const peers = Array.from(nodeA.peerStreamIDs.keys());
|
|
for (const peer of peers) {
|
|
if (peer !== nodeA.uuid) {
|
|
await nodeA.view(nodeA.peerStreamIDs.get(peer));
|
|
}
|
|
}
|
|
}, 1000);
|
|
} catch (error) {
|
|
addMessage('messagesA', `❌ Error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async function connectNodeB() {
|
|
if (nodeB) nodeB.disconnect();
|
|
|
|
nodeB = new VDONinjaDataChannel({
|
|
wss: 'wss://apibackup.vdo.ninja:443'
|
|
});
|
|
|
|
nodeB.addEventListener('data', (e) => {
|
|
addMessage('messagesB', `Received: ${JSON.stringify(e.detail.data)}`);
|
|
});
|
|
|
|
nodeB.addEventListener('peer-connected', (e) => {
|
|
addMessage('messagesB', '🔗 Peer connected!');
|
|
});
|
|
|
|
try {
|
|
await nodeB.joinRoom({
|
|
room: `demo-${window.location.hostname}`,
|
|
streamID: 'node-b',
|
|
label: 'demo-node'
|
|
});
|
|
addMessage('messagesB', '✅ Connected to room');
|
|
|
|
// Subscribe to demo nodes
|
|
nodeB.subscribe('demo-node');
|
|
|
|
// Auto-connect to node A
|
|
setTimeout(() => {
|
|
nodeB.view('node-a');
|
|
}, 1000);
|
|
} catch (error) {
|
|
addMessage('messagesB', `❌ Error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
function sendFromA() {
|
|
if (!nodeA || !nodeA.connected) {
|
|
alert('Node A not connected!');
|
|
return;
|
|
}
|
|
|
|
messageCount.A++;
|
|
const data = {
|
|
message: `Hello from Node A (#${messageCount.A})`,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
nodeA.publish(data);
|
|
addMessage('messagesA', `Sent: ${JSON.stringify(data)}`);
|
|
}
|
|
|
|
function sendFromB() {
|
|
if (!nodeB || !nodeB.connected) {
|
|
alert('Node B not connected!');
|
|
return;
|
|
}
|
|
|
|
messageCount.B++;
|
|
const data = {
|
|
message: `Hello from Node B (#${messageCount.B})`,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
nodeB.publish(data);
|
|
addMessage('messagesB', `Sent: ${JSON.stringify(data)}`);
|
|
}
|
|
|
|
function addMessage(containerId, message) {
|
|
const container = document.getElementById(containerId);
|
|
const div = document.createElement('div');
|
|
div.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
|
|
container.appendChild(div);
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
|
|
// Cleanup on page unload
|
|
window.addEventListener('beforeunload', () => {
|
|
if (nodeA) nodeA.disconnect();
|
|
if (nodeB) nodeB.disconnect();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |