-
socket.io를 이용한 채팅 서비스 구현Javascript/Node.js 2020. 1. 29. 14:19
schema
본 프로젝트에서는 nosql인 mongoDB를 사용했다. 스키마 설계는 다음과 같이 하였다.
Room은 채팅방에 관한 정보가 들어있으며, 비밀번호가 있으면 비밀방이다. Chat에 존재하는 room을 이용해 Room schema를 참조할 수 있다.
packages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters"dependencies": { "axios": "^0.18.0", "color-hash": "^1.0.3", "connect-flash": "^0.1.1", "cookie-parser": "^1.4.4", "dotenv": "^7.0.0", "express": "^4.16.4", "express-session": "^1.15.6", "mongoose": "^5.4.20", "morgan": "^1.9.1", "multer": "^1.4.1", "pug": "^2.0.3", "socket.io": "^2.2.0", "ws": "^5.2.2" }, 소스 코드(핵심)
app.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersconst express = require('express'); const path = require('path'); const morgan = require('morgan'); const cookieParser = require('cookie-parser'); const session = require('express-session'); const flash = require('connect-flash'); // 랜덤 색상을 구현해주는 모듈 const ColorHash = require('color-hash'); require('dotenv').config(); const webSocket = require('./socket'); const indexRouter = require('./routes'); const connect = require('./schemas'); const app = express(); // 몽고디비와 연결 connect(); // 세션을 저장 const sessionMiddleware = session({ resave: false, saveUninitialized: false, secret: process.env.COOKIE_SECRET, cookie: { httpOnly: true, secure: false, }, }); /* ... */ // 'gif/'는 uploads 폴더에서부터 시작 app.use('/gif', express.static(path.join(__dirname, 'uploads'))); /* ... */ // cookie에서 .env에 있는 비밀번호 사용 app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(sessionMiddleware); app.use(flash()); // 만약 session에 color가 존재하지 않는다면 새로 color를 만들어줌 app.use((req, res, next) => { if (!req.session.color) { const colorHash = new ColorHash(); req.session.color = colorHash.hex(req.sessionID); } next(); }); /* ... */ socket.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersconst SocketIO = require('socket.io'); const axios = require('axios'); module.exports = (server, app, sessionMiddleware) => { const io = SocketIO(server, { path: '/socket.io' }); // 라우터에서 io 객체를 쓸 수 있게 해줌. req.app.get('io')로 접근 가능하다. app.set('io', io); // of 메소드는 네임스페이스를 부여 const room = io.of('/room'); const chat = io.of('/chat'); io.use((socket, next) => { sessionMiddleware(socket.request, socket.request.res, next); }); room.on('connection', (socket) => { console.log('room 네임스페이스에 접속'); socket.on('disconnect', () => { console.log('room 네임스페이스 접속 해제'); }); }); chat.on('connection', (socket) => { console.log('chat 네임스페이스에 접속'); // 소켓에 존재하는 request 객체 뽑기 const req = socket.request; // headers에 있는 referer 뽑기 // socket.request.headers.referer에서 현제 웹 페이지 URL을 가져올 수 있고, // URL에서 room id 추출할 수 있다. const { headers: { referer } } = req; // referer에서 '/'으로 split 하고 맨 끝에 있는게 roomId인데 /\?.+/을 '' 로 교체 // 암튼 이렇게 하면 referer에서 roomId 뽑을 수 있음 const roomId = referer .split('/')[referer.split('/').length - 1] .replace(/\?.+/, ''); // 이 roomId로 join socket.join(roomId); // 이 방에 시스템 메세지로 아래 메세지 전송 socket.to(roomId).emit('join', { user: 'system', chat: `${req.session.color}님이 입장하셨습니다.`, }); socket.on('disconnect', () => { console.log('chat 네임스페이스 접속 해제'); // 방 나가기 socket.leave(roomId); const currentRoom = socket.adapter.rooms[roomId]; const userCount = currentRoom ? currentRoom.length : 0; // 이 방에 사람이 없다면 방 제거 if (userCount === 0) { axios.delete(`http://localhost:8005/room/${roomId}`) .then(() => { console.log('방 제거 요청 성공'); }) .catch((error) => { console.error(error); }); } else { // 아직 사람이 있다면 시스템 메세지 전송 socket.to(roomId).emit('exit', { user: 'system', chat: `${req.session.color}님이 퇴장하셨습니다.`, }); } }); }); }; 실행화면
출처
https://github.com/zeroCho/nodejs-book
ZeroCho/nodejs-book
Contribute to ZeroCho/nodejs-book development by creating an account on GitHub.
github.com
'Javascript > Node.js' 카테고리의 다른 글
socket.io (0) 2020.01.28 웹 소켓 (0) 2020.01.28 Mocha (0) 2020.01.28 middleware (0) 2020.01.22 express (0) 2020.01.22