thinkalpha / socket.io-amqp0

socket.io adapter for amqp 0.9.1+ (e.g. RabbitMQ)
10 stars 3 forks source link

this adapter doesn't work with dynamic namespace #7

Open bahmanbs opened 1 year ago

bahmanbs commented 1 year ago

when using dynamic namespaces (using regex), amqp adapter throws an error in line 167 of index.ts

this.publishChannel.assertExchange(this.exchangeName, 'direct', { autoDelete: true, durable: false });

it says can access assertExchange of undfined

After checking the code a bit, I realized that when connecting the client to the socket server with different namespaces, the client tries to communicate with the / namespace and this causes an error. In case I did not intend to connect to the / namespace. The problem was solved by placing the two methods createRoomExchangeAndQueue and createRoomListener inside the try/catch block

bytenik commented 1 year ago

Can you show more reproduction code? I'm not familiar with regex dynamic namespaces, but from a cursory read of the code I don't see a way that creating the publish channel would be dependent on the namespace name.

bahmanbs commented 1 year ago

client side code:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="https://cdn.socket.io/4.5.4/socket.io.min.js" integrity="sha384-/KNQL8Nu5gCHLqwqfQjA689Hhoqgi2S84SNUxC3roTe4EhJ9AfLkp8QiQcU8AMzI" crossorigin="anonymous"></script>
    <script>

        const io_1 = io(`http://localhost:3000/test-123`);

        const io_2 = io(`http://localhost:3000/test-456`);

        io_1.on("connection-established", (namespaceName) => console.log(`you are connected to the ${ namespaceName } namespace`));
        io_2.on("connection-established", (namespaceName) => console.log(`you are connected to the ${ namespaceName } namespace`));

    </script>
</body>

</html>

server side code

const { Server } = require('socket.io');

const io = new Server(3000);

// ----- amqp adapter does not work on dynamic naaspaces -----
const { createAdapter } = require('socket.io-amqp0');
const { connect } = require('amqplib');
io.adapter(createAdapter({ amqpConnection: () => connect('amqp://localhost') }));

// ----- redis adapter works on dynamic namespaces -----
// const { createAdapter } = require("@socket.io/redis-adapter");
// const { createClient } = require("redis");
// const pubClient = createClient({ url: "redis://localhost:6379" });
// const subClient = pubClient.duplicate();
// io.adapter(createAdapter(pubClient, subClient));

/**
 * the namespace here could be dynamic like so.
 * this means client can connect to socket server with a dynamic format 
 * for example:
 *  io("http://localhost:3000/[namespace]")
 *  in our example it could be:
 *  io("http://localhost:3000/test-abc123") OR io("http://localhost:3000/test-xyz789")
 * 
 * THIS IS SUPPORTED BY REDIS ADAPTER AND IT WORKS
 */

io.of(/^\/test-\w+$/).on("connection", (socket) => {
    const namespaceName = socket.nsp.name;
    socket.emit("connection-established", namespaceName);
});

console.log("server is running on port 3000")

just run rabbitmq or redis and uncomment related code to see what happens on successful connection, in console we can see name of namespaces

for more info about dynamic namespaces read this link on socket.io documentation