Skip to content

module parameters stopped working packages/transport-websockets #3332

@ZababurinSergei

Description

@ZababurinSergei
  • Version:

package.json

{
  "name": "test",
  "version": "1.0.0",
  "license": "Apache-2.0 OR MIT",
  "type": "module",
  "scripts": {
    "start": "node server.js",
    "build": "npm run build:pubsub && npm run build:libp2p && npm run build:filter && npm run build:peer-store && npm run build:pubsubPeerDiscovery && npm run build:gossipsub && npm run build:identify",
    "build:pubsub": "esbuild ./src/dep-pubsub.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-pubsub.js",
    "build:libp2p": "esbuild ./src/dep-libp2p.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-libp2p.js",
    "build:filter": "esbuild ./src/dep-filters.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-filters.js",
    "build:peer-store": "esbuild ./src/dep-peer-store.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-peer-store.js",
    "build:gossipsub": "esbuild ./src/dep-gossipsub.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-gossipsub.js",
    "build:pubsubPeerDiscovery": "esbuild ./src/dep-pubsubPeerDiscovery.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-pubsubPeerDiscovery.js",
    "build:identify": "esbuild ./src/dep-identify.js --bundle --sourcemap --format=esm --target=chrome114 --define:global=window --keep-names --outfile=./docs/lib-identify.js",
    "test:firefox": "npm run build && playwright test --browser=firefox test",
    "test:chrome": "npm run build && playwright test test"
  },
  "dependencies": {
    "@chainsafe/libp2p-gossipsub": "^14.1.2",
    "@chainsafe/libp2p-noise": "^17.0.0",
    "@chainsafe/libp2p-yamux": "^8.0.0",
    "@libp2p/autonat": "^3.0.5",
    "@libp2p/bootstrap": "^12.0.6",
    "@libp2p/circuit-relay-v2": "^4.0.5",
    "@libp2p/crypto": "^5.1.12",
    "@libp2p/dcutr": "^3.0.5",
    "@libp2p/identify": "^4.0.5",
    "@libp2p/interface-transport": "^4.0.3",
    "@libp2p/kad-dht": "^16.0.5",
    "@libp2p/peer-id": "^6.0.3",
    "@libp2p/peer-id-factory": "^4.2.4",
    "@libp2p/peer-store": "^12.0.5",
    "@libp2p/ping": "^3.0.5",
    "@libp2p/pubsub-peer-discovery": "^12.0.0",
    "@libp2p/tcp": "^11.0.5",
    "@libp2p/webrtc": "^6.0.6",
    "@libp2p/websockets": "^10.0.6",
    "@libp2p/webtransport": "^6.0.7",
    "@multiformats/multiaddr": "^13.0.1",
    "blockstore-core": "^6.1.1",
    "compression": "^1.8.1",
    "cors": "^2.8.5",
    "datastore-core": "^11.0.2",
    "datastore-idb": "^4.0.1",
    "dotenv": "^17.2.3",
    "express": "^5.1.0",
    "express-enqueue": "^1.0.0",
    "http-proxy": "^1.18.1",
    "libp2p": "^3.0.6",
    "peer-id": "^0.16.0",
    "protons-runtime": "^5.6.0",
    "uint8arrays": "^5.1.0"
  },
  "devDependencies": {
    "esbuild": "^0.25.10",
    "test-ipfs-example": "^1.3.3"
  }
}

  • Platform:

Linux manjaro

  • Subsystem:
    Not work is packages/transport-websockets

Severity:

Low - Medium

Description:

I built a relay server with an HTTP server.

It worked well. To transfer data to the HTTP server, I passed the webSockets({server}) server transport to the transport.

transports: [
webTransport(),
webSockets({server}),
tcp(),
],

I've now updated all the libraries to the latest versions.
When starting the server, I see the error Only WebSocket connections are supported

I looked in the library interface:
https://libp2p.github.io/js-libp2p/interfaces/_libp2p_websockets.WebSocketsInit.html

interface WebSocketsInit {
bufferedAmountPollInterval?: number;
http?: ServerOptions<typeof IncomingMessage, typeof ServerResponse>;
https?: ServerOptions<typeof IncomingMessage, typeof ServerResponse>;
maxBufferedAmount?: number;
signal?: AbortSignal;
}

I thought I needed to pass a new http parameter, but that didn't work.

Steps to reproduce the error:

