Skip to content

express example not work #132

@ZababurinSergei

Description

@ZababurinSergei

I tried to run the example projects so that I could navigate the paths in the browser.

I couldn't open the responses in the browser.

I created a relay server. Previously, I passed the server to the transport, and the requests were sent. Now, using the http server, I can't open the paths from Express routes in the browser.

How can I change the example in the message so that the HTML path opens in the browser and web socket connections for the relay are processed?

/* eslint-disable no-console */

import {createServer} from 'node:http'
import {http} from '@libp2p/http'
import {pingHTTP} from '@libp2p/http-ping'
import {canHandle} from '@libp2p/http-server/node'
import {createLibp2p} from 'libp2p'
import {HTTP_TEST_PROTOCOL} from './common.js'
import express from 'express'
import process from "node:process";
import path from "path";
import cors from "cors";
import compression from "compression";
import {privateKeyFromProtobuf, privateKeyToProtobuf} from "@libp2p/crypto/keys";
import fs from "node:fs";
import * as dotenv from "dotenv";
import {identify, identifyPush} from "@libp2p/identify";
import {gossipsub} from "@chainsafe/libp2p-gossipsub";
import {circuitRelayServer, circuitRelayTransport} from "@libp2p/circuit-relay-v2";
import {ping} from "@libp2p/ping";
import {nodeServer} from "@libp2p/http-server";
import {kadDHT, removePrivateAddressesMapper, removePublicAddressesMapper} from "@libp2p/kad-dht";
import {webTransport} from "@libp2p/webtransport";
import {webSockets} from "@libp2p/websockets";
import {tcp} from "@libp2p/tcp";
import {noise} from "@chainsafe/libp2p-noise";
import {yamux} from "@chainsafe/libp2p-yamux";
import {PUBSUB_PEER_DISCOVERY} from "./docs/constants.js";
const app = express()

let __dirname = process.cwd();
const RENDER_EXTERNAL_HOSTNAME = process.env.RENDER_EXTERNAL_HOSTNAME ? process.env.RENDER_EXTERNAL_HOSTNAME: 'localhost'
// Путь для сохранения приватного ключа
const PRIVATE_KEY_PATH = path.join(process.cwd(), 'private-key.proto');

const peerId = await getOrCreatePrivateKey();

console.log('RENDER_EXTERNAL_HOSTNAME', RENDER_EXTERNAL_HOSTNAME)


// an HTTP server that listens on a port and receives incoming requests
const server = createServer()

/**
 * Сохраняет приватный ключ на диск
 * @param {Uint8Array} privateKey - Приватный ключ в бинарном формате
 * @returns {Promise<boolean>} - Успешно ли сохранен ключ
 */
async function savePrivateKey(privateKey) {
    try {
        // Конвертируем приватный ключ в protobuf формат
        const privateKeyProto = privateKeyToProtobuf(privateKey);

        // Сохраняем на диск
        fs.writeFileSync(PRIVATE_KEY_PATH, privateKeyProto);
        console.log('Приватный ключ успешно сохранен:', PRIVATE_KEY_PATH);
        return true;
    } catch (error) {
        console.error('Ошибка при сохранении приватного ключа:', error);
        return false;
    }
}

/**
 * Читает приватный ключ с диска
 * @returns {Promise<Uint8Array|null>} - Приватный ключ или null если ошибка
 */
async function readPrivateKey() {
    try {
        // Проверяем существует ли файл
        if (!fs.existsSync(PRIVATE_KEY_PATH)) {
            console.log('Файл приватного ключа не найден:', PRIVATE_KEY_PATH);
            return null;
        }

        // Читаем файл
        const buffer = fs.readFileSync(PRIVATE_KEY_PATH);

        // Конвертируем из protobuf обратно в приватный ключ
        const privateKey = privateKeyFromProtobuf(buffer);
        console.log('Приватный ключ успешно загружен с диска');
        return privateKey;
    } catch (error) {
        console.error('Ошибка при чтении приватного ключа:', error);
        return null;
    }
}

