node.js + express 로 슬랙봇 만들기

JavaScript/Node.js · 2022. 3. 14. 01:54

노드로 슬랙봇을 만들어보았다. w/허키로

요구 사항

  1. 월요일 아침 10시 50분 마다 페어 매칭 공지
    1-1. 현재 채널에 있는 구성원 목록 가져오기
    1-2. 가져온 사람 수가 홀수면 한 조는 3인, 나머지은 2인으로 짝을 짓고, 짝수면 2인씩 짝짓는다.
    1-3. 월요일 아침 10시 50분에 슬랙 채널에 공지한다.
  2. 명령어 받아서 페어 명단 관리하기
    2-1. 채널에 명령어 '/페어' 입력 시 금주의 페어 목록 출력
    2-2. 채널에 명령어 '/제외 ooo' 입력 시 특정 인물 차주 페어 명단에서 제외
  3. 배포

slash commands로 명령어를 받아오기 위해서 아래와 같이 작성했다.

app.post('/', (req, res) => {

    if(req.body.command.split('/')[1] === '페어') {
      res.send(`금주의 페어는 ${pairList}입니다`)
    } else if(req.body.command.split('/')[1] === '제외'){
      excluded.push(req.body.text);
      res.end(`${req.body.text}은/는 제외되었습니다`);
    } else {
      res.end('해당하는 명령어가 없습니다');
    }
})

라우팅을 /페어로 받아오는 줄 알고 한참 삽질을 하다가 해결...ㅠㅠ

또 하나 주의할 점은,

const bodyParser = require('body-parser');
app.use(bodyParser.json());

이렇게 body-parser 모듈을 사용해야 req.body.command 안에 /페어를 파싱해줄 수 있다.

슬랙 채널에 메시지를 보내주는 로직 관련 코드는 아래와 같다.

const { WebClient, ErrorCode } = require('@slack/web-api');
const { scheduleJob } = require('node-schedule');
const schedule = require('node-schedule');

const token = process.env.SLACK_BOT_TOKEN;
const web = new WebClient(token);

const noticePair = async () => {
  try {
    const userList = await getUserList();
    const pairList = await makePair(userList);
    const result = await web.chat.postMessage({ 
      channel: conversationId, text: `이번 주 페어 명단은 ${pairList}입니다.`
    });
  } catch (err) {
    console.log(err)
  }

}

schedule.scheduleJob('50 01 * * mon', noticePair);

페어 매칭은 다음과 같이 명단이 담긴 배열을 섞어서, 앞에서부터 둘씩 pair 배열로 끊어 pairs 배열에 저장하고,
마지막에 3개 요소가 남았을 때 pair 배열에 담아 마찬가지로 pairs 배열에 넣고 반복문을 종료했다.

더 나은 코드가 충분히 있겠지만, 일단 빠르게 구현을 하고 싶었다.

const makePair = (usernames) => {
  try {
    const shuffle = (usernames) => {
      const copyUsernames = usernames.slice();
      return copyUsernames.sort(() => Math.random() - 0.5);
    }
    const shuffledUsernames = shuffle(usernames);

    let pairs = [];
    for(let i = 0; i < shuffledUsernames.length; i += 2) {
      let pair = shuffledUsernames.slice(i, i + 2);

      if(i === shuffledUsernames.length - 3) {
          pair = shuffledUsernames.slice(-3);
          pairs.push(pair);
          break;
      }
      pairs.push(pair);
    }

    const pairsToJSON = JSON.stringify(pairs);

    return pairsToJSON;


  } catch (error) {
    console.log(error);
  }
};

전체적으로 함수 모듈화에 나름 신경을 쓴다고 썼는데, 전역변수를 피하지 못했다.
in-memory로만 페어 명단을 관리하다보니, 서버가 예기치 않은 버그를 만나 재실행된다면, 기존에 /제외 명령어로 빼둔 유저 목록이 다시 리셋될 위험이 있다는 점도 마음에 걸린다.
redis를 붙여서 캐싱도 해보고 싶다.

일단, 슬랙봇 처음 만들어본 걸로 기쁘다.
배포 시 서버 시간이 9시간 이르기 때문에, scheduler에 인자로 전달하는 시간에서 -9를 해주었다.
파이프라인 만들어서 자동화도 해보고 싶다.

'JavaScript > Node.js' 카테고리의 다른 글

node.js로 파일 확장자명에 따라 분류하기  (0) 2022.02.03