SocketIO with auth working

This commit is contained in:
aronmal 2023-04-25 22:27:23 +02:00
parent 4af85bb572
commit ba7097207c
Signed by: aronmal
GPG key ID: 816B7707426FC612
6 changed files with 167 additions and 84 deletions

View file

@ -1,37 +1,42 @@
import { ClientToServerEvents, ServerToClientEvents } from "../pages/api/ws"
import { cSocket } from "../interfaces/NextApiSocket"
import useGameState from "@lib/hooks/useGameState"
import { useEffect } from "react"
import { io, Socket } from "socket.io-client"
import { io } from "socket.io-client"
let socket: cSocket
function SocketIO() {
const { session, status } = useGameState()
useEffect(() => {
socketInitializer()
}, [])
const socketInitializer = async () => {
await fetch("/api/ws")
const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io()
socket.on("test2", (warst) => {
console.log("Test2:", warst, socket.id)
if (status === "loading" || socket) return
socket = io({
path: "/api/ws2",
})
socket.on("connect", () => {
console.log(socket.connected) // true
setTimeout(() => {
socket.emit("test", "warst")
socket.emit("test", "tsra")
socket.emit("test", "1234")
// socket.disconnect()
}, 1000)
console.log("connected")
})
socket.on("test", () => {
console.log("Got test1234") // false
socket.on("authenticated", () => {
console.log("Yay!")
})
socket.on("disconnect", () => {
console.log(socket.connected) // false
socket.on("unauthenticated", () => {
console.log("No... pls work")
})
}
return () => {
socket.off("connect")
socket.off("authenticated")
socket.off("unauthenticated")
}
}, [status])
useEffect(() => {
console.log(4, socket)
socket?.emit("authenticate", { token: `hello from ${session?.user.email}` })
}, [session?.user.email, status])
return <div>SocketIO</div>
}

View file

@ -1,7 +1,9 @@
import { User } from "@prisma/client"
import type { Server as HTTPServer } from "http"
import type { Socket as NetSocket } from "net"
import type { NextApiResponse } from "next"
import type { Server as IOServer } from "socket.io"
import type { Server as IOServer, Server } from "socket.io"
import { Socket } from "socket.io-client"
interface SocketServer extends HTTPServer {
io?: IOServer
@ -14,3 +16,38 @@ interface SocketWithIO extends NetSocket {
export interface NextApiResponseWithSocket extends NextApiResponse {
socket: SocketWithIO
}
export interface ServerToClientEvents {
// noArg: () => void
// basicEmit: (a: number, b: string, c: Buffer) => void
// withAck: (d: string, callback: (e: number) => void) => void
"update-input": (msg: string) => void
unauthenticated: () => void
authenticated: () => void
test2: (test: string) => void
test: () => void
}
export interface ClientToServerEvents {
// hello: () => void
"input-change": (msg: string) => void
authenticate: (payload: { token: string }) => void
test: (payload: any) => void
}
interface InterServerEvents {
// ping: () => void
}
interface SocketData {
user: User | null
}
export type cServer = Server<
ClientToServerEvents,
ServerToClientEvents,
InterServerEvents,
SocketData
>
export type cSocket = Socket<ServerToClientEvents, ClientToServerEvents>

View file

@ -0,0 +1,7 @@
import crypto from "crypto"
export function getObjectChecksum(obj: Object) {
const objString = JSON.stringify(obj)
const hash = crypto.createHash("md5").update(objString).digest("hex")
return hash
}

View file

@ -1,58 +1,24 @@
import type { NextApiResponseWithSocket } from "../../interfaces/NextApiSocket"
import prisma from "@lib/prisma"
import type {
NextApiResponseWithSocket,
cServer,
} from "../../interfaces/NextApiSocket"
import type { NextApiRequest } from "next"
import { Server } from "socket.io"
export interface ServerToClientEvents {
// noArg: () => void
// basicEmit: (a: number, b: string, c: Buffer) => void
// withAck: (d: string, callback: (e: number) => void) => void
"update-input": (msg: string) => void
unauthenticated: () => void
authenticated: () => void
test2: (test: string) => void
test: () => void
}
export interface ClientToServerEvents {
// hello: () => void
"input-change": (msg: string) => void
authenticate: (payload: { token: string }) => void
test: (payload: any) => void
}
interface InterServerEvents {
// ping: () => void
}
interface SocketData {
// name: string
// age: number
isAuthenticated: boolean
}
// const authenticate = (socket, next) => {
// socket.isAuthenticated = false
//
// }
const SocketHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
if (res.socket.server.io) {
console.log("Socket is already running " + req.url)
} else {
console.log("Socket is initializing " + req.url)
const io = new Server<
ClientToServerEvents,
ServerToClientEvents,
InterServerEvents,
SocketData
>(res.socket.server)
const io: cServer = new Server(res.socket.server, {
path: "/api/ws",
})
res.socket.server.io = io
// io.use(authenticate)
io.on("connection", (socket) => {
socket.on("input-change", (msg) => {
if (!socket.data.isAuthenticated) socket.emit("unauthenticated")
if (!socket.data.user) socket.emit("unauthenticated")
// socket.broadcast.emit("update-input", msg)
io.emit("update-input", msg)
})

View file

@ -0,0 +1,64 @@
import {
NextApiResponseWithSocket,
cServer,
} from "../../interfaces/NextApiSocket"
import prisma from "@lib/prisma"
import colors from "colors"
import { NextApiRequest } from "next"
import { getSession } from "next-auth/react"
import { Server } from "socket.io"
colors.enable()
const SocketHandler = async (
req: NextApiRequest,
res: NextApiResponseWithSocket
) => {
if (res.socket.server.io) {
console.log("Socket is already running " + req.url)
} else {
console.log("Socket is initializing " + req.url)
const io: cServer = new Server(res.socket.server, { path: "/api/ws2" })
res.socket.server.io = io
// io.use(authenticate)
io.use(async (socket, next) => {
try {
const session = await getSession({
req: socket.request,
})
socket.data.user = await prisma.user.findUnique({
where: {
id: session?.user.id,
},
})
next()
} catch (err) {
console.log("Unauthorized")
next(new Error("Unauthorized"))
}
})
io.on("connection", (socket) => {
console.log(`User connected <${socket.data.user?.email}>`.green)
socket.on("authenticate", (msg) => {
// if (!socket.data.isAuthenticated) socket.emit("unauthenticated")
// socket.broadcast.emit("update-input", msg)
// io.emit("update-input", msg)
console.log(msg)
})
socket.on("test", (payload) => {
console.log("Got test:", payload)
// ...
})
socket.emit("test2", "lol")
})
}
res.end()
}
export default SocketHandler

View file

@ -1,27 +1,24 @@
import { ClientToServerEvents, ServerToClientEvents } from "./api/ws"
import { cSocket } from "../interfaces/NextApiSocket"
import useGameState from "@lib/hooks/useGameState"
import { ChangeEventHandler, useEffect, useState } from "react"
import { io, Socket } from "socket.io-client"
import { io } from "socket.io-client"
let socket: Socket<ServerToClientEvents, ClientToServerEvents>
let socket: cSocket
const Home = () => {
const [input, setInput] = useState("")
const [data, setData] = useState("")
useEffect(() => {
socketInitializer()
}, [])
const { status } = useGameState()
async function socketInitializer() {
await fetch("/api/ws")
socket = io()
await fetch("/api/login", {
method: "POST",
body: JSON.stringify({ username: "warst", password: "warst" }),
})
// getAccessToken().then((token) => {
// socket.emit("authenticate", { token })
// })
useEffect(() => {
if (status === "loading") return
if (!socket) {
console.log("Socket init.")
socket = io({
path: "/api/ws",
})
} else console.log("Socket present.")
socket.on("connect", () => {
console.log("connected")
@ -38,11 +35,18 @@ const Home = () => {
socket.on("update-input", (msg) => {
setData(msg)
})
}
return () => {
socket.off("connect")
socket.off("authenticated")
socket.off("unauthenticated")
socket.off("update-input")
}
}, [status, setData])
const onChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
setInput(e.target.value)
socket.emit("input-change", e.target.value)
socket?.emit("input-change", e.target.value)
}
return (