๊ณต์ฐ์ฅ ์ ์ฅ ์ QR์ฝ๋ ํฐ์ผ์ ์ฐ๊ณ ์ ์ฅ ํ์ธ์ ๋ฐ์ ํ์ ๋ค์ด๊ฐ๋ค. ์ฝ๋๋ฅผ ์ฐ๋ ์๋๋ก์ด๋ ์ฑ์์ ์ ๊ธ ์ฌ๋ถ๋ฅผ ํ์ธํ ํ์ ์ง์ ์ ์ฅํ ์๋ ์๊ฒ ์ง๋ง ์๋ฌด๋๋ ๋์ ๋ณด์ด๋ ๋ณํ๊ฐ ์์ผ๋ฉด ์ข์๊ฑฐ๋ ์๊ฐ์ด ๋ค์๋ค.
์์ผ์ ์ด์ฉํ ์ค์๊ฐ ํต์ ์ ๋ฃ์ด๋ณด๊ธฐ๋ก ํ๋ค. ์๋ฒ์์ ์ ์ฅ ํ์ธ์ด ๋๋ฉด ํด๋ผ์ด์ธํธ(ํด๋น ๊ด๊ฐ ๊ธฐ๊ธฐ)๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ฃผ๋ ๋ฐฉ์์ด๋ค.
๋ฐฑ์๋
๋์ฅ๋์ด ์์ ํ ๋ฐฑ์๋ ์ฝ๋์ด๋ค. ์ด์ฌํ ๋ฐฐ์์๋ค.
const { Server } = require('socket.io');
const { httpServer } = require('../index');
class SocketSingleton {
constructor(httpServer) {
// try catch ์์ด ์ด๊ธฐ ์ค์ ์ด fail ํ๋ฉด ์๋ฒ ๋ฐ๋ก ์ข
๋ฃ
this.io = new Server(httpServer, {
/* options */
cors: {
origin: ['https://admin.gosrock.link','https://gosrock.link', 'http://localhost:3000']
}
});
this.adminSocket = this.io.of('/socket/admin');
this.ticketsSocket = this.io.of('/socket/tickets');
this.startCheck = false; // ์์ผ ์๋ฒ ์คํ ์ฒดํฌ ๋ณ์
}
// ์์ผ ์๋ฒ ์คํ
startSocketServer = () => {
/**
*
**/
};
}
module.exports = new SocketSingleton(httpServer);
์์ฑ์ ์์์ ์์ผ์ ์ด๊ธฐํํด์ฃผ๊ณ ๋ค์์คํ์ด์ค๋ฅผ ๋ง๋ค์ด์ค๋ค. ๊ณต์๋ฌธ์๊ฐ ๋งค์ฐ ์ ๋์ด ์๋ค.
adminSocket ์ ์ด๋๋ฏผํ์ด์ง์์ ์ ์ฅํ์ธํ ๋, ticketsSocket์ ํ๋ก ํธ ํ์ด์ง์์ ์ ์ฅํ์ธํ ๋ ์ฌ์ฉํ ๋ค์์คํ์ด์ค์ด๋ค.
์ฑ๊ธํค
์์ผ ๊ฐ์ฒด๋ฅผ ์ฑ๊ธํค์ผ๋ก ๋ง๋ค์ด์ ์ธ๋ถ์์๋ ๊ฐ์ ์ ๊ทผํ ์ ์๋๋ก ํ๋ค. new SocketSingleton(httpServer);
๋ก ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ ๋ชจ๋๋ก exports ํด์ฃผ์๋ค. nodejs์์ ํ๋ฒ load(require)๋ ๋ชจ๋์ require.cache ๋ผ๋ ๊ฐ์ฒด์ ์บ์ฑ๋๋๋ฐ, ์ฆ ๋ชจ๋์ require ํ ๋๋ง๋ค ์๋ก์ด ์ธ์คํด์ค๊ฐ ์์ฑ๋๋๊ฒ ์๋๋ผ ์บ์ฑ๋ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์ฌ์ฌ์ฉํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฑ๊ธํค์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋๋ ๊ฒ!!
const express = require('express');
const app = express();
const { createServer } = require('http');
const httpServer = createServer(app);
module.exports = { httpServer };
//...
const SocketSingleton = require('./sockets');
const server = () => {
//...
SocketSingleton.startSocketServer();
//...
httpServer.listen(5000);
}
server();
index.js์์๋ ์์ผ ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์์ฒ๋ผ ๋ถ๋ฌ์์ ์ฌ์ฉํ๋ค.
์์ผ ์ฐ๊ฒฐํ๊ธฐ
startSocketServer = () => {
if (this.startCheck) throw Error('์์ผ์๋ฒ๋ฅผ ์ด์ค์ผ๋ก ์คํํ์ต๋๋ค.');
const connectionAuthMiddleware = require('./connectionAuthMiddleware');
const ticketsUrlMiddleware = require('./ticketsUrlMiddleware');
connectionAuthMiddleware();
ticketsUrlMiddleware();
this.io.on('connection', socket => {
socket.disconnect();
});
this.adminSocket.on('connection', socket => {
console.log('admin is enter', socket.data);
});
this.ticketsSocket.on('connection', socket => {
console.log('tickets is enter', socket.data.ticketId);
//๋ฃธ์ ๊ฐ์ ์ฝ์
socket.join(socket.data.ticketId);
});
this.startCheck = true;
};
startSocketServer ๋ฉ์๋์ด๋ค. ์๊น ์์ฑ์์์ ์ด๊ธฐํ๋ ๋ค์์คํ์ด์ค๋ณ๋ก connection ์ ๋ณด๋ฅผ ๋ฐ๋ก ๋ฐ๊ณ ์๋ค. ๊ธฐ๋ณธ ๋ค์์คํ์ด์ค์ ์ฐ๊ฒฐ๋ ์์ผ์ ํ์์์ผ๋ ๋ฐ๋ก ๋์ด์ค๋ค๊ณ ํ๋ค.
ticketsSocket์ด ์ฐ๊ฒฐ๋๋ฉด socket.join(socket.data.ticketId);
๋ก room์ ๋ง๋ค๊ณ joinํ๋ค. ์
์ฅํ์ธ ์ ๋ณด๋ฅผ ํ์์ฝ๋๋ฅผ ์ฐ์ ๊ฐ๊ฐ์ ๊ธฐ๊ธฐ์ ๊ฐ๋ณ์ ์ผ๋ก ๋ณด๋ด์ผ ํ๊ธฐ ๋๋ฌธ์ room์ ์ฌ์ฉํ๋ค. ์ฑํ
์ผ๋ก ์น๋ฉด ๊ฐ ํก๋ฐฉ. room์ socket.data.ticketId
์ ๊ฐ์ผ๋ก ๊ตฌ๋ถํ๋๋ฐ, ๊ทธ ๊ฐ์ ๋ฉ์๋๋ฅผ ์คํํ ํ์ ๋ฏธ๋ค์จ์ด์์ ๋ฐ์์ ๋๊ฒจ์ค ๊ฐ์ด๋ค.
๋ฏธ๋ค์จ์ด
๋ฏธ๋ค์จ์ด์์๋ ์์ผ ํต์ ์ ๋ด๊ธด ํค๋ ํ ํฐ ๊ฒ์ฆ๊ณผ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ ๋๊ฒจ์ค๋ค. ํ ํฐ์ด ๊ฒ์ฆ๋์๋ค๋ฉด socket.data.ticketId = ticketId;
๋ก ์ง์ socket ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋๋ค.
ํด๋ผ์ด์ธํธ์์ auth ์ต์
์ผ๋ก ๋ณด๋ธ ์ ๋ณด๋ฅผ ์๋ฒ์์ handshake.auth
๋ก ๋ฐ์ ์ ์๋ค.
์ ์ฅ ํ์ธ
SocketSingleton.ticketsSocket
.to(ticketId)
.emit('enter', { enterState: true, ticketInfo: ticketUpdated });
์๋๋ก์ด๋ ๊ธฐ๊ธฐ์์ ๋ณด๋ธ ์
์ฅํ์ธ api ์์ฒญ์ ๋ฐ๊ฒ ๋๋ฉด ํฐ์ผ์ ์
๊ธ์ํ๋ฅผ ๊ฒ์ฆํ ํ์ ์์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์คํํ๋ค. .to(ticketId).emit()
์ผ๋ก ํน์ ํ ticketId์ room์๋ง emit์ ๋ณด๋ผ ์ ์๋ค.
์ฑ๊ธํค์ ์ฐ๋ ์ด์ ๋ ์ฌ๊ธฐ์ ์๋ค. SocketSingleton ์ธ์คํด์ค๊ฐ ๋ฑ ํ๊ฐ๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋์ ์ ๊ทผํ๋ ๋๊ฐ์ ๊ฐ์ฒด์ ์ ๊ทผํ ์ ์๋ ๊ฒ์ด๋ค.
ํ๋ก ํธ
๋ด๊ฐ ๋ด๋นํ ํ๋ก ํธ์๋ ๋ถ๋ถ ์ฝ๋๋ ํจ์ฌ ๊ฐ๋จํ๋ค. ์๋ฒ์์ '์ ์ฅ ํ์ธ'์ด๋ผ๋ ์ ๋ณด๊ฐ ์ค๋ฉด ๋ฆฌ๋์ค์ ์ ์ฅ๋ ํฐ์ผ ์ํ๋ฅผ ๋ฐ๊ฟ์ฃผ๊ณ ํฐ์ผ์ ์๊น์ ๋ฐ๊ฟ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
npm install socket.io-client
socket.io-client ๋ฅผ ์ค์นํ๊ณ import io from 'socket.io-client'
๋ก ์ํฌํธํด์ค๋ค.
const [socket, setSocket] = useState();
useEffect(() => {
if (!socket) {
setSocket(
io('https://api.gosrock.link/socket/tickets', {
auth: {
ticketId: ticketId
}
})
);
} else {
socket.on('enter', data => {
if (data.enterState) {
dispatch({ type: 'TICKET_ENTER_SUCCESS', payload: data.ticketInfo });
toast('์
์ฅ ์๋ฃ', 5000);
}
});
}
}, [socket]);
socket state๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ๋ค. useEffect ํ ์ ์ฌ์ฉํ๋๊ฒ ์ ์ผ ์ข์ ๋ฐฉ๋ฒ์ธ์ง๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค. ์์ผ๊ณผ ์ฐ๊ฒฐ์ ์ฒซ ๋ ๋๋ง ์์๋ง ํ๊ธฐ ์ํด ํ ์์ ๋ฃ์๋ค.
io()์ ์ฒซ๋ฒ์งธ ์ธ์๋ก ๋๋ฉ์ธ์ ๋ฃ๊ณ ์ด๊ธฐํ ํด์ค๋ค. /socket/tickets
๋ค์ ์คํ์ด์ค๋ก ์ฐ๊ฒฐ์ด ๋๋ค. ๋๋ฒ์งธ ์ธ์๋ก๋ ์ต์
์ด ๋ค์ด๊ฐ๋๋ฐ, auth ์ต์
์ผ๋ก ๋ค์ ์คํ์ด์ค๋ก ์ฐ๊ฒฐํ ๋ ์ธ์ฆ์ ์ํ ํ ํฐ์ ๋ด์์ ๋ณด๋ผ ์ ์๋ค. ๋ฌธ์
socket.on()
์ผ๋ก ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ ์๋ค. 'enter'์ด๋ฒคํธ๊ฐ ์์ ๋ data๋ฅผ ์ด์ด์ ์
์ฅ ํ์ธ์ด๋ฉด ๋ฆฌ๋์ค์ ๋์คํจ์นํ๋ค.
๊ฒฐ๊ณผ
ํฌ์คํธ๋งจ์ผ๋ก ๋ณด๋ด๋ณด์๋ค. ์๋๋ก์ด๋ ๊ธฐ๊ธฐ์์ ์๋ฒ๋ก ๋ณด๋ด๋ ์ ์ฅํ์ธ api์ด๋ค. ์๋ฒ๋ ํฐ์ผ์ ์ ๊ธ ์ํ๋ฅผ ํ์ธํ๊ณ emit์ผ๋ก ๋ณด๋ธ๋ค.
๋ฆฌ๋์ค์ ์ ์ฅ๋ ํฐ์ผ์ ์ํ๊ฐ 'enter'์ด๋ฉด QR์ฝ๋ ์ฃผ๋ณ์ ํ ๋๋ฆฌ๊ฐ ๊ธ์์ด ๋๋๋ก ํ๋ค. ์ด์๋ค. ํ ์คํธ ๋ฌธ๊ตฌ๋ 5์ด๋์ ์ฌ๋ผ์๋ค๊ฐ ์ฌ๋ผ์ง๋๋ก. ์๋ฌด๋ ์ ๊ฒฝ ์์ธ ๊ฒ ๊ฐ์ง๋ง ๋ง์ ๋ ๋ค!! ์ด์ ๋ถํฐ ์์ผํต์ ์ ์จ๋ณด๊ณ ์ถ์๋๋ฐ ์ด๋ฒ ๊ธฐํ์ ์ ์ ํ๊ฒ ๋ฃ์ด๋ณผ ์ ์์ด์ ์ข์๋ค. ๋ค์ ๋ฌ์๋ ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์จ๋ด์ผ๊ฒ๋ค.