brunch

You can make anything
by writing

- C.S.Lewis -

by 에디의 기술블로그 Mar 17. 2019

Telegram Bot(텔레그램 봇) 만들기

너무 열받아서 개발하게 된 텔레그램 봇

최근에 너무 열받고 짜증나는 일이 있었다. 아직도 진행중이다 가끔씩 너무 짜증나게 만든다.


필자를 너무 열받게 만든 주범은 바로...


.

.

.

.

.

.

.


미세먼지!

미세먼지!!

미세먼지!!!


도대체 우리나라 공기가 왜이러는 걸까? 필자가 어렸을 때는 정말 아무 걱정 없이 뛰어놀 수 있었는데, 지금은 미세먼지가 심한 날은 외출도 하면 안되는 세상이다. 한참 뛰어놀아야 하는 어린이들, 면역력이 약한 어르신들, 심지어는 필자처럼 건강한 젊은 30대 청년(?)들도 외출을 삼가해야 한다는 사실이 너무 화가난다. 그래서, 간단하게 미세먼지 정보를 알려주는 봇을 만들어보기로 한다. 



기술 스펙


빠르게 개발하기 위해서, 필자에게 익숙한 기술 스펙으로 구현하였다. 개발 소요 일정은 주말 2일 정도 투자하였고, 프로토타이핑 목적이기 때무에, 최대한 빠르게 개발하였다. 리팩토링은 아직 진행하지 못했고, 테스트 코드도 거의 작성하지 못하였다.


Spring Boot 2.1.3

Spring Webflux

JDK 1.8, CentOS 7

RabbitMQ

MongoDB (Reactive)

JUnit 5.X

Lombok


Telegram Bot 서버 개발하기


사용자의 메시지에 응답할 수 있는 Telegram Bot 서버를 개발한다.


Telegram Bot 생성하기


개발을 시작하기 전에, 일단 Telegram Bot 을 새로 생성해야 한다. Bot을 생성하는 방법은 아주 쉽다. 


1. BotFather 에게 새로운 Bot 을 생성해달라고 요청한다.

2. 토큰 Key를 기억한다.


BotFather 는 텔레그램의 모든 Bot을 관리하는 관리자 Bot 이다. BotFather 에게 새로운 Bot을 생성해달라고 요청을 할 수 있다. 

BotFather 에게 /start 메시지를 날리면, 사용 가능한 기능을 알려준다. 

새로운 Bot 을 만들기 위해서는 /newbot 명령어를 실행하면 된다. 

필자는 eddykim_bot 이라는 봇을 생성하였다. 이렇게 신규 Telegram Bot을 생성을 하면 토큰키를 알려준다. 토큰키는 Telegram Bot API 서버에서 필요한 정보이다. 




더 자세한 내용은 공식 가이드 문서를 참고하길 바란다.

https://core.telegram.org/bots



Telegram Bot 서버 구축



본격적으로 개발 얘기를 하기 전에, 먼저 드릴 말씀이 있습니다...


"...스프링 부트 개발 경험이 없으시다면... 이 글은 읽지 않으셔도 됩니다... 설명이 친절하지 않습니다..."

"...또한, 코드가 조금 지저분합니다... 그냥 편하게 읽으시는 걸 추천합니다..."


Telegram Bot 서버는 왜 필요한가? 필자가 만든 Telegram Bot 은 친구 등록은 되지만, 메시지에 아무 반응을 하지 않는다. 메시지에 반응하고 대답을 할 수 있는 서버를 구축해야 한다.


1. 익명의 사용자는 Eddykim_bot 을 친구 등록한다. 

2. Eddy Bot 에게 미세먼지 정보를 알려달라고 물어본다.

3. Telegram Bot 서버는 대화를 요청한 익명의 사용자에게 미세먼지 정보를 전달한다. 


Telegram Bot 서버를 개발하는 방법은 여러가지 방법이 있는데, 필자는 스프링&자바 환경으로 빠르게 개발하였다. 필자가 사용한 Telegram Java 라이브러리는 아래와 같다. 

https://github.com/rubenlagus/TelegramBots

https://mvnrepository.com/artifact/org.telegram/telegrambots/4.1.2


참고로, 사실 필자는 예전에도 Telegram Bot을 간단하게 만들어본 경험이 있다. 당시에는, Node.js 로 개발하였고 30분만에 개발할 수 있을 정도로 아주 간편하게 구현했었다. 이 글을 읽는 분중에서 Telegram Bot을 빠르게 개발하고 싶다면, Node.js 로 개발하는 것을 추천한다. NPM 라이브러리가 많으니 잘 선택해서 구현하면 된다. 필자는 자바&스프링 공부 중이라서 자바 기반의 라이브러리를 사용하겠다. 


실제 구현 연동

필자는 스프링 부트 Gradle 5.x, Java1.8, 2.1.3.RELEASE 환경으로 개발하겠다. 아래와 같이 build.gradle 파일에 Telegram Bot 라이브러리 디펜던시를 추가한다. 참고로, 해당 캡쳐 화면은 필자가 개발을 모두 완료한 이후에 캡쳐를 했기 때문에 다른 디펜던시도 많이 추가가 된 상황이다. 일단... 이 글을 읽는 분들은 코드는 자세히 안봐도 된다. 이런식으로 했다 정도만 이해해주길 바란다.

Telegram bot 서버를 개발하기 위해서, Bot의 UserName 과 토큰 키를 사용해야 한다. 프로퍼티 파일에 아래와 같이 작성한다.

자 그리고, @Component 를 하나 생성한다. 해당 컴포넌트는 Telegram Message 에 응답을 하는 핵심 로직이 포함되어 있다.

그리고, 해당 컴포넌트에 Telegram Bot 을 초기화 하는 로직을 추가해야 한다. 간단하게 개발하는 과정에서 아래와 같이 구현할 수 있다. 물론... 리팩토링이 필요하지만, TelegramLongPollingBot 이라는 추상클래스를 구현해줘야 한다. 

getBotUsername() 와 getBotToken() 메서드에서는 반드시 Telegram Bot 의 Username, Token Key 정보를 리턴해줘야 한다. 그래서, 아래와 같이 변경을 한다.

메시지를 받고, 응답을 하는 로직은 onUpdateReceived() 메서드에 구현을 하면 된다. 

필자는 SendMessage 객체를 사용할 것이다. 메시지를 보내는 타입(?)은 여러가지가 있다. 필자가 구현한 SendMessage 는 단순 문자 메시지를 보내는 방식인데, 라이브러리를 까서 보니깐 기타 여러가지 방식이 많이 있었다. 참고로, enableHtml(true) 설정을 했는데... 이 설정을 하면 html 구문도 같이 포함해서 전달할 수 있다. 하지만 전달 가능한 태그는 몇개 안된다. <a> 태그는 잘 되지만, 아마도 <div> 태그를 전달하면 오류가 발생할 것이다. 지원하는 태그 종류는 몇개 있는데 필자가 외우지는 못한다. 암튼, 전달할 수 있는 메시지 타입은 종류가 많은데 아래와 같이 라이브러릴 코드를 보면 알 수 있다. 

문서, 오디오, 이미지, 애니메이션, 동영상 등등 여러가지 방법으로 메시지를 전송할 수 있다. 필자는 단순 메시지 전송 방식을 사용할 것이고, 메시지 전송은 message.setChatId에 반드시 ChatId를 설정해야 한다.

ChatID를 설정하는 이유는, 메시지를 주고받는 대상에게 보내기 위해서이다. 아무 관련없는 사람에게 메시지를 보내면 안된다. 이런식으로 개발하면 Telegram Bot 서버를 구축할 수 있다. 코드가 깔끔하지는 않지만 관심있는 개발자는 참고하길 바란다. 


정리


사실 비하인드 스토리를 얘기하자면... 원래 계획은 카카오톡 플러스 친구 챗봇을 구현할려고 했었다. 카카오톡 플러스 친구 챗봇이 예전에는 커스텀(필자가 구현한) API 를 등록할 수 있었는데, 얼마전에 그 기능이 종료가 되었다........... 안타깝다. ㅠㅠ  


암튼, 간단하게 Telegram Bot 서버를 구축하였는데, 이제 미세먼지 정보를 수집해서 Telegram Bot 에서 미세먼지 정보를 응답할 수 있도록 구현해보자. 



미세먼지 정보 수집 서버 개발하기


공공데이터를 사용해서 미세먼지를 조회한다.


공공데이터포털


필자는 공공데이터포털에서, 대기오염정보 조회 서비스 정보를 사용할 것이다. 무료로 사용할 수 있지만, Call 수 제한이 있다. 운영계정으로 심의를 받으면 호출 콜 수를 늘릴 수 있다. 필자는 그냥 개발계정으로 사용하였다.

https://www.data.go.kr/dataset/15000581/openapi.do

공공데이터 사용 방법에 대해서는 따로 설명하지 않겠다. 



데이터 수집 서버 개발


데이터를 수집 배치 서버를 개발한다. 데이터 수집 서버의 역할은 미세먼지 정보를 주기적으로 수집하고, 수집한 정보를 저장한다. 또한, Telegram Bot에게 업데이트 정보를 전달한다. 아키텍처는 아주 심플한데, 필자가 선호하는 메시지 패턴 기반의 분산 시스템이다. 메시지 패턴으로 구현하였기 때문에, Subscriber 는 Telegram Bot 뿐만 아니라, 다른 클라이언트도 등록할 수 있다. 즉, 확장하기 쉽다. 


실제 구현 연동

데이터 수집 서버 역시 스프링 부트 기반으로 개발한다. 

미세먼지 데이터를 매핑하는 dto 클래스를 정의한다. 

자세한 코드는 생략

공공 데이터 API를 호출하여, 리턴받은 데이터를 Air 클래스에 매핑한다. 그리고, 매핑된 데이터를 업데이트 하는 로직으로 전달한다. 

데이터 업데이트 메서드에서는, NoSQL 서버(MongoDB)에 저장한다. MongoDB에 저장한 데이터 샘플은 아래와 같다.


미세먼지 정보가 업데이트 되면, Telegram Bot 서버가 최신 데이터를 조회할 수 있도록, 메시지 브로커(RabbitMQ)에 업데이트 신호를 전달한다. 전달하는 코드는 아래오 ㅏ .같다. 

업데이트 신호를 전달 받은 Telegram Bot 은 신규 미세먼지 데이터를 업데이트한다. Telegram Bot 서버에서는 아래와 같이 메시지 수신 기능을 추가한다.

RabbitMQ 관리툴을 통해서, 메시지가 정상적으로 전달되는지 확인할 수 있었다. 


추가로, 미세먼지 정보는 10분에 한번 주기로 수집하도록 스케쥴을 정의하였다. 

공공데이터를 조회할 수 있는 콜수가 개발계정은 하루 500번 밖에 안된다. 그래서, 부득이하게 10분에 한번 조회하는 로직으로 구현하였다. 


테스트


개발을 완료하고 테스트를 진행하였다. 근데, 문제가 생겼다. 개인 대화는 정상적으로 응답을 하는데, 그룹에 초대했을 때는 아무 답변을 하지 않았다. 이유는 Telegram Bot 의 정책 때문이었다. 그룹채팅인 경우에는, Telegram Bot 에게 메시지를 보낼 때는 를 포함해서 메시지를 전송해야 한다. Telegram Bot 보안 정책때문이다. 

서초구 미세먼지로 메시지를 보내면, 보안 정책으로 응답을 하지 않는다. 그래서 /를 붙여서 /서초구 미세먼지로 메시지를 전송하였고, 정상적으로 미세먼지 정보를 응답하였다. 현재 3월17일 11시 기준으로 미세먼지는 보통, 초미세먼지 보통, 통합대기지수 보통 이라는 것을 알 수 있다. 


참고로 필자는 서울시 정보만 구현하였다. 조회가 가능한 정보는 아래와 같다. 


/강남구 미세먼지

/서초구 미세먼지

/종로 미세먼지

/용산구 미세먼지

/성동구 미세먼지

/관악구 미세먼지

/한강대로 미세먼지

/구로구 미세먼지

등등..40개 정도 데이터이다. 귀찮아서 다 작성하지는 않겠다. 



글 마무리


이정도로 마치고 글을 마무리하겠다. 모든 코드를 상세하게 내용을 작성할 수는 없었다. 프로토타입 수준으로 개발했기 때문에, 기능은 아주 심플하다. 하지만, 개발을 하다 보니깐, 조금 재미가 생겨서 이것저것 기능을 추가해볼까 고민중이다. 미세 먼지 외에 재미난 기능을 추가해보면 좋을 것 같다. 허접한 개발이지만 혹시라도 관심있는 개발자는 github 의 코드를 한번 보길 바란다.


https://github.com/sieunkr/bot


매거진의 이전글 Redis & Spring API 성능 테스트

매거진 선택

키워드 선택 0 / 3 0

댓글여부

afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari
브런치 시작하기

카카오계정으로 간편하게 가입하고
좋은 글과 작가를 만나보세요

카카오계정으로 시작하기
페이스북·트위터로 가입했다면