fix: remove ajax method in dev env

main
Justin Xiao 2023-07-24 00:13:35 +08:00
parent a0e364905d
commit f47b952b38
7 changed files with 81 additions and 96 deletions

View File

@ -96,8 +96,7 @@ export default function Home() {
useEffect(() => {
connect();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [connect]);
useEffect(() => {
if (!socket) return;
@ -160,7 +159,11 @@ export default function Home() {
>
{!message.me && (
<div className={classes.avatar}>
<Avatar alt="User" color="blue" radius="xl">
<Avatar
alt={onlineUsers[message.from]}
color="blue"
radius="xl"
>
{onlineUsers[message.from] &&
onlineUsers[message.from].length > 5
? `${onlineUsers[message.from].slice(0, 1)}`

View File

@ -8,15 +8,15 @@ type Prop = {
children: React.ReactNode;
};
export function AppProvider({ children }: Prop) {
const [disconnect] = useSocketStore(({ disconnect }) => [disconnect]);
const disconnect = useSocketStore((state) => state.disconnect);
useEffect(() => {
window.addEventListener("beforeunload", disconnect);
return () => {
console.log("disconnect");
window.removeEventListener("beforeunload", disconnect);
disconnect();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [disconnect]);
return (
<RootStyleRegistry>

View File

@ -29,7 +29,6 @@ import {
} from "@tabler/icons-react";
import { SetStateAction, Dispatch, FC, useEffect, useState } from "react";
import useSocketStore from "@/store/socket";
import { environment } from "@/config";
import Avatar from "./Avatar";
type Props = {
@ -218,11 +217,7 @@ const ChatroomTitle: FC<Props> = ({ targetSocketId, setTargetSocketId }) => {
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>
{environment === "development"
? "Not available" // in development mode, hide online user list because it's a server side feature
: "Online user"}
</Menu.Label>
<Menu.Label>Online user</Menu.Label>
{socket?.connected &&
Object.keys(onlineUsers)
.filter((socketId) => socketId !== socket?.id)

View File

@ -1,20 +0,0 @@
import { NextApiResponseServerIO, SocketBroadcastMessage } from "@/types/next";
import { NextApiRequest } from "next";
const broadcast = (req: NextApiRequest, res: NextApiResponseServerIO) => {
if (req.method === "POST") {
// get message
const { from: sourceSocketId, timestamp, message } = req.body as SocketBroadcastMessage;
console.log("PRODUCTION SERVER: Broadcast ", message)
// dispatch to channel "message"
res?.socket?.server?.io?.emit("broadcast", {
from: sourceSocketId,
message,
timestamp,
} as SocketBroadcastMessage);
// return message
res.status(201).json(message);
}
};
export default broadcast;

View File

@ -1,33 +0,0 @@
import { NextApiResponseServerIO, SocketPrivateMessage } from "@/types/next";
import { NextApiRequest } from "next";
const private_message = (req: NextApiRequest, res: NextApiResponseServerIO) => {
if (req.method === "POST") {
// get message
const {
from: sourceSocketId,
to: targetSocketId,
timestamp,
message,
} = req.body as SocketPrivateMessage;
// dispatch to channel "message"
res?.socket?.server?.io?.to(targetSocketId).emit("private_message", {
from: sourceSocketId,
to: targetSocketId,
message,
timestamp,
} as SocketPrivateMessage);
res?.socket?.server?.io?.to(sourceSocketId).emit("private_message", {
from: sourceSocketId,
to: targetSocketId,
message,
timestamp,
} as SocketPrivateMessage);
// return message
res.status(201).json(message);
}
};
export default private_message;

View File

@ -9,6 +9,10 @@ export const config = {
},
};
const onlineUsers = new Map<string, string>();
let isEmitting = false;
let sendOnlineUsers: NodeJS.Timeout;
const socketio = async (req: NextApiRequest, res: NextApiResponseServerIO) => {
if (!res.socket.server.io) {
console.log("MOCK SERVER: First connect on socket.io");
@ -18,10 +22,62 @@ const socketio = async (req: NextApiRequest, res: NextApiResponseServerIO) => {
path: "/api/socket/socketio",
addTrailingSlash: false,
});
io.on("connect", (socket) => {
console.log("MOCK SERVER: SOCKET CONNECTED!", socket.id);
}).on("disconnect", () => {
console.log("MOCK SERVER: SOCKET DISCONNECTED!");
io.on("connection", (socket) => {
console.log("MOCK SERVER: user connected, online user count:", onlineUsers.size);
socket.on("join", (data) => {
const { socketId, name = socketId } = data;
onlineUsers.set(socketId, name);
// console.log(
// 'MOCK SERVER: user joined, online user count:',
// 'socketId: ',
// socketId,
// 'name: ',
// name,
// );
});
socket.on("broadcast", (broadcast, callback) => {
console.log("MOCK SERVER: Broadcast ", broadcast);
io.emit("broadcast", broadcast);
if (callback) {
callback({
ok: true,
});
}
});
socket.on("private_message", (message, callback) => {
console.log("MOCK SERVER: private_message", message);
const { from: sourceSocketId, to: targetSocketId } = message;
io.to(targetSocketId).emit("private_message", message);
io.to(sourceSocketId).emit("private_message", message);
if (callback) {
callback({
ok: true,
});
}
});
socket.on("disconnect", () => {
onlineUsers.delete(socket.id);
console.log(
"MOCK SERVER: user disconnected, online user count:",
onlineUsers.size
);
if (isEmitting && onlineUsers.size === 0) {
clearInterval(sendOnlineUsers);
isEmitting = false;
}
});
if (!isEmitting) {
sendOnlineUsers = setInterval(
() => io.emit("online_user", Object.fromEntries(onlineUsers)),
5000
);
isEmitting = true;
}
});
// append SocketIO server to Next.js socket server response
res.socket.server.io = io;

View File

@ -12,8 +12,8 @@ type EmitModeDataTypes = {
type Store = {
socket: null | Socket;
emitMode: "broadcast" | "private_message";
setEmitMode: (mode: "broadcast" | "private_message") => void;
emitMode: keyof EmitModeDataTypes;
setEmitMode: (mode: keyof EmitModeDataTypes) => void;
emit: <T extends keyof EmitModeDataTypes>(event: T, data: EmitModeDataTypes[T]) => void;
connect: () => void;
disconnect: () => void;
@ -33,21 +33,6 @@ const useSocketStore = create<Store>((set, get) => {
* @param data - The data to send along with the event.
*/
emit: (event, data) => {
// console.log("emit", event, data);
// Check if environment is development
if (environment === "development") {
// Send a POST request to the /api/socket/${event} endpoint with the data
fetch(`/api/socket/${event}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}).catch((error) => {
// Display an error message if there was an error sending the request
if (error instanceof Error) toast.error(error?.message);
});
} else {
const { socket } = get();
if (!socket) return toast.error("Socket not connected");
// This callback response needs to define on server at first.
@ -56,7 +41,6 @@ const useSocketStore = create<Store>((set, get) => {
// Display an error message if response.ok is false
if (!response.ok) toast.error("Something went wrong");
});
}
},
/**
* Connects to the socket server.