/**
 * Генерирует и сохраняет новый приватный ключ, если его нет
 * @returns {Promise<Uint8Array>} - Существующий или новый приватный ключ
 */
async function getOrCreatePrivateKey() {
    // Пытаемся прочитать существующий ключ
    let privateKey = await readPrivateKey();

    // Если ключа нет, генерируем новый и сохраняем
    if (!privateKey) {
        console.log('Генерация нового приватного ключа...');
        const {generateKeyPair} = await import('@libp2p/crypto/keys');
        privateKey = await generateKeyPair('Ed25519');

        // Сохраняем новый ключ
        await savePrivateKey(privateKey);
    }

    return privateKey;
}

dotenv.config();

const PORT = process.env.PORT
    ? process.env.PORT
    : 4839;

app.use(compression());
app.use(express.json());

app.use(await cors({credentials: true}));

app.use('/pubsub', express.static(path.join(__dirname, '/docs')));
// app.use('/assets', express.static(path.join(__dirname, '/dist/assets')));
app.use('/assets', express.static(path.join(__dirname, '/public')));

app.get(`/`, async (req, res) => {

    const html = `<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Relay Node</title>
    <meta name="description" content="Relay Node Information Dashboard">
    <link rel="shortcut icon" href="data:image/png;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbbv+DGW3/mRlt/5kZbf+ZGq6/hIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGa3/ohkt/7/Zbj//2S3/v9lt/6WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGm5/iRlt/74Zbj//2W4//9luP//Zbf++mi4/i4gIPciGhr24hsb9uwbG/bsGhr24CEh9xoAAAAAAAAAAAAAAABnuP5mZLf+/2W4//9luP//Zbj//2S3/v9muP5yGBj2rhMT9v8TE/b/ExP2/xMT9f8YGPWkAAAAAAAAAAAAAAAAb7z/BGW3/tZluP//Zbj//2W4//9lt/7gJzH3ShMT9f8TE/b/ExP2/xMT9v8TE/b/ExP1/CAg9joAAAAAAAAAAAAAAABmuP5GZLf+6GS3/uhkt/7oZbf+UhgY9YQSEvX/ExP2/xMT9v8TE/b/ExP2/xIS9f8aGvZ8AAAAAD4++gQgIPZ6IiL2hiIi9oYgIPZ8KCj5BAAAAAAtLfgUFBT17BMT9v8TE/b/ExP2/xMT9v8VFfXoLCz4DgAAAAAaGvZqEhL1/xMT9v8TE/b/EhL1/xsb9nIAAAAAAAAAABwc9m4SEvX/ExP2/xMT9v8SEvX/HR32ZAAAAAAnJ/gSFRX16hMT9v8TE/b/ExP2/xMT9v8UFPXuJyf4Fp2xlAKNnqUYLC/mfhYW83ATE/VuFxf1aDc3+gIAAAAAGBj1fhIS9f8TE/b/ExP2/xMT9v8TE/b/ExP1/xkZ9YaGn3yIhZ57/4Wee/+Gn3yKAAAAAAAAAAAAAAAAAAAAACMj9zYTE/X8ExP2/xMT9v8TE/b/ExP2/xMT9f9JUshihZ57+IaffP+Gn3z/hZ579oigfiYAAAAAAAAAAAAAAAAAAAAAGBj1oBIS9f8TE/b/ExP2/xMT1f8YGPWmiKB+PIWee/+Gn3z/hp98/4Wee/+HoH06AAAAAAAAAAAAAAAAAAAAACUl9xgVFfXOExP11BMT9dQUFPXQJib3HgAAAACGn3ymhp98/4affP+Gn3ymAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiKB+EIihf0CIoX9AiKB+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AADg/wAA4MMAAOCBAADggQAA8QEAAOeBAADDwwAAgf8AAIAPAACBDwAAgQ8AAMMPAAD//wAA//8AAA==" type="image/png">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
            color: #333;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        .header {
            text-align: center;
            background: rgba(255, 255, 255, 0.95);
            padding: 30px;
            border-radius: 15px;
            margin-bottom: 20px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
        }
        
        .logo {
            width: 80px;
            height: 80px;
            margin-bottom: 15px;
        }
        
        .dashboard {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 20px;
            margin-bottom: 20px;
        }
        
        .card {
            background: rgba(255, 255, 255, 0.95);
            padding: 25px;
            border-radius: 15px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
        }
        
        .card h3 {
            color: #4a5568;
            margin-bottom: 15px;
            border-bottom: 2px solid #e2e8f0;
            padding-bottom: 8px;
        }
        
        .info-grid {
            display: grid;
            gap: 10px;
        }
        
        .info-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 0;
            border-bottom: 1px solid #f1f1f1;
        }
        
        .info-label {
            font-weight: 600;
            color: #4a5568;
            display: flex;
            width: 7dvw;
            

        }
        
        .info-value {
            font-family: 'Courier New', monospace;
            background: #f7fafc;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 0.9em;
            word-break: break-all;
            // max-width: 60%;
            text-align: right;
        }
        
        .copy-btn {
            background: #4299e1;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.8em;
            margin-left: 8px;
            transition: background 0.3s;
            height: fit-content;
            align-self: center;
        }
        
        .copy-btn:hover {
            background: #3182ce;
        }
        
        .copy-btn.copied {
            background: #48bb78;
        }
        
        .status-indicator {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 8px;
        }
        
        .status-online {
            background: #48bb78;
        }
        
        .status-offline {
            background: #f56565;
        }
        
        .peers-list {
            max-height: 300px;
            overflow-y: auto;
        }
        
        .peer-item {
            background: #f7fafc;
            padding: 10px;
            margin: 5px 0;
            border-radius: 6px;
            border-left: 4px solid #4299e1;
            font-family: 'Courier New', monospace;
            font-size: 0.85em;
            word-break: break-all;
        }
        
        .actions {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            margin-bottom: 15px;
        }
        
        .btn {
            background: #4299e1;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.9em;
            transition: all 0.3s;
        }
        
        .btn:hover {
            background: #3182ce;
            transform: translateY(-2px);
        }
        
        .btn-secondary {
            background: #718096;
        }
        
        .btn-secondary:hover {
            background: #4a5568;
        }
        
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-top: 15px;
        }
        
        .stat-item {
            text-align: center;
            padding: 15px;
            background: #f7fafc;
            border-radius: 8px;
        }
        
        .stat-value {
            font-size: 1.5em;
            font-weight: bold;
            color: #4299e1;
        }
        
        .stat-label {
            font-size: 0.8em;
            color: #718096;
            margin-top: 5px;
        }
        
        .refresh-info {
            text-align: center;
            color: #718096;
            font-size: 0.8em;
            margin-top: 10px;
        }
        
        .full-width {
            grid-column: 1 / -1;
              margin-bottom: 20px;
    }
        
        @media (max-width: 768px) {
            .dashboard {
                grid-template-columns: 1fr;
            }
            
            .stats-grid {
                grid-template-columns: repeat(2, 1fr);
            }
            
            .info-item {
                flex-direction: column;
                align-items: flex-start;
                gap: 5px;
            }
            
            .info-value {
                max-width: 100%;
                text-align: left;
            }
        }
        
        .container_peer_id {
            display: flex;
            width: 100%;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <img src="./assets/logo.png" alt="Logo" class="logo">
            <h1>Relay Node</h1>
            <p>Real-time information and monitoring dashboard</p>
        </div>
        
        <div class="dashboard">
            <div class="card">
                <h3>🆔 Node Identity</h3>
                <div class="info-grid">
                    <div class="info-item">
                        <span class="info-label">Peer ID:</span>
                        <div class="container_peer_id">
                            <span class="info-value" id="peerId">${node.peerId.publicKey.toString()}</span>
                            <button class="copy-btn" onclick="copyToClipboard('peerId')">Copy</button>
                        </div>
                    </div>
                    <div class="info-item">
                        <span class="info-label">Node Status:</span>
                        <span class="info-value">
                            <span class="status-indicator status-online"></span>
                            <span id="nodeStatus">Online</span>
                        </span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">Process ID:</span>
                        <span class="info-value" id="processId">${process.pid}</span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">Port:</span>
                        <span class="info-value" id="nodePort">${PORT}</span>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <h3>🌐 Network Addresses</h3>
                <div class="info-grid" id="addressesList">
                    ${node.getMultiaddrs().map((addr, index) =>
        `<div class="info-item">
                            <span class="info-label">Address ${index + 1}:</span>
                            <span class="info-value address-item">${addr.toString()}</span>
                        </div>`
    ).join('')}
                </div>
            </div>
            
            <div class="card">
                <h3>📊 Node Statistics</h3>
                <div class="stats-grid">
                    <div class="stat-item">
                        <div class="stat-value" id="peersCount">${node.getPeers().length}</div>
                        <div class="stat-label">Connected Peers</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-value" id="clientsCount">0</div>
                        <div class="stat-label">SSE Clients</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-value" id="dhtMode">${node.services.lanDHT?.getMode() || 'Unknown'}</div>
                        <div class="stat-label">DHT Mode</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-value" id="uptime">0s</div>
                        <div class="stat-label">Uptime</div>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <h3>🔧 Services & Protocols</h3>
                <div class="info-grid">
                    <div class="info-item">
                        <span class="info-label">DHT (LAN):</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">DHT (Amino):</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">Circuit Relay:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">PubSub:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">AutoNAT:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">Identify:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <h3>🔄 Transports</h3>
                <div class="info-grid">
                    <div class="info-item">
                        <span class="info-label">WebTransport:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">WebSockets:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">TCP:</span>
                        <span class="status-indicator status-online"></span>
                    </div>
                </div>
            </div>
            
             <div class="card">
            <h3>📝 Node Information</h3>
            <div class="info-grid">
                <div class="info-item">
                    <span class="info-label">Start Time:</span>
                    <span class="info-value" id="startTime">${new Date().toLocaleString()}</span>
                </div>
                <div class="info-item">
                    <span class="info-label">Environment:</span>
                    <span class="info-value">${process.env.NODE_ENV || 'development'}</span>
                </div>
                <div class="info-item">
                    <span class="info-label">Version:</span>
                    <span class="info-value" id="libp2pVersion">Loading...</span>
                </div>
            </div>
        </div>
        </div>
        
        <div class="card full-width">
            <h3>👥 Connected Peers</h3>
            <div class="actions">
                <button class="btn" onclick="refreshPeers()">🔄 Refresh Peers</button>
                <button class="btn btn-secondary" onclick="copyAllAddresses()">📋 Copy All Addresses</button>
                <button class="btn" onclick="exportNodeInfo()">💾 Export Node Info</button>
            </div>
            <div class="peers-list" id="peersList">
                ${node.getPeers().length > 0
        ? node.getPeers().map(peer =>
            `<div class="peer-item">${peer.toString()}</div>`
        ).join('')
        : '<div class="refresh-info">No peers connected</div>'
    }
            </div>
        </div>
        
        <div class="card">
            <h3>📡 Bootstrap Address</h3>
            <div class="info-item">
                <span class="info-label">Primary Address:</span>
                <div>
                    <span class="info-value" id="primaryAddress">${pathNode}</span>
                    <button class="copy-btn" onclick="copyToClipboard('primaryAddress')">Copy</button>
                </div>
            </div>
            <div class="refresh-info">Use this address to connect other nodes to this relay</div>
        </div>
    </div>

    <script>
        let nodeData = {};
        let startTime = Date.now();
        
        // Utility functions
        function copyToClipboard(elementId) {
            const element = document.getElementById(elementId);
            const text = element.textContent || element.innerText;
            navigator.clipboard.writeText(text).then(() => {
                
                // const btn = event.target;
                // const originalText = btn.textContent;
                // btn.textContent = '✓ Copied!';
                // btn.classList.add('copied');
                
                // setTimeout(() => {
                    // btn.textContent = originalText;
                    // btn.classList.remove('copied');
                // }, 2000);
            }).catch(err => {
                console.error('Failed to copy: ', err);
                alert('Failed to copy to clipboard');
            });
        }
        
        function copyAllAddresses() {
            const addresses = Array.from(document.querySelectorAll('.address-item'))
                .map(item => item.textContent)
                .join('\\n');
            
            if (addresses) {
                navigator.clipboard.writeText(addresses).then(() => {
                    showNotification('All addresses copied to clipboard!');
                });
            }
        }
        
        function exportNodeInfo() {
            const nodeInfo = {
                peerId: document.getElementById('peerId').textContent,
                addresses: Array.from(document.querySelectorAll('.address-item')).map(item => item.textContent),
                peers: Array.from(document.querySelectorAll('.peer-item')).map(item => item.textContent),
                statistics: {
                    peersCount: document.getElementById('peersCount').textContent,
                    clientsCount: document.getElementById('clientsCount').textContent,
                    dhtMode: document.getElementById('dhtMode').textContent,
                    uptime: document.getElementById('uptime').textContent
                },
                exportTime: new Date().toISOString()
            };
            
            const dataStr = JSON.stringify(nodeInfo, null, 2);
            const dataBlob = new Blob([dataStr], {type: 'application/json'});
            
            const url = URL.createObjectURL(dataBlob);
            const link = document.createElement('a');
            link.href = url;
            link.download = \`node-info-\${new Date().toISOString().split('T')[0]}.json\`;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
            
            showNotification('Node information exported!');
        }
        
        function showNotification(message) {
            // Create notification element
            const notification = document.createElement('div');
            notification.style.cssText = \`
                position: fixed;
                top: 20px;
                right: 20px;
                background: #48bb78;
                color: white;
                padding: 12px 20px;
                border-radius: 6px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 1000;
                font-size: 0.9em;
            \`;
            notification.textContent = message;
            
            document.body.appendChild(notification);
            
            setTimeout(() => {
                notification.remove();
            }, 3000);
        }
        
        function formatUptime() {
            const seconds = Math.floor((Date.now() - startTime) / 1000);
            const days = Math.floor(seconds / 86400);
            const hours = Math.floor((seconds % 86400) / 3600);
            const minutes = Math.floor((seconds % 3600) / 60);
            const secs = seconds % 60;
            
            if (days > 0) return \`\${days}d \${hours}h \${minutes}m\`;
            if (hours > 0) return \`\${hours}h \${minutes}m \${secs}s\`;
            if (minutes > 0) return \`\${minutes}m \${secs}s\`;
            return \`\${secs}s\`;
        }
        
        // Data fetching functions
        async function refreshPeers() {
            try {
                const response = await fetch('/peers');
                const data = await response.json();
                nodeData = data;
                updateDashboard();
                showNotification('Peers list updated');
            } catch (error) {
                console.error('Error fetching peers:', error);
                showNotification('Error updating peers list');
            }
        }
        
        async function refreshClients() {
            try {
                const response = await fetch('/clients');
                const clients = await response.json();
                document.getElementById('clientsCount').textContent = clients.length;
            } catch (error) {
                console.error('Error fetching clients:', error);
            }
        }
        
        function updateDashboard() {
            // Update peers count and list
            if (nodeData.peers) {
                document.getElementById('peersCount').textContent = nodeData.peers.length;
                
                const peersList = document.getElementById('peersList');
                if (nodeData.peers.length > 0) {
                    peersList.innerHTML = nodeData.peers.map(peer => 
                        \`<div class="peer-item">\${peer}</div>\`
                    ).join('');
                } else {
                    peersList.innerHTML = '<div class="refresh-info">No peers connected</div>';
                }
            }
            
            // Update DHT mode
            if (nodeData.dhtMode) {
                document.getElementById('dhtMode').textContent = nodeData.dhtMode;
            }
        }
        
        // SSE connection for real-time updates
        function setupEventSource() {
            const events = new EventSource('/events');
            
            events.onmessage = (event) => {
                const data = JSON.parse(event.data);
                // Peer ID уже установлен на сервере, но обновляем если приходит новый
                if (data.peerId && data.peerId !== document.getElementById('peerId').textContent) {
                // console.log('ddddddddddddd', data.peerId.publicKey.toString())
                //     document.getElementById('peerId').textContent = data.peerId.publicKey.toString();
                }
            };
            
            events.onerror = (err) => {
                console.log('SSE connection error:', err);
                document.getElementById('nodeStatus').textContent = 'Connection Issues';
                document.querySelector('#nodeStatus').previousElementSibling.className = 'status-indicator status-offline';
                
                // Attempt reconnect after 5 seconds
                setTimeout(setupEventSource, 5000);
            };
        }
        
        // Initialize dashboard
        document.addEventListener('DOMContentLoaded', function() {
            setupEventSource();
            refreshClients();
            
            // Set libp2p version (this would need to be passed from server)
            document.getElementById('libp2pVersion').textContent = '3.0.6';
            
            // Update uptime every second
            setInterval(() => {
                document.getElementById('uptime').textContent = formatUptime();
            }, 1000);
            
            // Refresh data every 30 seconds
            setInterval(() => {
                refreshPeers();
                refreshClients();
            }, 30000);
        });
    </script>
</body>
</html>`;

    res.status(200).send(html);
})


