mirror of
https://github.com/UltraCoderRU/telebotxx.git
synced 2026-01-28 04:05:13 +00:00
Basic response parsing implemented.
Fixed typo.
This commit is contained in:
parent
96394c3e0d
commit
f58208f864
6 changed files with 168 additions and 12 deletions
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
project(tetebotxx CXX)
|
project(telebotxx CXX)
|
||||||
|
|
||||||
option (TELEBOTXX_BUILD_TESTS "Build unit tests using Boost.Test" ON)
|
option (TELEBOTXX_BUILD_TESTS "Build unit tests using Boost.Test" ON)
|
||||||
option (TELEBOTXX_GENERATE_DOC "Generate API documentation with Doxygen" ON)
|
option (TELEBOTXX_GENERATE_DOC "Generate API documentation with Doxygen" ON)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef TELEBOTXX_BOTAPI_H
|
#ifndef TELEBOTXX_BOTAPI_H
|
||||||
#define TELEBOTXX_BOTAPI_H
|
#define TELEBOTXX_BOTAPI_H
|
||||||
|
|
||||||
|
#include "User.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -14,6 +16,10 @@ namespace telebotxx
|
||||||
|
|
||||||
~BotApi();
|
~BotApi();
|
||||||
|
|
||||||
|
/// \brief Get basic information about the bot
|
||||||
|
/// \return User object with information about the bot
|
||||||
|
User getMe();
|
||||||
|
|
||||||
/// \brief Send text message
|
/// \brief Send text message
|
||||||
/// \param [in] chat chat identifier
|
/// \param [in] chat chat identifier
|
||||||
/// \param [in] text message text
|
/// \param [in] text message text
|
||||||
|
|
|
||||||
36
include/telebotxx/Exception.hpp
Normal file
36
include/telebotxx/Exception.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef TELEBOTXX_EXCEPTION_HPP
|
||||||
|
#define TELEBOTXX_EXCEPTION_HPP
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace telebotxx
|
||||||
|
{
|
||||||
|
class ParseError : public std::invalid_argument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseError(const std::string& message)
|
||||||
|
: std::invalid_argument(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ApiError : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ApiError(int code, const std::string& message)
|
||||||
|
: std::runtime_error(message), code_(code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int getCode() const
|
||||||
|
{
|
||||||
|
return code_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int code_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TELEBOTXX_EXCEPTION_HPP
|
||||||
129
src/BotApi.cpp
129
src/BotApi.cpp
|
|
@ -1,15 +1,82 @@
|
||||||
#include <telebotxx/BotApi.hpp>
|
#include <telebotxx/BotApi.hpp>
|
||||||
|
#include <telebotxx/Exception.hpp>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <rapidjson/document.h>
|
||||||
#include <rapidjson/writer.h>
|
#include <rapidjson/writer.h>
|
||||||
|
#include <rapidjson/istreamwrapper.h>
|
||||||
|
|
||||||
#include <curlpp/cURLpp.hpp>
|
#include <curlpp/cURLpp.hpp>
|
||||||
#include <curlpp/Easy.hpp>
|
#include <curlpp/Easy.hpp>
|
||||||
#include <curlpp/Options.hpp>
|
#include <curlpp/Options.hpp>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
using namespace telebotxx;
|
using namespace telebotxx;
|
||||||
|
|
||||||
|
const rapidjson::Value& parseResponse(const rapidjson::Document& doc)
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
if (!doc.IsObject())
|
||||||
|
throw ParseError("Object expected");
|
||||||
|
|
||||||
|
// Get status
|
||||||
|
if (!doc.HasMember("ok") || !doc["ok"].IsBool())
|
||||||
|
throw ParseError("Field 'ok' not found or has invalid type");
|
||||||
|
bool ok = doc["ok"].GetBool();
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
if (!doc.HasMember("result") || !doc["result"].IsObject())
|
||||||
|
throw ParseError("Field 'result' not found or has invalid type");
|
||||||
|
return doc["result"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!doc.HasMember("error_code") || !doc["error_code"].IsInt())
|
||||||
|
throw ParseError("Field 'error_code' not found or has invalid type");
|
||||||
|
int code = doc["error_code"].GetInt();
|
||||||
|
|
||||||
|
if (!doc.HasMember("description") || !doc["description"].IsString())
|
||||||
|
throw ParseError("Field 'description' not found or has invalid type");
|
||||||
|
std::string description(doc["description"].GetString());
|
||||||
|
|
||||||
|
throw ApiError(code, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
User parseUser(const rapidjson::Value& obj)
|
||||||
|
{
|
||||||
|
if (!obj.HasMember("id") || !obj["id"].IsInt())
|
||||||
|
throw ParseError("Field 'id' not found or has invalid type");
|
||||||
|
int id = obj["id"].GetInt();
|
||||||
|
|
||||||
|
if (!obj.HasMember("first_name") || !obj["first_name"].IsString())
|
||||||
|
throw ParseError("Field 'first_name' not found or has invalid type");
|
||||||
|
std::string firstName(obj["first_name"].GetString());
|
||||||
|
|
||||||
|
std::string lastName;
|
||||||
|
if (obj.HasMember("last_name"))
|
||||||
|
{
|
||||||
|
if (obj["last_name"].IsString())
|
||||||
|
lastName = obj["last_name"].GetString();
|
||||||
|
else
|
||||||
|
throw ParseError("Field 'last_name' has invalid type");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string username;
|
||||||
|
if (obj.HasMember("username"))
|
||||||
|
{
|
||||||
|
if (obj["username"].IsString())
|
||||||
|
username = obj["username"].GetString();
|
||||||
|
else
|
||||||
|
throw ParseError("Field 'username' has invalid type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return User(id, firstName, lastName, username);
|
||||||
|
}
|
||||||
|
|
||||||
class BotApi::Impl
|
class BotApi::Impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -17,8 +84,27 @@ public:
|
||||||
: token_(token)
|
: token_(token)
|
||||||
{
|
{
|
||||||
telegramMainUrl_ = "https://api.telegram.org/bot" + token_;
|
telegramMainUrl_ = "https://api.telegram.org/bot" + token_;
|
||||||
|
botUser_ = getMe();
|
||||||
|
}
|
||||||
|
|
||||||
/// \todo run getMe command to check token
|
inline User getMe()
|
||||||
|
{
|
||||||
|
curlpp::Easy request;
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/getMe"));
|
||||||
|
request.setOpt(new curlpp::Options::Verbose(false));
|
||||||
|
request.setOpt(new curlpp::options::WriteStream(&ss));
|
||||||
|
request.perform();
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << ss.str();
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
IStreamWrapper isw(ss);
|
||||||
|
Document doc;
|
||||||
|
doc.ParseStream(isw);
|
||||||
|
|
||||||
|
return parseUser(parseResponse(doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void sendMessage(const std::string& chat, const std::string& text)
|
inline void sendMessage(const std::string& chat, const std::string& text)
|
||||||
|
|
@ -35,9 +121,11 @@ public:
|
||||||
writer.String(text.c_str());
|
writer.String(text.c_str());
|
||||||
writer.EndObject();
|
writer.EndObject();
|
||||||
|
|
||||||
std::istringstream myStream(s.GetString());
|
std::istringstream requestStream(s.GetString());
|
||||||
std::cout << myStream.str() << std::endl;
|
BOOST_LOG_TRIVIAL(debug) << requestStream.str();
|
||||||
auto size = myStream.str().size();
|
auto size = requestStream.str().size();
|
||||||
|
|
||||||
|
std::stringstream responseStream;
|
||||||
|
|
||||||
// Construct HTTP request
|
// Construct HTTP request
|
||||||
curlpp::Easy request;
|
curlpp::Easy request;
|
||||||
|
|
@ -47,20 +135,33 @@ public:
|
||||||
headers.push_back("Content-Type: application/json");
|
headers.push_back("Content-Type: application/json");
|
||||||
|
|
||||||
// Content-Length
|
// Content-Length
|
||||||
std::ostringstream ss;
|
{
|
||||||
ss << "Content-Length: " << size;
|
std::ostringstream ss;
|
||||||
headers.push_back(ss.str());
|
ss << "Content-Length: " << size;
|
||||||
|
headers.push_back(ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
// Set options
|
// Set options
|
||||||
request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendMessage"));
|
request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendMessage"));
|
||||||
request.setOpt(new curlpp::Options::Verbose(true));
|
request.setOpt(new curlpp::Options::Verbose(false));
|
||||||
request.setOpt(new curlpp::Options::ReadStream(&myStream));
|
request.setOpt(new curlpp::Options::ReadStream(&requestStream));
|
||||||
|
request.setOpt(new curlpp::options::WriteStream(&responseStream));
|
||||||
request.setOpt(new curlpp::Options::InfileSize(size));
|
request.setOpt(new curlpp::Options::InfileSize(size));
|
||||||
request.setOpt(new curlpp::options::HttpHeader(headers));
|
request.setOpt(new curlpp::options::HttpHeader(headers));
|
||||||
request.setOpt(new curlpp::Options::Post(true));
|
request.setOpt(new curlpp::Options::Post(true));
|
||||||
|
|
||||||
// Perform request
|
// Perform request
|
||||||
request.perform();
|
request.perform();
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << responseStream.str();
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
IStreamWrapper isw(responseStream);
|
||||||
|
Document doc;
|
||||||
|
doc.ParseStream(isw);
|
||||||
|
|
||||||
|
/// \todo Parse message
|
||||||
|
parseResponse(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void sendPhoto(const std::string& chat, const std::istream& file, const std::string& caption)
|
inline void sendPhoto(const std::string& chat, const std::istream& file, const std::string& caption)
|
||||||
|
|
@ -80,7 +181,7 @@ public:
|
||||||
|
|
||||||
// Set options
|
// Set options
|
||||||
request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendPhoto"));
|
request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendPhoto"));
|
||||||
request.setOpt(new curlpp::Options::Verbose(true));
|
request.setOpt(new curlpp::Options::Verbose(false));
|
||||||
request.setOpt(new curlpp::options::HttpHeader(headers));
|
request.setOpt(new curlpp::options::HttpHeader(headers));
|
||||||
request.setOpt(new curlpp::Options::Post(true));
|
request.setOpt(new curlpp::Options::Post(true));
|
||||||
|
|
||||||
|
|
@ -90,8 +191,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
std::string token_;
|
std::string token_;
|
||||||
std::string telegramMainUrl_;
|
std::string telegramMainUrl_;
|
||||||
|
User botUser_;
|
||||||
};
|
};
|
||||||
|
|
||||||
BotApi::BotApi(const std::string& token)
|
BotApi::BotApi(const std::string& token)
|
||||||
|
|
@ -101,6 +205,11 @@ BotApi::BotApi(const std::string& token)
|
||||||
|
|
||||||
BotApi::~BotApi() = default;
|
BotApi::~BotApi() = default;
|
||||||
|
|
||||||
|
User BotApi::getMe()
|
||||||
|
{
|
||||||
|
return impl_->getMe();
|
||||||
|
}
|
||||||
|
|
||||||
void BotApi::sendMessage(const std::string& chat, const std::string& text)
|
void BotApi::sendMessage(const std::string& chat, const std::string& text)
|
||||||
{
|
{
|
||||||
return impl_->sendMessage(chat, text);
|
return impl_->sendMessage(chat, text);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
message(STATUS "Configuring telebotxx")
|
message(STATUS "Configuring telebotxx")
|
||||||
|
|
||||||
|
find_package(Boost 1.54 REQUIRED log system)
|
||||||
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
find_package(CURLpp REQUIRED)
|
find_package(CURLpp REQUIRED)
|
||||||
include_directories(${CURLPP_INCLUDE_DIRS})
|
include_directories(${CURLPP_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
|
@ -22,4 +25,5 @@ set(SOURCE_FILES BotApi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(telebotxx SHARED ${SOURCE_FILES})
|
add_library(telebotxx SHARED ${SOURCE_FILES})
|
||||||
target_link_libraries(telebotxx curlpp ${CURL_LIBRARIES})
|
target_link_libraries(telebotxx curlpp ${Boost_LIBRARIES} ${CURL_LIBRARIES})
|
||||||
|
set_property(TARGET telebotxx APPEND PROPERTY COMPILE_DEFINITIONS BOOST_LOG_DYN_LINK)
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ BOOST_AUTO_TEST_SUITE(TestBotApi)
|
||||||
BOOST_AUTO_TEST_CASE(SendMessage)
|
BOOST_AUTO_TEST_CASE(SendMessage)
|
||||||
{
|
{
|
||||||
PRINT_TESTNAME;
|
PRINT_TESTNAME;
|
||||||
|
BOOST_REQUIRE(bot);
|
||||||
BOOST_REQUIRE_NO_THROW(bot->sendMessage(chat, "Hello from C++!"));
|
BOOST_REQUIRE_NO_THROW(bot->sendMessage(chat, "Hello from C++!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue