| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- import { defineBoot } from "#q-app/wrappers";
- import { io } from "socket.io-client";
- import { reactive } from "vue";
- const state = reactive({
- activeRooms: new Set(),
- isConnected: false,
- });
- const socket = io(process.env.WEBSOCKET_API, {
- transport: ["websocket"],
- path: process.env.WEBSOCKET_PATH,
- auth: {
- apiKey: process.env.WEBSOCKET_API_KEY,
- },
- reconnection: true,
- reconnectionDelay: 1000,
- timeout: 20000,
- });
- /**
- * Join a room with automatic reconnection handling
- * @param {string} roomName Room name to join
- * @return {boolean} Success status
- */
- const joinRoom = (roomName) => {
- if (!roomName) return false;
- const fullRoomName = `${process.env.WEBSOCKET_ROOM}:${roomName}`;
- state.activeRooms.add(fullRoomName);
- if (state.isConnected) {
- socket.emit("join", fullRoomName);
- console.log(`Joined room: ${fullRoomName}`);
- } else {
- console.log(`Room ${fullRoomName} will join upon connection`);
- }
- return true;
- };
- /**
- * Leave a room and clean up
- * @param {string} roomName Room name to leave
- */
- const leaveRoom = (roomName) => {
- if (!roomName) return;
- const fullRoomName = `${process.env.WEBSOCKET_ROOM}:${roomName}`;
- state.activeRooms.delete(fullRoomName);
- if (state.isConnected) {
- socket.emit("leave", fullRoomName);
- console.log(`Left room: ${fullRoomName}`);
- }
- };
- const sendEventToLaravel = (eventName, data) => {
- const channel = process.env.WEBSOCKET_ROOM + ":" + eventName;
- socket.emit("eventWrapperToLaravel", {
- channel: channel,
- data: data,
- });
- };
- const sendEvent = (room, eventName, data) => {
- const channel = process.env.WEBSOCKET_ROOM + ":" + room + "@" + eventName;
- socket.emit("eventWrapperToNode", {
- channel: channel,
- data: data,
- });
- };
- export default defineBoot(async () => {
- socket.on("connect", () => {
- console.log("Connected to websocket server!");
- state.isConnected = true;
- // Rejoin all active rooms after reconnection
- if (state.activeRooms.size > 0) {
- console.log(
- `Rejoining ${state.activeRooms.size} rooms after reconnection`,
- );
- state.activeRooms.forEach((room) => {
- socket.emit("join", room);
- });
- }
- });
- socket.on("disconnect", () => {
- console.log("Disconnected from websocket server!");
- state.isConnected = false;
- });
- socket.on("connect_error", (error) => {
- console.error("Websocket connection error: ", error);
- state.isConnected = false;
- });
- socket.on("connect_timeout", (timeout) => {
- console.error("Websocket connection timeout: ", timeout);
- state.isConnected = false;
- });
- socket.on("reconnect", (attemptNumber) => {
- console.log(
- "Reconnected to websocket server! Attempt number: ",
- attemptNumber,
- );
- state.isConnected = true;
- });
- socket.on("reconnect_attempt", (attemptNumber) => {
- console.log("Reconnect attempt number: ", attemptNumber);
- });
- });
- /**
- * Helper function to create one-time event listeners with automatic cleanup
- * @param {string} event Event name
- * @param {Function} callback Callback function
- * @param {string|null} roomName Optional room to leave on callback
- * @return {Function} Cleanup function
- */
- const onceEvent = (event, callback, roomName = null) => {
- if (!event || typeof callback !== "function") return () => {};
- const wrappedCallback = (data) => {
- socket.off(event, wrappedCallback);
- if (roomName) {
- leaveRoom(roomName);
- }
- callback(data);
- };
- socket.on(event, wrappedCallback);
- return () => {
- socket.off(event, wrappedCallback);
- if (roomName) {
- leaveRoom(roomName);
- }
- };
- };
- export {
- socket,
- joinRoom,
- leaveRoom,
- sendEvent,
- sendEventToLaravel,
- onceEvent,
- state,
- };
|