UNPKG

peerpigeon

Version:

WebRTC-based peer-to-peer mesh networking library with intelligent routing and signaling server

604 lines (559 loc) โ€ข 33.8 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>PeerPigeon - Complete API Testing Suite</title> <link rel="stylesheet" href="styles.css"> <link rel="icon" type="image/png" sizes="32x32" href="../browser/assets/images/favicon.png"> </head> <body> <div class="container"> <header> <h1>๐Ÿฆ PeerPigeon - Complete API Testing Suite</h1> <p>Comprehensive browser-based tool for testing all PeerPigeon features</p> <div class="peer-info"> <span><strong>Peer ID:</strong> <code id="peer-id">Initializing...</code></span> <span><strong>Status:</strong> <span id="status" class="status disconnected">Disconnected</span></span> </div> </header> <nav class="feature-tabs"> <button class="tab-btn active" data-tab="connection">Connection</button> <button class="tab-btn" data-tab="messaging">Messaging</button> <button class="tab-btn" data-tab="media">Media</button> <button class="tab-btn" data-tab="dht">WebDHT & Storage</button> <button class="tab-btn" data-tab="crypto">Encryption</button> <button class="tab-btn" data-tab="network">Network Info</button> <button class="tab-btn" data-tab="testing">API Testing</button> </nav> <!-- Global Message History - Visible across all tabs --> <section class="global-message-history"> <div class="card"> <h3>๐Ÿ“ฌ Message History</h3> <div class="message-filters"> <select id="message-filter"> <option value="all">All Messages</option> <option value="sent">Sent Messages</option> <option value="received">Received Messages</option> <option value="broadcast">Broadcast Messages</option> <option value="direct">Direct Messages</option> <option value="group">Group Messages</option> </select> <button id="export-messages-btn" class="btn tertiary">๐Ÿ“ฅ Export History</button> </div> <div id="message-history" class="message-history"> <p class="empty-state">No messages yet</p> </div> <div class="button-group"> <button id="clear-messages-btn" class="btn tertiary">Clear History</button> <button id="refresh-messages-btn" class="btn tertiary">Refresh</button> </div> </div> </section> <main> <!-- Connection Management Tab --> <section id="connection-tab" class="tab-content active"> <h2>๐ŸŒ Connection Management</h2> <div class="card"> <h3>๐ŸŒ Network & Signaling Server</h3> <div class="input-group"> <label for="network-name">Network Name:</label> <input type="text" id="network-name" value="global" placeholder="global (e.g., 'gaming', 'work', 'family')"> <small>Create isolated networks or use 'global' for default mesh</small> </div> <div class="input-group"> <label for="signaling-url">Server URL:</label> <input type="text" id="signaling-url" value="ws://localhost:3000" placeholder="ws://localhost:3000"> </div> <div class="checkbox-group"> <label><input type="checkbox" id="allow-global-fallback" checked> Allow Global Fallback</label> <small>Automatically fallback to global network when current network is empty</small> </div> <div class="button-group"> <button id="connect-btn" class="btn primary">Connect</button> <button id="disconnect-btn" class="btn secondary" disabled>Disconnect</button> <button id="cleanup-btn" class="btn tertiary">Cleanup Stale Data</button> </div> <div id="network-status" class="network-status" style="display: none;"> <div class="status-info"> <span><strong>Current Network:</strong> <span id="current-network">global</span></span> <span id="fallback-indicator" style="display: none;" class="fallback-badge">Fallback Mode</span> </div> <div class="status-info" id="original-network-info" style="display: none;"> <span><strong>Original Network:</strong> <span id="original-network"></span></span> </div> </div> </div> <div class="card"> <h3>๐ŸŽฏ Quick Network Switch</h3> <p class="description">Quickly switch between common networks (only when disconnected)</p> <div class="quick-networks"> <button class="btn tertiary network-btn" data-network="global">Global</button> <button class="btn tertiary network-btn" data-network="gaming">Gaming</button> <button class="btn tertiary network-btn" data-network="work">Work</button> <button class="btn tertiary network-btn" data-network="family">Family</button> <button class="btn tertiary network-btn" data-network="test">Test</button> </div> </div> <div class="card"> <h3>Mesh Configuration</h3> <div class="config-grid"> <div class="input-group"> <label for="max-peers">Max Peers:</label> <input type="number" id="max-peers" value="3" min="1" max="10"> </div> <div class="input-group"> <label for="min-peers">Min Peers:</label> <input type="number" id="min-peers" value="2" min="1" max="10"> </div> <div class="checkbox-group"> <label><input type="checkbox" id="auto-connect" checked> Auto Connect</label> <label><input type="checkbox" id="auto-discovery" checked> Auto Discovery</label> <label><input type="checkbox" id="eviction-strategy" checked> Eviction Strategy</label> <label><input type="checkbox" id="xor-routing" checked> XOR Routing</label> </div> <div class="checkbox-group"> <label><input type="checkbox" id="enable-crypto" checked> Enable Crypto</label> <label><input type="checkbox" id="enable-webdht" checked> Enable WebDHT</label> <label><input type="checkbox" id="enable-distributed-storage" checked> Enable Distributed Storage</label> </div> <div class="checkbox-group"> <label><input type="checkbox" id="enable-gossip"> Disable Gossip Protocol</label> <label><input type="checkbox" id="enable-hole-punching"> Disable Hole Punching</label> <label><input type="checkbox" id="enable-backup-connections"> Disable Backup Connections</label> </div> </div> <button id="apply-config-btn" class="btn tertiary">Apply Configuration</button> <button id="get-current-config-btn" class="btn tertiary">Show Current Config</button> </div> <div class="card"> <h3>Connected Peers (<span id="peer-count">0</span>)</h3> <div id="peers-list" class="peers-list"> <p class="empty-state">No peers connected</p> </div> <div class="peer-actions"> <input type="text" id="manual-peer-id" placeholder="Enter peer ID to connect"> <button id="connect-peer-btn" class="btn tertiary">Connect to Peer</button> <button id="force-connect-all-btn" class="btn tertiary">Force Connect All</button> </div> </div> </section> <!-- Messaging Tab --> <section id="messaging-tab" class="tab-content"> <h2>๐Ÿ’ฌ Messaging & Communication</h2> <div class="card"> <h3>๐Ÿ“ข Broadcast Messages</h3> <p class="description">Send messages to all connected peers in the mesh</p> <div class="message-input"> <div class="input-group"> <label for="broadcast-message">Broadcast Message:</label> <textarea id="broadcast-message" placeholder="Enter your broadcast message..." rows="3"></textarea> </div> <div class="message-options"> <label><input type="checkbox" id="encrypt-broadcast" checked> Encrypt Message</label> <label><input type="checkbox" id="high-priority-broadcast"> High Priority</label> </div> <div class="button-group"> <button id="send-broadcast-btn" class="btn primary">๐Ÿ“ข Send Broadcast</button> <button id="send-anonymous-btn" class="btn secondary">๐ŸŽญ Send Anonymous</button> </div> </div> </div> <div class="card"> <h3>๐Ÿ“ง Direct Messages</h3> <p class="description">Send private messages to specific peers</p> <div class="message-input"> <div class="input-group"> <label for="target-peer">Target Peer:</label> <select id="target-peer-select"> <option value="">Select a connected peer...</option> </select> <input type="text" id="target-peer" placeholder="Or enter peer ID manually"> </div> <div class="input-group"> <label for="direct-message">Private Message:</label> <textarea id="direct-message" placeholder="Enter your direct message..." rows="3"></textarea> </div> <div class="message-options"> <label><input type="checkbox" id="encrypt-direct" checked> Encrypt Message</label> <label><input type="checkbox" id="request-receipt"> Request Read Receipt</label> <label><input type="checkbox" id="ephemeral-message"> Ephemeral (Auto-delete)</label> </div> <div class="button-group"> <button id="send-direct-btn" class="btn primary">๐Ÿ“ง Send Direct Message</button> <button id="send-file-btn" class="btn secondary">๐Ÿ“Ž Send File</button> </div> </div> </div> <div class="card"> <h3>๐Ÿ’ฌ Group Chat</h3> <p class="description">Create and manage group conversations</p> <div class="group-controls"> <div class="input-group"> <label for="group-name">Group Name:</label> <input type="text" id="group-name" placeholder="Enter group name"> </div> <div class="input-group"> <label for="group-members">Members (comma-separated peer IDs):</label> <textarea id="group-members" placeholder="peer1,peer2,peer3..." rows="2"></textarea> </div> <div class="button-group"> <button id="create-group-btn" class="btn primary">Create Group</button> <button id="join-group-btn" class="btn secondary">Join Group</button> <button id="leave-group-btn" class="btn tertiary">Leave Group</button> </div> <div class="input-group"> <label for="group-message">Group Message:</label> <textarea id="group-message" placeholder="Enter group message..." rows="3"></textarea> <button id="send-group-btn" class="btn primary">Send to Group</button> </div> </div> </div> </section> <!-- Media Tab --> <section id="media-tab" class="tab-content"> <h2>๐ŸŽฅ Media Management</h2> <div class="card"> <h3>Local Media</h3> <div class="media-controls"> <div class="checkbox-group"> <label><input type="checkbox" id="enable-video"> Enable Video</label> <label><input type="checkbox" id="enable-audio"> Enable Audio</label> </div> <div class="device-selectors"> <div class="input-group"> <label for="camera-select">Camera:</label> <select id="camera-select"> <option value="">Select camera...</option> </select> </div> <div class="input-group"> <label for="microphone-select">Microphone:</label> <select id="microphone-select"> <option value="">Select microphone...</option> </select> </div> </div> <div class="button-group"> <button id="start-media-btn" class="btn primary">Start Media</button> <button id="stop-media-btn" class="btn secondary" disabled>Stop Media</button> <button id="enumerate-devices-btn" class="btn tertiary">Refresh Devices</button> </div> <div class="media-toggle"> <button id="toggle-video-btn" class="btn tertiary" disabled>Toggle Video</button> <button id="toggle-audio-btn" class="btn tertiary" disabled>Toggle Audio</button> </div> </div> <div class="media-preview"> <video id="local-video" autoplay muted playsinline style="display: none;"></video> <div id="media-status" class="media-status">No active media stream</div> </div> </div> <div class="card"> <h3>Remote Streams</h3> <div id="remote-streams" class="remote-streams"> <p class="empty-state">No remote streams</p> </div> </div> <div class="card"> <h3>Media Information</h3> <div id="media-info" class="info-display"> <div>Local Stream: <span id="local-stream-status">None</span></div> <div>Video Enabled: <span id="video-enabled-status">No</span></div> <div>Audio Enabled: <span id="audio-enabled-status">No</span></div> <div>Active Camera: <span id="active-camera">None</span></div> <div>Active Microphone: <span id="active-microphone">None</span></div> </div> </div> </section> <!-- WebDHT & Storage Tab --> <section id="dht-tab" class="tab-content"> <h2>๐Ÿ—„๏ธ WebDHT (Low-Level DHT)</h2> <p class="description">Low-level distributed hash table for raw key-value storage without encryption or access control</p> <div class="card"> <h3>Store Raw Data</h3> <div class="dht-form"> <div class="input-group"> <label for="dht-key">Key:</label> <input type="text" id="dht-key" placeholder="Enter raw storage key"> </div> <div class="input-group"> <label for="dht-value">Value (JSON):</label> <textarea id="dht-value" placeholder='{"example": "data"}' rows="3"></textarea> </div> <div class="input-group"> <label for="dht-ttl">TTL (ms, optional):</label> <input type="number" id="dht-ttl" placeholder="Time to live in milliseconds"> </div> <div class="button-group"> <button id="dht-put-btn" class="btn primary">Store Data</button> <button id="dht-update-btn" class="btn secondary">Update Data</button> </div> </div> </div> <div class="card"> <h3>Retrieve Data</h3> <div class="input-group"> <label for="dht-get-key">Key:</label> <input type="text" id="dht-get-key" placeholder="Enter key to retrieve"> </div> <div class="button-group"> <button id="dht-get-btn" class="btn primary">Get Data</button> <button id="dht-delete-btn" class="btn danger">Delete Key</button> </div> <div id="dht-result" class="result-display"></div> </div> <div class="card"> <h3>Subscriptions</h3> <div class="input-group"> <label for="dht-subscribe-key">Key to Subscribe:</label> <input type="text" id="dht-subscribe-key" placeholder="Enter key to monitor"> </div> <div class="button-group"> <button id="dht-subscribe-btn" class="btn primary">Subscribe</button> <button id="dht-unsubscribe-btn" class="btn secondary">Unsubscribe</button> </div> <div id="dht-subscriptions" class="subscriptions-list"> <p class="empty-state">No active subscriptions</p> </div> </div> <div class="card"> <h3>DHT Activity Log</h3> <div id="dht-log" class="activity-log"> <p class="empty-state">No DHT activity yet</p> </div> <button id="clear-dht-log-btn" class="btn tertiary">Clear Log</button> </div> <div class="card"> <h3>๐Ÿ—ƒ๏ธ Distributed Storage (High-Level)</h3> <p class="description">High-level storage with encryption, access control, and storage spaces - built on top of WebDHT</p> <div class="storage-controls"> <div class="button-group"> <button id="storage-enable-btn" class="btn primary">Enable Storage</button> <button id="storage-disable-btn" class="btn secondary">Disable Storage</button> <button id="storage-status-btn" class="btn tertiary">Get Status</button> </div> <div class="storage-form"> <div class="input-group"> <label for="storage-key">Storage Key:</label> <input type="text" id="storage-key" placeholder="Enter unique storage key"> </div> <div class="input-group"> <label for="storage-data">Data (JSON):</label> <textarea id="storage-data" placeholder='{"persistent": "data"}' rows="3"></textarea> </div> <div class="input-group"> <label for="storage-space">Storage Space:</label> <select id="storage-space"> <option value="private">Private (encrypted, owner-only)</option> <option value="public">Public (unencrypted, readable by all)</option> <option value="frozen">Frozen (immutable, readable by all)</option> </select> </div> <div class="button-group"> <button id="storage-put-btn" class="btn primary">Store Data</button> <button id="storage-get-btn" class="btn secondary">Retrieve Data</button> <button id="storage-delete-btn" class="btn danger">Delete Data</button> </div> </div> <div class="storage-management"> <div class="button-group"> <button id="storage-list-btn" class="btn tertiary">List All Keys</button> <button id="storage-stats-btn" class="btn tertiary">Storage Stats</button> <button id="storage-clear-btn" class="btn danger">Clear All Storage</button> </div> </div> </div> <div id="storage-result" class="result-display"></div> <div class="card"> <h4>Storage Activity Log</h4> <div id="storage-log" class="activity-log"> <p class="empty-state">No storage activity yet</p> </div> <button id="clear-storage-log-btn" class="btn tertiary">Clear Storage Log</button> </div> </div> </section> <!-- Encryption Tab --> <section id="crypto-tab" class="tab-content"> <h2>๐Ÿ” Encryption & Security</h2> <div class="card"> <h3>Crypto Status</h3> <div id="crypto-status" class="info-display"> <div>Crypto Enabled: <span id="crypto-enabled-status">Unknown</span></div> <div>Public Key: <span id="public-key-display">Not available</span></div> <div>Key Exchanges: <span id="key-exchanges-count">0</span></div> </div> <div class="button-group"> <button id="refresh-crypto-status-btn" class="btn tertiary">Refresh Status</button> <button id="force-crypto-init-btn" class="btn secondary">Force Crypto Init</button> <button id="exchange-keys-btn" class="btn primary">Exchange Keys</button> </div> </div> <div class="card"> <h3>Encrypted Messaging</h3> <div class="input-group"> <label for="encrypted-message">Message:</label> <textarea id="encrypted-message" placeholder="Enter message to encrypt and broadcast..." rows="3"></textarea> </div> <div class="input-group"> <label for="group-id">Group ID (optional):</label> <input type="text" id="group-id" placeholder="Enter group encryption key ID"> </div> <button id="send-encrypted-btn" class="btn primary">Send Encrypted Broadcast</button> </div> <div class="card"> <h3>Key Exchange</h3> <div class="input-group"> <label for="key-exchange-peer">Peer ID:</label> <input type="text" id="key-exchange-peer" placeholder="Enter peer ID for key exchange"> </div> <button id="exchange-keys-btn" class="btn primary">Exchange Keys</button> </div> <div class="card"> <h3>Manual Key Management</h3> <div class="input-group"> <label for="manual-peer-id">Peer ID:</label> <input type="text" id="manual-peer-id" placeholder="Enter peer ID"> </div> <div class="input-group"> <label for="manual-public-key">Public Key:</label> <textarea id="manual-public-key" placeholder="Enter peer's public key..." rows="3"></textarea> </div> <button id="add-peer-key-btn" class="btn primary">Add Peer Key</button> </div> <div class="card"> <h3>Encryption Activity Log</h3> <div id="crypto-log" class="activity-log"> <p class="empty-state">No encryption activity yet</p> </div> <button id="clear-crypto-log-btn" class="btn tertiary">Clear Log</button> </div> </section> <!-- Network Information Tab --> <section id="network-tab" class="tab-content"> <h2>๐Ÿ“Š Network Information & Monitoring</h2> <div class="card"> <h3>Network Status</h3> <div id="network-status" class="status-grid"> <div class="status-item"> <label>Connected:</label> <span id="network-connected">No</span> </div> <div class="status-item"> <label>Connected Peers:</label> <span id="network-peer-count">0</span> </div> <div class="status-item"> <label>Discovered Peers:</label> <span id="network-discovered-count">0</span> </div> <div class="status-item"> <label>Signaling URL:</label> <span id="network-signaling-url">None</span> </div> <div class="status-item"> <label>Uptime:</label> <span id="network-uptime">0s</span> </div> <div class="status-item"> <label>Can Accept More:</label> <span id="network-can-accept">Unknown</span> </div> </div> <button id="refresh-status-btn" class="btn tertiary">Refresh Status</button> </div> <div class="card"> <h3>Peer State Summary</h3> <div id="peer-state-summary" class="peer-states"> <p class="empty-state">No peer state information available</p> </div> <button id="get-peer-states-btn" class="btn tertiary">Get Peer States</button> </div> <div class="card"> <h3>Connection Monitoring</h3> <div class="button-group"> <button id="start-monitoring-btn" class="btn primary">Start Monitoring</button> <button id="stop-monitoring-btn" class="btn secondary" disabled>Stop Monitoring</button> <button id="debug-connectivity-btn" class="btn tertiary">Debug Connectivity</button> </div> <div id="connection-stats" class="stats-display"> <p class="empty-state">No monitoring data available</p> </div> </div> <div class="card"> <h3>Discovered Peers</h3> <div id="discovered-peers" class="discovered-peers-list"> <p class="empty-state">No peers discovered</p> </div> </div> </section> <!-- API Testing Tab --> <section id="testing-tab" class="tab-content"> <h2>๐Ÿงช API Testing & Utilities</h2> <div class="card"> <h3>Utility Functions</h3> <div class="button-group"> <button id="validate-peer-id-btn" class="btn primary">Validate Peer ID</button> <button id="force-connect-all-api-btn" class="btn secondary">Force Connect All Peers</button> <button id="cleanup-stale-btn" class="btn tertiary">Cleanup Stale Data</button> </div> <div class="input-group"> <label for="test-peer-id">Peer ID to Validate:</label> <input type="text" id="test-peer-id" placeholder="Enter 40-character hex peer ID"> </div> <div id="utility-results" class="result-display"></div> </div> <div class="card"> <h3>Performance Testing</h3> <div class="input-group"> <label for="test-message-count">Number of Messages:</label> <input type="number" id="test-message-count" value="10" min="1" max="100"> </div> <div class="input-group"> <label for="test-message-size">Message Size (chars):</label> <input type="number" id="test-message-size" value="100" min="1" max="10000"> </div> <div class="button-group"> <button id="performance-test-btn" class="btn primary">Run Performance Test</button> <button id="stress-test-btn" class="btn danger">Run Stress Test</button> </div> <div id="performance-results" class="result-display"></div> </div> <div class="card"> <h3>Test Results & Logs</h3> <div id="test-log" class="test-log"> <p class="empty-state">No test results yet</p> </div> <div class="button-group"> <button id="export-logs-btn" class="btn tertiary">Export Logs</button> <button id="clear-test-log-btn" class="btn tertiary">Clear Test Log</button> </div> </div> <div class="card"> <h3>Error Testing</h3> <div class="button-group"> <button id="test-invalid-peer-btn" class="btn danger">Test Invalid Peer Connection</button> <button id="test-malformed-message-btn" class="btn danger">Test Malformed Message</button> <button id="test-dht-limits-btn" class="btn danger">Test DHT Limits</button> </div> <div id="error-test-results" class="result-display"></div> </div> </section> </main> <footer> <div class="system-log"> <h3>System Log</h3> <div id="system-log" class="log-display"> <p class="empty-state">System log will appear here...</p> </div> <button id="clear-log-btn" class="btn tertiary">Clear Log</button> </div> </footer> </div> <!-- Load PeerPigeon library --> <script src="../../dist/peerpigeon-browser.js"></script> <!-- Load our application --> <script src="app.js"></script> </body> </html>