Functioning websocket connections

This commit is contained in:
aronmal 2023-04-27 17:41:16 +02:00
parent a227da52bc
commit 30db96a3f7
Signed by: aronmal
GPG key ID: 816B7707426FC612
9 changed files with 104 additions and 182 deletions

View file

@ -1,10 +1,12 @@
import Icon from "./Icon"
import Player from "./Player"
import useGameState from "@lib/hooks/useGameState"
import useSocket from "@lib/hooks/useSocket"
import { Fragment, useEffect, useState } from "react"
function LobbyFrame({ openSettings }: { openSettings: () => void }) {
const { payload } = useGameState().gameProps
useSocket()
const [dots, setDots] = useState(1)
useEffect(() => {
@ -18,7 +20,8 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
<div className="flex items-center justify-between border-b-2 border-slate-900">
<Icon src="speech_bubble.png">Chat</Icon>
<h1 className="font-farro text-5xl font-medium">
Game-PIN: <span className="underline">{payload?.gamePin?.pin}</span>
Game-PIN:{" "}
<span className="underline">{payload?.gamePin?.pin ?? "---"}</span>
</h1>
<Icon src="gear.png" onClick={openSettings}>
Settings

View file

@ -1,44 +0,0 @@
import { cSocket } from "../interfaces/NextApiSocket"
import useGameState from "@lib/hooks/useGameState"
import { useEffect } from "react"
import { io } from "socket.io-client"
let socket: cSocket
function SocketIO() {
const { session, status } = useGameState()
useEffect(() => {
if (status === "loading" || socket) return
socket = io({
path: "/api/ws2",
})
socket.on("connect", () => {
console.log("connected")
})
socket.on("authenticated", () => {
console.log("Yay!")
})
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>
}
export default SocketIO

View file

@ -1,3 +1,4 @@
import { GamePropsSchema } from "@lib/zodSchemas"
import { User } from "@prisma/client"
import type { Server as HTTPServer } from "http"
import type { Socket as NetSocket } from "net"
@ -20,19 +21,14 @@ export interface NextApiResponseWithSocket extends NextApiResponse {
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
// withAck: (d: string, ) => void
forbidden: () => void
update: (game: GamePropsSchema) => void
}
export interface ClientToServerEvents {
// hello: () => void
"input-change": (msg: string) => void
join: (userId: string, callback: () => void) => void
authenticate: (payload: { token: string }) => void
test: (payload: any) => void
}
interface InterServerEvents {
@ -41,6 +37,7 @@ interface InterServerEvents {
interface SocketData {
user: User | null
gameProps: GamePropsSchema
}
export type cServer = Server<

View file

@ -0,0 +1,58 @@
import useGameState from "@lib/hooks/useGameState"
import { socket } from "@lib/socket"
import { useEffect, useState } from "react"
function useSocket() {
const [isConnected, setIsConnected] = useState(socket.connected)
const [hasJoined, setHasJoined] = useState(false)
// const [fooEvents, setFooEvents] = useState([])
const { session, status, setGameProps } = useGameState()
useEffect(() => {
if (status === "loading") return
socket.on("connect", () => {
console.log("connected")
setIsConnected(true)
})
socket.on("connect_error", () => {
console.log("connect_error")
})
socket.on("disconnect", () => {
console.log("disconnect")
setIsConnected(false)
})
socket.on("forbidden", () => {
console.log("forbidden")
})
socket.on("update", (body) => {
console.log("update")
setGameProps(body)
})
return () => {
// for all events
socket.removeAllListeners()
}
}, [status, setGameProps])
useEffect(() => {
if (session?.user.id && !hasJoined) {
socket?.emit("join", session?.user.id, () => {
setHasJoined(true)
})
}
}, [session?.user.id, hasJoined])
useEffect(() => {
if (!isConnected) return
socket?.emit("authenticate", { token: `hello from ${session?.user.email}` })
}, [isConnected, status, session?.user.email])
return socket
}
export default useSocket

View file

@ -0,0 +1,6 @@
import { cSocket } from "../interfaces/NextApiSocket"
import { io } from "socket.io-client"
export const socket: cSocket = io({
path: "/api/ws2",
})

View file

@ -1,37 +0,0 @@
import type {
NextApiResponseWithSocket,
cServer,
} from "../../interfaces/NextApiSocket"
import type { NextApiRequest } from "next"
import { Server } from "socket.io"
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: 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.user) socket.emit("unauthenticated")
// socket.broadcast.emit("update-input", msg)
io.emit("update-input", msg)
})
socket.on("test", (payload) => {
console.log("Got test:", payload)
// ...
})
socket.emit("test2", "lol")
})
}
res.end()
}
export default SocketHandler

View file

@ -2,6 +2,7 @@ import {
NextApiResponseWithSocket,
cServer,
} from "../../interfaces/NextApiSocket"
import { composeBody, getAnyRunningGame } from "./game/running"
import prisma from "@lib/prisma"
import colors from "colors"
import { NextApiRequest } from "next"
@ -18,7 +19,12 @@ const SocketHandler = async (
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" })
const io: cServer = new Server(res.socket.server, {
path: "/api/ws2",
cors: {
origin: "https://leaky-ships.mal-noh.de",
},
})
res.socket.server.io = io
@ -41,21 +47,34 @@ const SocketHandler = async (
})
io.on("connection", (socket) => {
console.log(`User connected <${socket.data.user?.email}>`.green)
console.log(
`User connected <${socket.data.user?.email}>`.green,
socket.id
)
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("join", async (userId, cb) => {
console.log(socket.rooms, "join")
const game = await getAnyRunningGame(userId ?? "")
if (!game) {
const warst = socket.emit("forbidden")
console.log("forbidden", warst)
return
}
cb()
socket.join(userId)
const body = composeBody(game)
socket.data.gameProps = body
io.to(userId).emit("update", body)
})
socket.on("test", (payload) => {
console.log("Got test:", payload)
// ...
socket.on("disconnecting", () => {
console.log("disconnecting", socket.rooms) // the Set contains at least the socket ID
})
socket.emit("test2", "lol")
socket.on("disconnect", () => {
// socket.rooms.size === 0
console.log("disconnect", socket.id)
})
})
}
res.end()

View file

@ -1,65 +0,0 @@
import { cSocket } from "../interfaces/NextApiSocket"
import useGameState from "@lib/hooks/useGameState"
import { ChangeEventHandler, useEffect, useState } from "react"
import { io } from "socket.io-client"
let socket: cSocket
const Home = () => {
const [input, setInput] = useState("")
const [data, setData] = useState("")
const { status } = useGameState()
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")
})
socket.on("authenticated", () => {
console.log("Yay!")
})
socket.on("unauthenticated", () => {
console.log("No... pls work")
})
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)
}
return (
<>
<input
placeholder="Type something"
value={input}
onChange={onChangeHandler}
onDoubleClick={() => setInput(data)}
/>
<h1>{data}</h1>
</>
)
}
export default Home

View file

@ -1,15 +0,0 @@
import SocketIO from "../components/SocketIO"
export default function Home() {
return (
<>
<main>
<div className="App">
<header className="App-header">
<SocketIO />
</header>
</div>
</main>
</>
)
}