leaky-ships/leaky-ships/pages/api/ws.ts
2023-05-24 10:10:56 +02:00

211 lines
5.6 KiB
TypeScript

import {
NextApiResponseWithSocket,
sServer,
sSocket,
} from "../../interfaces/NextApiSocket"
import {
composeBody,
gameSelects,
getAnyGame,
getAnyRunningGame,
} from "./game/running"
import logging from "@lib/backend/logging"
import prisma from "@lib/prisma"
import { GamePropsSchema } from "@lib/zodSchemas"
import colors from "colors"
import status from "http-status"
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) {
logging("Socket is already running " + req.url, ["infoCyan"], req)
} else {
logging("Socket is initializing " + req.url, ["infoCyan"], req)
const io: sServer = new Server(res.socket.server, {
path: "/api/ws",
cors: {
origin: "https://leaky-ships.mal-noh.de",
},
})
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,
},
})
const game = await getAnyRunningGame(socket.data.user?.id ?? "")
if (!game) {
logging(
"Forbidden, no game found: " +
JSON.stringify(Array.from(socket.rooms)),
["debug"],
socket.request
)
next(new Error(status["403"]))
return
}
socket.data.gameId = game.id
socket.join(game.id)
next()
} catch (err) {
logging(status["401"], ["warn"], socket.request)
next(new Error(status["401"]))
}
})
io.on("connection", async (socket) => {
logging(
`User connected <${socket.data.user?.email}>`.green +
", " +
socket.id.cyan,
["infoGreen"],
socket.request
)
join(socket, io)
socket.on("update", async (cb) => {
const game = await getAnyGame(socket.data.gameId ?? "")
if (!game) return
const body = composeBody(game)
cb(body)
})
socket.on("gameSetting", async (payload, cb) => {
const game = await prisma.game.update({
where: { id: socket.data.gameId ?? "" },
data: payload,
...gameSelects,
})
const { hash } = composeBody(game)
if (!hash) return
cb(hash)
io.to(game.id).emit("gameSetting", payload, hash)
})
socket.on("ping", (count, callback) => {
callback(count)
})
socket.on("leave", async (cb) => {
if (!socket.data.gameId || !socket.data.user?.id) return cb(false)
const user_Game = await prisma.user_Game.delete({
where: {
gameId_userId: {
gameId: socket.data.gameId,
userId: socket.data.user?.id,
},
},
})
const enemy = await prisma.user_Game.findFirst({
where: {
gameId: socket.data.gameId,
},
})
let body: GamePropsSchema
if (user_Game.index === "player1" && enemy) {
body = composeBody(
(
await prisma.user_Game.update({
where: {
gameId_index: {
gameId: socket.data.gameId,
index: "player2",
},
},
data: {
index: "player1",
},
select: {
game: { ...gameSelects },
},
})
).game
)
} else {
const game = await prisma.game.findUnique({
where: {
id: socket.data.gameId,
},
...gameSelects,
})
if (!game) return cb(false)
body = composeBody(game)
}
const { payload, hash } = body
if (!payload || !hash) return cb(false)
io.to(socket.data.gameId).emit(
"playerEvent",
{ player1: payload.player1, player2: payload.player2 },
hash,
"leave"
)
cb(true)
if (!payload?.player1 && !payload?.player2) {
await prisma.game.delete({
where: {
id: socket.data.gameId,
},
})
}
})
socket.on("disconnecting", async () => {
logging(
"Disconnecting: " + JSON.stringify(Array.from(socket.rooms)),
["debug"],
socket.request
)
// if (!socket.data.gameId) return
// const game = await prisma.game.findUnique({
// where: {
// id: socket.data.gameId
// },
// ...gameSelects
// })
// if (!game) return
// const { payload, hash } = composeBody(game, socket.data.user?.id ?? "")
// if (!hash) return
// io.to(socket.data.gameId).emit("playerEvent", {}, hash, "disconnect")
})
socket.on("disconnect", () => {
// socket.rooms.size === 0
logging("Disconnect: " + socket.id, ["debug"], socket.request)
})
})
}
res.end()
}
async function join(socket: sSocket, io: sServer) {
const game = await getAnyGame(socket.data.gameId ?? "")
if (!game) return socket.disconnect()
const { payload, hash } = composeBody(game)
if (!hash) return socket.disconnect()
io.to(game.id).emit(
"playerEvent",
{ player1: payload?.player1, player2: payload?.player2 },
hash,
"join"
)
}
export default SocketHandler