Skip to content

Instantly share code, notes, and snippets.

@TheLexoPlexx
Last active June 13, 2023 21:16
Show Gist options
  • Save TheLexoPlexx/6a98a1930cb2647a7e6215ce9c3494c4 to your computer and use it in GitHub Desktop.
Save TheLexoPlexx/6a98a1930cb2647a7e6215ce9c3494c4 to your computer and use it in GitHub Desktop.
socket.io in Nextjs 13.4.3
/*
Contains 3 Files:
- components/socket/socketProvider.tsx (Client-Connection)
- components/socket/webSocketStatus.tsx (Client-Status and useSocket-Example)
- websocket/src/index.ts (Server)
Websocket-Server is done externally because nextjs-API-Routes are simply not made for that except you hate yourself.
"next": "^13.4.3",
"socket.io-client": "^4.6.2",
"express": "^4.18.2",
"socket.io": "^4.6.2"
*/
//components/socket/socketProvider.tsx
"use client"
import { ReactNode, createContext, useContext, useEffect, useMemo, useState } from 'react';
import { Socket, io } from 'socket.io-client';
export enum SocketStatus {
CONNECTED = "connected",
DISCONNECTED = "disconnected",
TIMEOUT = "timeout",
LOADING = "loading"
}
interface SocketContextValue {
socket: Socket;
status: SocketStatus;
}
const newSocket = io("http://localhost:3300/", {
transports: ["websocket"],
autoConnect: false
});
export const SocketContext = createContext<SocketContextValue>({
socket: newSocket,
status: SocketStatus.LOADING,
});
export const SocketProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [socket, setSocket] = useState<Socket>(newSocket);
const [status, setStatus] = useState<SocketStatus>(SocketStatus.LOADING);
const events = useMemo(
() => [
{
event: "connect",
callback: () => {
console.log("connected", newSocket.id);
setStatus(SocketStatus.CONNECTED);
}
},
{
event: "disconnect",
callback: () => {
console.log("disconnected", newSocket.id);
setStatus(SocketStatus.DISCONNECTED);
}
},
{
event: "reconnect",
callback: () => {
console.log("reconnect", newSocket.id);
setStatus(SocketStatus.CONNECTED);
}
},
{
event: "connect_error",
callback: (error: any) => {
console.log("connect_error, retrying in 5...", error.name);
setStatus(SocketStatus.DISCONNECTED);
}
},
{
event: "connect_timeout",
callback: () => {
console.log("connect_timeout");
setStatus(SocketStatus.TIMEOUT);
}
},
],
[]
)
useEffect(() => {
events.forEach((event) => {
// console.log("registering", event.event)
newSocket.on(event.event, (arg) => { event.callback(arg) })
})
newSocket.connect()
setSocket(newSocket);
return () => {
events.forEach((event) => {
// console.log("off", event.event)
newSocket.off(event.event, event.callback)
})
newSocket.disconnect();
};
}, [socket, events]);
return (
<SocketContext.Provider value={{ socket, status }}>
{children}
</SocketContext.Provider>
);
};
export function useSocket() {
const { socket, status } = useContext(SocketContext);
if (!socket) {
throw new Error('useSocket must be used within a SocketProvider');
}
return { socket, status }
}
// ################################################
// components/socket/webSocketStatus.tsx
"use client"
import { useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import { SocketStatus, useSocket } from "./socketProvider";
import { toast } from "react-toastify";
export default function WebSocketStatus() {
let path = usePathname()
let { socket, status } = useSocket()
let [lastStatus, setLastStatus] = useState<SocketStatus>(SocketStatus.LOADING)
useEffect(() => {
if (status == SocketStatus.DISCONNECTED || status == SocketStatus.TIMEOUT) {
if (lastStatus !== SocketStatus.DISCONNECTED || status != SocketStatus.TIMEOUT) {
toast.error("Websocket-Verbindung verloren.")
}
}
if (status === SocketStatus.CONNECTED) {
if (lastStatus === SocketStatus.DISCONNECTED) {
toast.success("Websocket verbunden")
}
socket.emit("path", path)
console.log("status", status)
}
setLastStatus(status)
}, [status, path, lastStatus, socket])
return (
<p>{status}</p>
);
}
// ################################################
// websocket/src/index.tsx
import express from "express"
import http from "http"
import { Server, Socket } from "socket.io"
import { PrismaClient } from "@prisma/client"
function main() {
const app = express()
const server = http.createServer(app)
const io = new Server(server)
const prisma = new PrismaClient()
io.on("connection", (socket: Socket) => {
console.log("connect", socket.id)
socket.onAny(async (event, ...args) => {
if (event == "path") {
console.log("[" + socket.id + "] path: ", args)
} else if (event == "refetch") {
console.log("refetch", args)
io.emit("refetch", args)
} else if (event == "prisma") {
console.log("prisma", args)
} else {
console.log("[" + socket.id + "] unhandled: ", event, args)
}
})
socket.on("disconnect", () => {
console.log("disconnect", socket.id)
})
});
server.listen(3300, () => {
console.log("Server gestartet auf: *:3300");
});
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment