11-3. 새 포스트 생성시 실시간 전송
이제 서버쪽에서 웹소켓을 다루는 방법과, redis 를 데이터 전달 중간자 역할로써 구현하는 방법을 알아보았으니, 유저가 새 포스트를 작성했을 때 접속중인 모든 유저들에게 실시간으로 데이터를 전달해보겠습니다.
방법은 간단합니다. posts.controller 에서 redis publisher 를 만들고, write 함수가 실행 될 때, 포스트 내용을 발행하면 됩니다. 이 때 우리는, 데이터 형식을 편의상 리덕스 액션 형식과 동일하게 구성하겠습니다.
추가적으로, redis 쪽과 소켓쪽에서 데이터가 전송 될 때는 문자열 형태여야 하므로, JSON.stringify
로 한번 객체를 감싼다음에 발행하세요.
src/api/posts/posts.controller.js
(...)
const redis = require('redis');
const publisher = redis.createClient();
exports.write = async (ctx) => {
(...)
/* 포스트 정보 반환 */
ctx.body = post;
/* 데이터를 리덕스 액션 형식으로 전송 */
publisher.publish('posts', JSON.stringify({
type: 'posts/RECEIVE_NEW_POST',
payload: post
}));
};
(...)
그 다음엔, 웹 소켓쪽 코드를 조금 수정해주고, 불필요한 코드는 제거해주겠습니다.
src/ws/index.js
const Router = require('koa-router');
const redis = require('redis');
// 두개의 redis 클라이언트 생성
const subscriber = redis.createClient();
subscriber.subscribe('posts'); // posts 채널 구독
const ws = new Router();
ws.get('/ws', (ctx, next) => {
// 구독자가 message 받을 때 마다 해당 소켓에 데이터 전달
// 연결이 끊겼을 때 취소 할 수 있도록 따로 구분해줍니다
const listener = (channel, message) => {
// 메시지를 그대로 전달해줍니다
ctx.websocket.send(message);
};
subscriber.on('message', listener);
// 유저가 나갔을 때
ctx.websocket.on('close', () => {
subscriber.removeListener('message', listener);
});
});
module.exports = ws;
구독자가 새 데이터를 받게되면 그 데이터를 그대로 유저에게 전달합니다. 그리고, 접속이 끊기게 되면 removeListener
르 통하여 이벤트 등록한것을 취소해주어야하는데요, 이 과정에서 만약에 상단코드에서 on('message', (channel, message) => {...})
형식으로 익명함수로 만들어서 등록을 하면 취소를 할 수 없으니 따로 listener
라는 레퍼런스를 넣어서 담아주고, 접속종료시 이를 제거해주도록 하는 코드를 추가했습니다.