sam3d / next-plugin-websocket

Add WebSocket support to Next.js API routes
https://www.npmjs.com/package/next-plugin-websocket
58 stars 8 forks source link

Get the WebSocketServer #2

Closed anurag-roy closed 1 year ago

anurag-roy commented 1 year ago

The example provided in the README works perfectly, but it only illustrates how to respond back to the client when it sends something first.

How do I send something from the server to all connected clients or a particular client? Is there an exposed WebSocketServer that I am missing?

Thanks

sam3d commented 1 year ago

Heya! The socket handler you expose in your Next.js API route is directly mapped to the handleUpgrade(req, socket, head) callback from the ws library. There are a couple of methods you could use to implement a broadcast, but the following method is how I'd go about it.

Every time you get a socket connection, store it in a Map or a Set:

import { NextApiHandler } from "next";
import { NextWebSocketHandler } from "next-plugin-websocket";
import { WebSocket } from "ws";

const clients = new Set<WebSocket>();

export const socket: NextWebSocketHandler = (client, req) => {
  // Add the client to the set when it connects
  clients.add(client);

  // Remove the client from the set when it disconnects
  client.on("close", () => {
    console.log("Client disconnected");
    clients.delete(client);
  });
};

// When you call the API route, broadcast to all clients, for example
const handler: NextApiHandler = (req, res) => {
  clients.forEach((client) => client.send("Hello, world!"));
  res.end();
};
export default handler;

You could probably also do the same using a new WebSocketServer({ noServer: true }) instance. I shall update the docs soon with some more examples on how you might go about doing this.

It would also be possible to pass the internal WebSocketServer instance to the socket handler if that was absolutely necessary, but I've decided against that for now as it's responsible for handling all WebSocket connections for the whole server, regardless of whichever API route received the request.

sam3d commented 1 year ago

If you wanted to implement a "send to a specific client" feature (e.g. instant messaging), instead of using a Set, use a Map<string, WebSocket>. The key would need to be some unique client identifier (you can either generate this or you can obtain it from the req, depending on your business logic). Then when you need to send to a particular client, find their socket instance in the Map and send to it.

anurag-roy commented 1 year ago

Thanks for the detailed response!

I was able to achieve what I wanted to do through your example. I was looking for wss.clients, but storing the clients and then sending messages via a loop works as well. Thanks so much!