let addresses = process.env.PORT
    ? {
        listen: [
            `/ip4/0.0.0.0/tcp/${PORT}/wss`
        ],
        announce: [
            `/dns4/${process.env.RENDER_EXTERNAL_HOSTNAME}`,
            `/dns4/${process.env.RENDER_EXTERNAL_HOSTNAME}/wss`
        ]
    }
    : {
        listen: [
            `/ip4/127.0.0.1/tcp/${PORT}/ws`
        ],
        announce: [
            `/dns4/127.0.0.1/tcp/${PORT}`,
            `/dns4/127.0.0.1/tcp/${PORT}/ws`
        ]
    }

// create a libp2p node with a HTTP service that can serve arbitrary HTTP
// protocols and a HTTP ping handler that implements the HTTP ping protocol
const node = await createLibp2p({
    privateKey: peerId,
    addresses: addresses,
    transports: [
        circuitRelayTransport(),
        webTransport(),
        webSockets(),
        tcp(),
    ],
    connectionEncryption: [
        noise()
    ],
    streamMuxers: [yamux()],
    services: {
        identify: identify(),
        identifyPush: identifyPush(),
        relay: circuitRelayServer,
        http: http({
            server: nodeServer(server)
        }),
        pingHTTP: pingHTTP(),
        pubsub: gossipsub(),
        // autoNAT: autoNATv2(),
    }
})


node.services.pubsub.subscribe(PUBSUB_PEER_DISCOVERY)
// console.log(`Node started with id ${node.peerId.toString()}`)
let pathNode = ''

node.getMultiaddrs().forEach((ma, index) => {
    pathNode = ma.toString()
    console.log(`${index}::Listening on:`, pathNode)
})

// register a handler function for the passed protocol - it will be served at
// the protocol id path by default
node.services.http.handle(HTTP_TEST_PROTOCOL, {
    handler: (req) => {
        return new Response('Hello World!')
    }
})

// this handler will return `true` if the request was handled by the libp2p
// node, otherwise it should be passed to an application server like express
// or otherwise handled
const handled = canHandle(node)

server.on('request', (req, res) => {
    const isLibp2p = handled(req, res)
    if (isLibp2p) {
        return
    }
    app(req, res)
})

// server.listen(PORT, () => {
//     console.info('Server listening on:')
//     console.info(`http://127.0.0.1:${server.address().port}`)
// })

Browser
http://127.0.0.1:4839/

Only WebSocket connections are supported

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions