getUpdates() implemented.

This commit is contained in:
Kirill Kirilenko 2016-11-09 20:28:06 +03:00
parent 5c1f3a3dd0
commit 9da2b2966e
8 changed files with 273 additions and 0 deletions

View file

@ -3,6 +3,7 @@
#include "User.hpp" #include "User.hpp"
#include "Message.hpp" #include "Message.hpp"
#include "Update.hpp"
#include <string> #include <string>
#include <memory> #include <memory>
@ -49,6 +50,13 @@ namespace telebotxx
/// \return Message object, recieved from the server /// \return Message object, recieved from the server
Message sendPhotoUrl(const std::string& chat, const std::string& url, const std::string& caption = ""); Message sendPhotoUrl(const std::string& chat, const std::string& url, const std::string& caption = "");
/// \brief Get updates using long polling
/// \param offset identifier of the first update to be returned
/// \param limit maximum number of updates to be retrieved
/// \param timeout timeout in seconds for long polling
/// \return Updates (vector of Update)
Updates getUpdates(int offset = 0, unsigned short limit = 0, unsigned timeout = 0);
private: private:
class Impl; class Impl;
std::unique_ptr<Impl> impl_; std::unique_ptr<Impl> impl_;

View file

@ -0,0 +1,74 @@
#ifndef TELEBOTXX_UPDATE_HPP
#define TELEBOTXX_UPDATE_HPP
#include "Message.hpp"
#include <vector>
#include <memory>
namespace telebotxx
{
class Update
{
public:
enum class Type
{
Message,
EditedMessage,
InlineQuery,
ChosenInlineResult,
CallbackQuery
};
Update(int id, Type type);
Update(const Update&);
Update(Update&&);
virtual ~Update() = 0;
int getId() const;
Type getType() const;
void swap(Update& other) noexcept;
private:
int id_;
Type updateType_;
};
using UpdatePtr = std::shared_ptr<Update>;
using Updates = std::vector<UpdatePtr>;
class MessageUpdate : public Update
{
public:
MessageUpdate(int id, const Message& message);
MessageUpdate(const MessageUpdate&);
MessageUpdate(MessageUpdate&&);
~MessageUpdate();
const Message& getMessage() const;
void swap(MessageUpdate& other) noexcept;
const MessageUpdate& operator=(MessageUpdate other);
private:
Message message_;
};
class EditedMessageUpdate: public MessageUpdate
{
public:
EditedMessageUpdate(int id, const Message& message);
EditedMessageUpdate(const EditedMessageUpdate&);
EditedMessageUpdate(EditedMessageUpdate&&);
~EditedMessageUpdate();
void swap(EditedMessageUpdate& other) noexcept;
const EditedMessageUpdate& operator=(EditedMessageUpdate other);
};
}
#endif // TELEBOTXX_UPDATE_HPP

View file

@ -131,6 +131,49 @@ public:
return *parseMessage(doc, "result", REQUIRED); return *parseMessage(doc, "result", REQUIRED);
} }
Updates getUpdates(int offset, unsigned short limit, unsigned timeout)
{
// Construct JSON body
using namespace rapidjson;
StringBuffer s;
Writer<StringBuffer> writer(s);
writer.StartObject();
if (offset != 0)
{
writer.String("offset");
writer.Int(offset);
}
if (limit != 0)
{
writer.String("limit");
writer.Uint(limit);
}
if (timeout != 0)
{
writer.String("timeout");
writer.Uint(timeout);
}
writer.EndObject();
std::string request = s.GetString();
auto r = cpr::Post(cpr::Url{telegramMainUrl_ + "/getUpdates"},
cpr::Header{{"Content-Type", "application/json"}},
cpr::Body{request}
);
auto& response = r.text;
if (debugMode)
std::cout << "Response: " << response << std::endl;
rapidjson::Document doc;
doc.Parse(response.c_str());
checkResponse(doc);
return *parseUpdates(doc, "result", REQUIRED);
}
private: private:
std::string token_; std::string token_;
@ -164,3 +207,8 @@ Message BotApi::sendPhotoUrl(const std::string& chat, const std::string& url, co
{ {
return impl_->sendPhotoUrl(chat, url, caption); return impl_->sendPhotoUrl(chat, url, caption);
} }
Updates BotApi::getUpdates(int offset, unsigned short limit, unsigned int timeout)
{
return impl_->getUpdates(offset, limit, timeout);
}

View file

@ -14,6 +14,7 @@ set(SOURCE_FILES Attachment.cpp
JsonObjects.cpp JsonObjects.cpp
Logging.cpp Logging.cpp
Message.cpp Message.cpp
Update.cpp
User.cpp User.cpp
) )

View file