This is the code that worked. After the update, it started saying "Only WebSocket connections are supported."

import path from 'path';
import process from "node:process";
import cors from 'cors';
import Enqueue from 'express-enqueue';
import compression from 'compression';
import * as dotenv from 'dotenv';
import express from 'express';
import http from 'http'

/* eslint-disable no-console */
import { privateKeyFromRaw, generateKeyPair, privateKeyToProtobuf, privateKeyFromProtobuf } from '@libp2p/crypto/keys'
import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
import {identify, identifyPush} from '@libp2p/identify'
import { webSockets } from '@libp2p/websockets'
import { createLibp2p } from 'libp2p'
import { tcp } from '@libp2p/tcp'
import * as  peerIdLib  from '@libp2p/peer-id'
import * as createEd25519PeerId from '@libp2p/peer-id-factory'
import { webTransport } from '@libp2p/webtransport'
import fs from "node:fs";
import { persistentPeerStore } from '@libp2p/peer-store'
import { MemoryDatastore } from 'datastore-core'
import {ping} from "@libp2p/ping";
import { PUBSUB_PEER_DISCOVERY } from './docs/constants.js'
import { gossipsub } from '@chainsafe/libp2p-gossipsub'

let __dirname = process.cwd();
const buffer = fs.readFileSync(__dirname + '/peerId.proto')
const peerId =  await createEd25519PeerId.createFromProtobuf(buffer)

dotenv.config();

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

let whitelist = []

let app = express();
const server = http.createServer(app);

async function main () {
    app.use(compression());
    app.use(express.json());

    const queue = new Enqueue({
        concurrentWorkers: 4,
        maxSize: 200,
        timeout: 30000
    });

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

    let corsOptions = {
        origin: function (origin, callback) {
            console.log('origin', origin);
            if (whitelist.indexOf(origin) !== -1) {
                callback(null, true);
            } else {
                callback(new Error('Not allowed by CORS'));
            }
        }
    };

    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(`/env.json`, async (req, res) => {
        res.status(200).sendFile(path.join(__dirname, 'env.json'))
    })

    app.get(`/env.mjs`, async (req, res) => {
        res.status(200).sendFile(path.join(__dirname, 'env.mjs'))
    })

    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>org browser relay</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
    <meta
            name="description"
            content="">
    <meta property="og:site_name" content="markdown" />
    <meta property="og:locale" content="ru_RU" />
    <meta property="og:type" content="contract" />
    <meta property="og:title" content="markdown" />
    <meta property="og:description" content="markdown" />
    <meta property="og:image" content="https://i.imgur.com/pSrPUkJ.jpg" />
    <meta property="og:image:width" content="537" />
    <meta property="og:image:height" content="240" />
    <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/xMT9f8YGPWmiKB+PIWee/+Gn3z/hp98/4Wee/+HoH06AAAAAAAAAAAAAAAAAAAAACUl9xgVFfXOExP11BMT9dQUFPXQJib3HgAAAACGn3ymhp98/4affP+Gn3ymAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiKB+EIihf0CIoX9AiKB+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AADg/wAA4MMAAOCBAADggQAA8QEAAOeBAADDwwAAgf8AAIAPAACBDwAAgQ8AAMMPAAD//wAA//8AAA=="
          type="image/png">
    <style>
      .body {
        display: flex;
        flex-direction: column;
        justify-content: center;
        text-align: center;
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
      }
      .body img {
        align-self: center;
      }

      #addr {
        display: flex;
        flex-direction: row;
        gap: 24px;
        justify-content: center;
        align-items: center;
      }

      p {
        background: #AFAFAF;
        padding: 4px;
        border-radius: 2px;
        width: max-content;
      }
    </style>
  </head>
  <body>
  <div class="body">
    <br>
    <img src="./assets/logo.png" alt="org Logo" width="128">
    <h2>Relay</h2>
    <div id="addr">
        You can add this bootstrap list with the address 
        <p
            onclick="(function(self) {
                if ('clipboard' in navigator) {
                    navigator.clipboard.writeText(self.textContent.trim())
                    .then(() => {
                      console.log('Text copied');
                    })
                    .catch((err) => console.error(err.name, err.message));
                } else {
                 
                }
            })(this)"
        >
            ${pathNode}
        </p>
    </div>
    <div class="container">
        <div class="peers">
            <button class="get-peers"> get peers</button>
            <ul>
            
            </ul>
        </div>
    </div>
  </div>
    <script type="module">
     let mount = true;
        let events;
        let timer;
        let createEvents = () => {
       
            if(events){
                events.close();
            }
            // Устанавливаем SSE соединение
            events = new EventSource('/events');
            events.onmessage = (event) => {
                console.log('event: ', JSON.parse(event.data))
           
                // if(mount){
                //     let parsedData = JSON.parse(event.data);
                //     setTasks(parsedData);
                // }
            };
            
  
            events.onerror = (err) => {
                console.log('error', err)
                // timer = setTimeout(() => {
                //     createEvents();
                // }, 1000);
            };
        };
        
        createEvents();
        const peers = document.querySelector('.get-peers')
        peers.addEventListener('click', async () => {
           let data =  await fetch('/peers')
           data = await data.json()
           console.log('peers: ', data)
        })
    </script>
  </body>
