작년에 클라이언트 프로그램에서 이슈가 발생했을 때 사용자에게 문자를 보내줘야하는 기능을 개발 해야했는데
SMS는 돈주고 사야하므로 유료이므로 난 그럴 능력이 없으므로 텔레그램 봇을 개발했었다.
그때는 "NetTelegramBotApi"라는 라이브러리를 사용해 개발을 했었는데
지금 글을 쓰려고 다시 찾아보니 Nuget에 더 좋은 라이브러리가 있었다.
"NetTelegramBotApi"는 패스
Nuget에서 telegram을 검색하면 제일 위에 나오는 "Telegram.Bot"라이브러리를 써보자.
<- 요놈 받으면 된다.
일단 개발해보기에 앞서 Telegram Bot을 만들려면 API access 키를 발급 받아야 한다.
어려울거 하나 없다.
핸드폰 보랴 모니터 보랴 왔다갔다 하지말고 https://web.telegram.org/ 에 들어가서 봇을 추가하자.
1. BotFather를 찾아라.
BotFather를 클릭하면 아래와 같이 화면이 바뀐다.
Start 버튼을 클릭하자.
그럼, 봇아빠가 알아듣는 커맨드가 쭈루룩 나온다. 그걸 잘 읽어보면 봇을 만들 수 있다.
2. Bot을 추가해라.
봇아빠에게 /newbot 이라고 입력하자.
그럼 이름을 말하라고 한다.
원하는 봇의 이름을 입력하자.
주의할점은 끝에 _bot 또는 Bot이 꼭 들어가야 한다. 안그러면 안만들어쥼
이름을 잘 입력해서 만들면 access token을 바로 똭하고 준다.
/// 그 외 다양한 커맨드가 있으니 한번씩 해보세요. 재밌어요.
3. Access Token을 받아 개발을 해보자.
그럼 access token을 복사해서 봇을 만들어 보자.
* 참고
Telegram 홈페이지 Telegram Bot API : Telegram API Doc
Telegram.Bot 라이브러리 도큐먼트 : Telegram.Bot dll Doc
Telegram.Bot 라이브러리 예제 : Telegram.Bot Example << 예제를 보면 다양한 케이스가 많다. 사진, 음성, 위치접근, 연락처, 등등
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////만들어 보자
나는 C# 콘솔 응용 프로그램 으로 만들었다.
class Program { static void Main(string[] args) { /// 봇 접근 함수 호출 testAPIAsync(); Console.ReadLine(); } /// 비동기 봇 접근 static async void testAPIAsync() { var Bot = new Telegram.Bot.TelegramBotClient("봇 아빠가 준 access token을 넣어요."); var me = await Bot.GetMeAsync(); // 올바르게 접속이 되면 봇 이름이 출력된다. System.Console.WriteLine("Hello my name is " + me.FirstName); } }
위 소스를 실행 하면 다음과 같은 결과 화면을 볼 수 있다.
간단하게 봇을 실행 시키는 것까지 성공했다.
하지만 내가 해야할 것은 이벤트가 생겼을 때 telegram 봇이 사용자에게 메세지를 전송 하거나,
사용자로 부터 명령을 받아 DB를 바꾼다던지, DB를 조회해 정보를 보여준다던지 등의 작업을 해야한다.
아래 소스를 하나씩 따라가보자.
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; ///텔레그램 dll using using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; namespace telegram { class Program { //봇 생성 private static readonly TelegramBotClient Bot = new TelegramBotClient("봇 아빠가 준 access token을 넣어요."); //임시방편 유저 리스트 private static List<User> Users = new List<User>(); //telegram 사용자의 상태 저장 변수 private static Dictionary<long, UserState> dicUserState = new Dictionary<long, UserState>(); static void Main(string[] args) { ///임시방편 유저 리스트에 유저 추가 Users.Add(new User("시나공공", 28)); //28살이다...ㅁㄴ아ㅓㄹ ㅓㅁㄴ아ㅣㄹ허 님 Users.Add(new User("텔레그램", 30)); Users.Add(new User("봇아빠", 55)); ///봇 이벤트 추가 Bot.OnMessage += Bot_OnMessage; Bot.OnMessageEdited += Bot_OnMessage; Bot.OnReceiveError += Bot_OnReceiveError; ///Me 획득 (Me가 뭔지 정확하게는.... 일단 눈치껏 보면 Username에 sinagonggongBot이 들어가는걸 보면 Bot 본인을 뜻하는 듯하다) var me = Bot.GetMeAsync().Result; Console.Title = me.Username; /// Recv Start Bot.StartReceiving(); Console.ReadLine(); /// Recv Stop Bot.StopReceiving(); } /// Recv Error private static void Bot_OnReceiveError(object sender, Telegram.Bot.Args.ReceiveErrorEventArgs e) { Debugger.Break(); } ///사용자로 부터 Message Recv private static async void Bot_OnMessage(object sender, Telegram.Bot.Args.MessageEventArgs messageEventArgs) { /// Message 객체 var message = messageEventArgs.Message; /// 예외처리 if (message == null || message.Type != MessageType.TextMessage) return; /// "/사용자추가" 라는 명령을 받음 if (message.Text.StartsWith("/사용자추가")) { dicUserState[message.Chat.Id] = UserState.addUser; await Bot.SendTextMessageAsync(message.Chat.Id, @"사용자 이름과 나이를 입력해 주세요. ex)시나공공,28"); } /// "/사용자삭제" 라는 명령을 받음 else if (message.Text.StartsWith("/사용자삭제")) { dicUserState[message.Chat.Id] = UserState.deleteUser; await Bot.SendTextMessageAsync(message.Chat.Id, "사용자 이름을 입력해 주세요."); } /// "/사용자목록" 라는 명령을 받음 else if (message.Text.StartsWith("/사용자목록")) { dicUserState[message.Chat.Id] = UserState.none; string _message = string.Empty; Users.ForEach(x => _message += string.Format("이름 : {0}, 나이 : {1}\r\n", x.Name, x.Age) ); await Bot.SendTextMessageAsync(message.Chat.Id, _message); } /// "/도움말" 라는 명령을 받음 else if(message.Text.StartsWith("/도움말")) { var usage = @" /사용자추가 - 사용자 추가 /사용자삭제 - 사용자 삭제 /사용자목록 - 사용자 목록 /도움말 - 도움말 "; await Bot.SendTextMessageAsync(message.Chat.Id, usage, replyMarkup: new ReplyKeyboardHide()); } /// 그 외 다른 말을 받을 경우 사용자 상태를 보고 적절하게 대응한다. else { /// 예외처리 if(!dicUserState.ContainsKey(message.Chat.Id)) { await Bot.SendTextMessageAsync(message.Chat.Id, "먼 말인지 모르겠어요."); return; } /// 사용자 상태가 사용자 추가일 경우 if (dicUserState[message.Chat.Id] == UserState.addUser) { /// 이름,나이 로 입력을 받을 것이기 때문에 , 로 tokenizing하자 /// 0번은 이름, 1번은 나이 string[] NameAndAge = message.Text.Split(','); /// 쪼갰는데 개수가 2보다 작으면 잘못된 값을 받았다 판단 if (NameAndAge.Length < 2) { await Bot.SendTextMessageAsync(message.Chat.Id, @"다시 입력해 주세요. ex)시나공공, 28"); return; } /// 이름 나이 셋팅 string _name = NameAndAge[0]; int _age = 0; bool result = Int32.TryParse(NameAndAge[1], out _age); /// 나이값이 정상이면 추가 if(result) { // DB작업을 해야한다면 여기서 하면 될것같다. Users.Add(new User(_name, _age)); await Bot.SendTextMessageAsync(message.Chat.Id, message.Text + " 사용자를 추가 했어요."); dicUserState[message.Chat.Id] = UserState.none; } /// 나이값이 이상하면 예외 else { await Bot.SendTextMessageAsync(message.Chat.Id, @"나이가 이상해요. 다시 입력해 주세요."); } } /// 사용자 상태가 사용자 삭제일 경우 else if(dicUserState[message.Chat.Id] == UserState.deleteUser) { /// SingleOfDefault로 사용자를 찾았는데 없으면 예외처리 있으면 삭제 var _user = Users.SingleOrDefault(x => x.Name == message.Text); if (_user != null) { // DB작업을 해야한다면 여기서 하면 될것같다. Users.Remove(_user); await Bot.SendTextMessageAsync(message.Chat.Id, message.Text + " 사용자를 삭제 했어요."); dicUserState[message.Chat.Id] = UserState.none; } else { await Bot.SendTextMessageAsync(message.Chat.Id, message.Text + @" 사용자가 없어요. 다시 입력해 주세요."); } } /// 사용자 상태가 추가, 삭제가 아닌 경우 시치미 뚝 else { await Bot.SendTextMessageAsync(message.Chat.Id, "먼 말인지 모르겠어요."); } } } } /// <summary> /// 사용자를 상태를 나타내는 enum /// </summary> public enum UserState { addUser, deleteUser, none } /// <summary> /// 사용자 클래스, 이름과 나이 /// </summary> public class User { string name = string.Empty; public string Name { get { return name; } set { name = value; } } int age = 0; public int Age { get { return age; } set { age = value; } } public User() : this("none", 0) { } public User(string name, int age) { this.Name = name; this.Age = age; } } }
이렇게 하면 아래와 같은 결과를 볼 수 있다.
봇에게 말을 걸려면 봇아빠에게 말을 걸었던것과 같이 하면 된다.
나의 경우 @sinagonggongBot을 검색해 대화를 시작했다.
Telegram Bot을 이용해 간단하게 요청을 하고 응답을 받는 서비스를 만들어봤다.
네이버나 다음의 API를 섞어서 사용하거나, 나름의 알고리즘으로 유용한 봇을 만들 수 있을 것 같다.
아 5초마다 이벤트 발생시켜서 사용자한테 메세지 보내는걸 까먹었네. 그건 패스할게요... 귀찮...
키포인트는 Message.Chat.Id를 잘 보관해야 한다.
작년 개발 당시 Message.Chat.Id를 로그인 DB에 컬럼을 추가해 같이 저장해 이용했다.
이슈가 생겼을 때 DB의 TelegramID를 조회해 sendMessage를 했었다.
Group Chat방에 메세지를 보낼땐 https://stackoverflow.com/a/45577773 참조 바랍니다. (Group Chat ID 얻어오기 Tip)
끝.
'Programming > 기타' 카테고리의 다른 글
HMAC SHA-256 암호화 (C#, Javascript, Nodejs) (9) | 2018.08.28 |
---|---|
noVNC (597) | 2017.01.02 |