MQTT로 카톡서버 만들어보자 - 3/10. 사용자 상태

빙고리우스·2024년 3월 25일
2
post-thumbnail

내 죽음을 서버에게 알려라~

장군께서는

나의 죽음을 적에게 알리지마라

라고 하셨지만, client는 자신의 죽음을 server 에게 알려야 한다.
이것을 LWT(Last will and testament) 라고 하며 고급지게 유언 이라 한다.
우리는 죽을 때 말(言)을 남기는데, 서양은 윌(Will)을 남기나 보다.

죽었니? 살았니?

장군의 죽음을 왜군이 알아선 안되지만,
serverclient 상태를 알아야 한다.
왜?
servertalk을 보낼 때(전파할 때) 이 톡을 받는 주체는 clientmqtt_connect이다.
clientmqtt_connect이 살아 있는지, 아니면 죽었는지에 따라 pub할지 push할지 결정하기 때문이다.

clientmqtt_connect가 죽었는지, 살았는지 알려면 어떡해해야할까?
will이 그 답이다.
clientmqtt_connect 가 죽으면 bokerclientwill을 보낼 것이다.
server는 이 will을 수신하고 있다가, 어느 client가 죽었는지? 살았는지 판단하면 된다.

상태설명
active😁 앱에서 mqtt_connect 가 살아 있을 때
inactive😅 mqtt_connect 가 죽었을 때
uninstall😰 슬프게도 앱을 삭제했을 때

mqtt_connect 생사 여부와 별개로 앱에서 앱 Noti 띄우는 건 또 다른 로직이다.
client 앱에서는 mqtt_connect 가 살아 있고, foreground 상태이며, 현재 message와 동일 room 에 있다면 앱 Noti에 등록하지 않고 톡방에만 쏘면 된다.
그 이외에는 Noti에 띄워야 한다.
앱 개발자라면 이 말을 이해할 것이다.

상태설명
App.state == Foreground && room == message.roomroom 화면에 talk 내용을 쓰면 된다.
App.state == Foreground && room != message.roomNoti에 등록
App.state == Background || App을 실행하지 않은 경우Noti에 등록

어떻게 나의 죽음을 알릴 것인가?

lwt의 기본 개념은 이렇다.
죽기 전 lwt(유언)을 써 놓고, 내가 죽으면 내 죽음에 관심있는 자(여기선 server겠지)에게 뿌리라고 borker에게 부탁하는거다.
client가 mqtt 연결할 때 lwt를 함께 등록하는 거다.
nodejs mqtt에서는 다음과 같다.

클라이언트에 추가되는 코드

client에 추가하는 코드는 단순한다. 접속할 때 나의 will을 등록하면 된다.
요렇게 해 놓으면 connection이 끊어지면 broker(브로커라기보단 변호사네😏) 가 나의 죽음에 관심있는(sub하고 있는) 이들한테 이를 뿌려준다.

const user_id = process.argv[2]; //'client1';

const client = mqtt.connect({
    host: 'localhost',
    will: {
        topic: 'server/die',
        payload: JSON.stringify({ data: { id: user_id } })
    }
});

내 죽음에 관심 있는 자들이 여럿 있겠지만 😂, server가 가장 관심이 있을 것이다.
왜냐하면 이를 DB에 저장하고 pub할지 push할지 결정해야 하기 때문이다.
따라서 서버 토픽인 server/die로 이름 짓자.

서버에 추가되는 코드

이제 서버가 server/die topic도 sub하도록 추가하면 된다.

server.on("connect", () => {
    server.subscribe(["server/login", "server/talk", "server/die"]);
});

그 다음 server/die가 들어왔을 때 처리하는 함수만 짜 넣으면 끝.

server.on("message", (topic, message) => {
    console.log('received: ', topic, JSON.parse(message));
    if (topic.endsWith('/login')) process_login(message);
    else if (topic.endsWith('/talk')) process_talk(message);
    else if (topic.endsWith('/die')) process_die(message);
});

...

function process_die(message) {
    let json = JSON.parse(message);
    mysql_conn.sql(UPDATE_USER_STATE, [json.data.id,'inactive'], function(err, results, fields) {
    ...
    }
}

서버가 있어 너무 행복😁하지 아니한가?

다른 상태는?

active는 따로 로직을 뺄 필요도 없다.
active는 로그인 시 active로 DB에 Update하도록 추가하면 된다.
uninstall은 앱 삭제 이벤트 받아 Update하면 된다.


profile
다할줄아는 사람보다 뭔가 한가지 똑부러지게하는 사람이되자.

2개의 댓글

comment-user-thumbnail
2024년 3월 27일

녜. 저도 서버가 있어 행복하고 싶네요.
조금 더 봐야할듯요.

1개의 답글