Websockets & Connection Upgrade on Next server

So i've been trying to bind a websocket connection from client to server on next, and i've done my usual server flow for this kind of shit:
import { NextApiRequest, NextApiResponse } from "next";
import { WebSocketServer } from 'ws';
import { getServerAuthSession } from "../../server/common/get-server-auth-session";
import socketHandler from "../../server/socket";

const socketBinder = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getServerAuthSession({ req, res });

if (session) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (res.socket.server.wss) {
console.log('Socket is already running')
} else {
console.log('Socket is initializing')
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const wss = new WebSocketServer({ server: res.socket.server })
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
res.socket.server.wss = wss
socketHandler(wss);
}
res.end()
} else res.end("Fuck off.");
}

export default socketBinder;
import { NextApiRequest, NextApiResponse } from "next";
import { WebSocketServer } from 'ws';
import { getServerAuthSession } from "../../server/common/get-server-auth-session";
import socketHandler from "../../server/socket";

const socketBinder = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getServerAuthSession({ req, res });

if (session) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (res.socket.server.wss) {
console.log('Socket is already running')
} else {
console.log('Socket is initializing')
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const wss = new WebSocketServer({ server: res.socket.server })
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
res.socket.server.wss = wss
socketHandler(wss);
}
res.end()
} else res.end("Fuck off.");
}

export default socketBinder;
and connected to it like so, with a context:
import { createContext, useContext, useMemo, useEffect, ReactNode } from 'react';

type WSProviderProps = { children: ReactNode; url: string };

const WSStateContext = createContext<WebSocket | null>(null);

function WSProvider({ children, url }: WSProviderProps): JSX.Element {
const wsInstance = useMemo(
() => (typeof window != 'undefined' ? new WebSocket(`ws${window.location.protocol === 'https:' ? 's' : ''}://${window.location.host}${url}`) : null),
[]
);

// useEffect(() => {
// return () => {
// wsInstance?.close();
// };
// }, []);

return <WSStateContext.Provider value={wsInstance}>{children}</WSStateContext.Provider>;
}

function useWS(): WebSocket {
const context = useContext(WSStateContext);

if (!context) {
throw new Error('useWS must be used within a WSProvider');
}

return context;
}

// elsewhere, in a page:

import { NextPage } from "next";
import Head from "next/head";
import { FC, useEffect } from "react";
import { WSProvider, useWS } from "../utils/ws";

const ChatView: FC = () => {
let ws: WebSocket;

if (typeof window !== 'undefined') ws = useWS();

useEffect(() => {
ws.onopen = (e: Event) => console.log(e);
})

return (
<>
{/* shit */}
</>
);
};

const ChatPage: NextPage = () => {
return (
<WSProvider url="/api/socket">
<Head>
<title>Iridium Chat</title>
</Head>

<main className="h-screen w-screen bg-gray-50 dark:bg-slate-900">
<ChatView />
</main>
</WSProvider>
);
}

export default ChatPage;
import { createContext, useContext, useMemo, useEffect, ReactNode } from 'react';

type WSProviderProps = { children: ReactNode; url: string };

const WSStateContext = createContext<WebSocket | null>(null);

function WSProvider({ children, url }: WSProviderProps): JSX.Element {
const wsInstance = useMemo(
() => (typeof window != 'undefined' ? new WebSocket(`ws${window.location.protocol === 'https:' ? 's' : ''}://${window.location.host}${url}`) : null),
[]
);

// useEffect(() => {
// return () => {
// wsInstance?.close();
// };
// }, []);

return <WSStateContext.Provider value={wsInstance}>{children}</WSStateContext.Provider>;
}

function useWS(): WebSocket {
const context = useContext(WSStateContext);

if (!context) {
throw new Error('useWS must be used within a WSProvider');
}

return context;
}

// elsewhere, in a page:

import { NextPage } from "next";
import Head from "next/head";
import { FC, useEffect } from "react";
import { WSProvider, useWS } from "../utils/ws";

const ChatView: FC = () => {
let ws: WebSocket;

if (typeof window !== 'undefined') ws = useWS();

useEffect(() => {
ws.onopen = (e: Event) => console.log(e);
})

return (
<>
{/* shit */}
</>
);
};

const ChatPage: NextPage = () => {
return (
<WSProvider url="/api/socket">
<Head>
<title>Iridium Chat</title>
</Head>

<main className="h-screen w-screen bg-gray-50 dark:bg-slate-900">
<ChatView />
</main>
</WSProvider>
);
}

export default ChatPage;
This only results in a pending handshake or a client error where it says i'm not in a context (the latter of which only happens when i leave out the useEffect and undefined check on the client) https://i-work-at-the.cocaine.institute/Lizzy6373b0daKzIbzcbyX5xU.png I've done the same deal with socket.io before with no problem and this seems to be the recommended way of doing this according to the google wtf is going on lol
4 Replies
mey
meyOP3y ago
well, we've got websockets working by themselves but i'd like to be able to broadcast a message to all or some clients via trpc, i.e. when a message is created.
mey
meyOP3y ago
the project is on github if anyone wants to take a look at our current source: https://github.com/SynapseTech/iridium-chat
GitHub
GitHub - SynapseTech/iridium-chat: Iridium Chat helps teams and pro...
Iridium Chat helps teams and professionals connect and do what matters most: get sh*t done. - GitHub - SynapseTech/iridium-chat: Iridium Chat helps teams and professionals connect and do what matte...
mey
meyOP3y ago
for some reason clients is still an empty set even with websocket clients actively connected https://i-work-at-the.cocaine.institute/Lizzy637ce353BtfU4j3x0UhV.png
mey
meyOP3y ago
for more context, in a trpc mutation i'm calling socketState.broadcastMessage() and in this instance the value of this.clients is Set{0} i solved it, weirdly enough by putting the client list on the global object
Want results from more Discord servers?
Add your server