@ -249,6 +249,38 @@ namespace telebotxx
return nullptr; return nullptr;
} }
std::unique_ptr<Update> parseUpdate(const rapidjson::Value& obj)
{
int id = parse<int>(obj, "update_id", REQUIRED);
std::unique_ptr<Message> message;
if (message = parseMessage(obj, "message", OPTIONAL))
return std::make_unique<MessageUpdate>(id, *message);
else if (message = parseMessage(obj, "edited_message", OPTIONAL))
return std::make_unique<EditedMessageUpdate>(id, *message);
/// \todo: other updates
else
throw ParseError("Unknown update type");
}
std::unique_ptr<Updates> parseUpdates(const rapidjson::Value& parent, const char* name, bool required)
{
bool found;
auto& obj = parseArray(parent, name, required, found);
if (found)
{
std::vector<UpdatePtr> updates;
for (auto& elem : obj.GetArray())
{
auto update = parseUpdate(elem);
updates.emplace_back(std::move(update));
}
return std::make_unique<Updates>(std::move(updates));
}
else
return nullptr;
}
std::unique_ptr<User> parseUser(const rapidjson::Value& parent, const char* name, bool required) std::unique_ptr<User> parseUser(const rapidjson::Value& parent, const char* name, bool required)
{ {
bool found; bool found;

View file

@ -3,6 +3,7 @@
#include <telebotxx/Attachment.hpp> #include <telebotxx/Attachment.hpp>
#include <telebotxx/Message.hpp> #include <telebotxx/Message.hpp>
#include <telebotxx/Update.hpp>
#include <telebotxx/User.hpp> #include <telebotxx/User.hpp>
#include <memory> #include <memory>
@ -35,6 +36,13 @@ namespace telebotxx
/// \return pointer to Message /// \return pointer to Message
std::unique_ptr<Message> parseMessage(const rapidjson::Value& parent, const char* name, bool required); std::unique_ptr<Message> parseMessage(const rapidjson::Value& parent, const char* name, bool required);
/// \brief Parse JSON array of Update
/// \param parent reference to parent JSON object
/// \param name field with array of Update objects
/// \param required REQUIRED or OPTIONAL
/// \return Updates (vector of UpdatePtr>
std::unique_ptr<Updates> parseUpdates(const rapidjson::Value& parent, const char* name, bool required);
/// \brief Check JSON response /// \brief Check JSON response
/// ///
/// Throws an exception if error code recieved. /// Throws an exception if error code recieved.

82
src/Update.cpp Normal file
View file

@ -0,0 +1,82 @@
#include <telebotxx/Update.hpp>
using namespace telebotxx;
Update::Update(int id, Type type)
: id_(id),
updateType_(type)
{
}
Update::Update(const Update&) = default;
Update::Update(Update&&) = default;
Update::~Update() = default;
int Update::getId() const
{
return id_;
}
Update::Type Update::getType() const
{
return updateType_;
}
void Update::swap(Update& other) noexcept
{
using std::swap;
swap(id_, other.id_);
swap(updateType_, other.updateType_);
}
////////////////////////////////////////////////////////////////
MessageUpdate::MessageUpdate(int id, const Message& message)
: Update(id, Type::Message),
message_(message)
{
}
MessageUpdate::MessageUpdate(const MessageUpdate&) = default;
MessageUpdate::MessageUpdate(MessageUpdate&&) = default;
MessageUpdate::~MessageUpdate() = default;
const Message& MessageUpdate::getMessage() const
{
return message_;
}
void MessageUpdate::swap(MessageUpdate& other) noexcept
{
using std::swap;
Update::swap(other);
swap(message_, other.message_);
}
const MessageUpdate& MessageUpdate::operator=(MessageUpdate other)
{
swap(other);
return *this;
}
////////////////////////////////////////////////////////////////
EditedMessageUpdate::EditedMessageUpdate(int id, const Message& message)
: MessageUpdate(id, message)
{
}
EditedMessageUpdate::EditedMessageUpdate(const EditedMessageUpdate&) = default;
EditedMessageUpdate::EditedMessageUpdate(EditedMessageUpdate&&) = default;
EditedMessageUpdate::~EditedMessageUpdate() = default;
void EditedMessageUpdate::swap(EditedMessageUpdate& other) noexcept
{
MessageUpdate::swap(other);
}
const EditedMessageUpdate& EditedMessageUpdate::operator=(EditedMessageUpdate other)
{
swap(other);
return *this;
}

View file

@ -131,4 +131,24 @@ BOOST_AUTO_TEST_SUITE(TestBotApi)
BOOST_REQUIRE_NO_THROW(bot->sendPhotoUrl(chat, photoUrl, "Sample caption")); BOOST_REQUIRE_NO_THROW(bot->sendPhotoUrl(chat, photoUrl, "Sample caption"));
} }
BOOST_AUTO_TEST_CASE(GetUpdates)
{
using namespace telebotxx;
PRINT_TESTNAME;
BOOST_REQUIRE(bot);
Updates updates;
BOOST_REQUIRE_NO_THROW(updates = bot->getUpdates());
for (auto update : updates)
{
if (update->getType() == Update::Type::Message)
{
auto& message = std::dynamic_pointer_cast<MessageUpdate>(update)->getMessage();
if (message.getFrom())
std::cout << *message.getFrom() << ": ";
std::cout << message.getText() << std::endl;
}
}
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()