</html>
`;
        res.status(200).send(html);
        // res.status(200).sendFile(path.join(__dirname, '/index.html'));
    });


    app.use(queue.getErrorMiddleware());

    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/0.0.0.0/tcp/${port}/ws`
            ],
            announce: [
                `/dns4/localhost/tcp/${port}`,
                `/dns4/localhost/tcp/${port}/ws`
            ]
        }

    const node = await createLibp2p({
        peerId,
        addresses: addresses,
        transports: [
            webTransport(),
            webSockets({ server }),
            tcp(),
        ],
        connectionEncryption: [
            noise()
        ],
        streamMuxers: [yamux()],
        services: {
            identify: identify(),
            identifyPush: identifyPush(),
            pubsub: gossipsub(),
            // autoNat: autoNAT(),
            relay: circuitRelayServer(),
            ping: ping()
        }
    })

    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)
    })

    console.log('pid: ', process.pid);
    console.log('listening on http://localhost:' + port);

    let clients = [];
    let todoState = [];

    app.get('/state', (req, res) => {
        res.json(todoState);
    });

    app.get('/events', (req, res) => {
        const headers = {
            'Content-Type': 'text/event-stream',
            'Access-Control-Allow-Origin': '*',
            'Connection': 'keep-alive',
            'Cache-Control': 'no-cache'
        };

        res.writeHead(200, headers);

        const sendData = `data: ${JSON.stringify({
            peerId: peerId.toString()
        })}\n\n`;

        res.write(sendData);
        res.flush();

        const clientId = genUniqId();

        const newClient = {
            id: clientId,
            res,
        };

        clients.push(newClient);

        console.log(`${clientId} - Connection opened`);

        req.on('close', () => {
            console.log(`${clientId} - Connection closed`);
            clients = clients.filter(client => client.id !== clientId);
        });
    });

    function genUniqId(){
        return Date.now() + '-' + Math.floor(Math.random() * 1000000000);
    }

    function sendToAllUsers() {
        for(let i=0; i<clients.length; i++){
            clients[i].res.write(`data: ${JSON.stringify(todoState)}\n\n`);
            clients[i].res.flush();
        }
    }

    app.get('/clients', (req, res) => {
        res.json(clients.map((client) => client.id));
    });

    app.get('/peers', (req, res) => {
        let peers = []
        for(let item of node.getPeers()) {
            peers.push(item.toString())
        }

        res.json({
            status: true,
            peers: peers,
            dhtMode:  node.services.dht.getMode(),
            MA: node.getMultiaddrs()
        });
    });

    app.post('/add-task', (req, res) => {
        const addedText = req.body.text;
        todoState = [
            { id: genUniqId(), text: addedText, checked: false },
            ...todoState
        ];
        res.json(null);
        sendToAllUsers();
    });

    app.post('/check-task', (req, res) => {
        const id = req.body.id;
        const checked = req.body.checked;

        todoState = todoState.map((item) => {
            if(item.id === id){
                return { ...item, checked };
            }
            else{
                return item;
            }
        });
        res.json(null);
        sendToAllUsers();
    });

    app.post('/del-task', (req, res) => {
        const id = req.body.id;
        todoState = todoState.filter((item) => {
            return item.id !== id;
        });

        res.json(null);
        sendToAllUsers();
    });

}

main()


How to get the express server back?

Metadata

Metadata

Assignees

No one assigned

    Labels

    need/triageNeeds initial labeling and prioritization

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions