간혹 자동으로 돌아가는 데몬같은 프로그램에서 알림 메세지를 전송 받아야 하는 경우가 있는데
텔레그램 봇을 생성하고 메세지를 전송하는 방법에 대해 알아보겠습니다.
텔레그램에서 @Botfather를 검색해서 대화를 시작합니다.
대화를 시작하고 /newbot를 입력하거나 선택합니다.
봇의 이름을 지정합니다.
봇 이름 끝에는 반드시 bot이 들어가야된다고 합니다.
이미 만들어진 이름은 사용할 수 없습니다.
봇 이름이 정해지면 HTTP API 엑세스 토큰이 발급됩니다.
봇이 만들어졌으면 먼저 그룹을 만듭니다.
그 다음 만든 봇 이름을 검색해서 채팅을 시작하고 그룹에 추가 버튼으로 이전에 만든 그룹에 초대하고
아무 채팅이나 입력해서 대화방을 활성화 합니다.
그 다음 브라우저에 아래와 같이 입력하여 chat id를 확인합니다.
https://api.telegram.org/bot79804.../getUpdates
(bot 뒷부분에는 토큰을 입력합니다)
응답 중 "chat":{"id":440.., 이 부분이 chat id입니다.
그럼 이제 아래와 같이 입력하면 봇이 메세지를 전송합니다.
https://api.telegram.org/bot<토큰>/sendMessage?chat_id=<채팅ID>&text=Hello
이제 MFC프로젝트에서 위의 기능을 API로 전송하는 방법을 알아보겠습니다.
1. WinHttp방식
#include <windows.h>
#include <winhttp.h>
#pragma comment(lib, "winhttp.lib")
void CtelebotDlg::SendTelegramMessage(CString token, CString chatId, CString message)
{
CString host = _T("api.telegram.org");
CString path;
path.Format(_T("/bot%s/sendMessage?chat_id=%s&text=%s"),
token, chatId, message);
HINTERNET hSession = WinHttpOpen(L"MFC Telegram Bot/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) return;
HINTERNET hConnect = WinHttpConnect(hSession, host, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!hConnect) { WinHttpCloseHandle(hSession); return; }
HINTERNET hRequest = WinHttpOpenRequest(
hConnect,
L"GET",
path,
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
if (hRequest)
{
BOOL bResult = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
if (bResult) {
bResult = WinHttpReceiveResponse(hRequest, NULL);
}
WinHttpCloseHandle(hRequest);
}
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
}
2. CHttpFile 방식
#include <memory>
#include <afxinet.h>
void CtelebotDlg::SendTelegramMessage(CString token, CString chatId, CString message)
{
try
{
CInternetSession session(_T("MFC Telegram Bot"), 1, INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, INTERNET_FLAG_SECURE);
CString urlPath = _T("/bot") + token + _T("/sendMessage");
CString server = _T("api.telegram.org");
std::string utf8ChatId = CStringToUTF8(chatId);
std::string utf8Message = CStringToUTF8(message);
std::string encodedChatId = UrlEncode(utf8ChatId);
std::string encodedMessage = UrlEncode(utf8Message);
CStringA postData;
postData.Format("chat_id=%s&text=%s", encodedChatId.c_str(), encodedMessage.c_str());
std::unique_ptr<CHttpConnection> pConnection(
session.GetHttpConnection(server, INTERNET_DEFAULT_HTTPS_PORT, _T(""), _T(""))
);
std::unique_ptr<CHttpFile> pFile(
pConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, urlPath, nullptr, 1, nullptr, nullptr, INTERNET_FLAG_SECURE)
);
CString headers = _T("Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n");
pFile->AddRequestHeaders(headers);
pFile->SendRequest(nullptr, 0, (LPVOID)(LPCSTR)postData, postData.GetLength());
CString response;
CHAR buffer[1024];
UINT bytesRead;
while ((bytesRead = pFile->Read(buffer, sizeof(buffer) - 1)) > 0)
{
buffer[bytesRead] = '\0';
response += buffer;
}
pFile->Close();
pConnection->Close();
}
catch (CInternetException* pEx)
{
TCHAR error[1024];
pEx->GetErrorMessage(error, 1024);
AfxMessageBox(_T("Error: ") + CString(error));
pEx->Delete();
}
}
std::string CtelebotDlg::CStringToUTF8(const CString& str)
{
int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr);
std::string utf8Str(len, 0);
WideCharToMultiByte(CP_UTF8, 0, str, -1, &utf8Str[0], len, nullptr, nullptr);
return utf8Str;
}
std::string CtelebotDlg::UrlEncode(const std::string& str)
{
std::string encoded;
for (unsigned char c : str)
{
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
encoded += c;
else
{
char buf[4];
sprintf_s(buf, "%%%02X", c);
encoded += buf;
}
}
return encoded;
}
WinHttp와 CHttpFile을 사용한 소스입니다.
응답이 빠른편은 아니고 전송이 안되는 환경에서는 먹통이되니
가급적 스레드로 구현하는 것이 좋아보입니다.
댓글