yatbcpp  0.0.1
Yet another Telegram Bot CPP Library
Bot.cc
Go to the documentation of this file.
1 //
2 // Created by norbert on 12.08.17.
3 //
4 
5 #include <iostream>
6 #include <functional>
7 #include <thread>
8 #include <condition_variable>
9 #include <vector>
10 #include <queue>
11 #include <curl/curl.h>
12 
13 #include "exceptions/curl_error.h"
15 #include "types/telegram_type.h"
16 #include "methods/getMe.h"
17 #include "types/User.h"
18 #include "types/Update.h"
19 
20 #include "bot/Bot.h"
21 
22 #include "methods/sendMessage.h"
23 
24 using namespace yatbcpp;
25 using namespace std;
26 
28 // Constructor Section //
30 
31 Bot::Bot(Token& T) : token(T), isPolling(false){
32 // isPolling=false;
33 // cout << T.getToken() << endl;
34 }
35 
37 // Util Section //
39 
44 void Bot::join(){
45  Polling.join();
46  Updating.join();
47 }
48 
60 static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *stringptr){
61  ((string*)stringptr)->append((char*)contents, size * nmemb);
62  return size * nmemb;
63 }
64 
66 // Polling Section //
68 
73  this->startLongPoll(100);
74 }
75 
76 void Bot::startLongPoll(long timeout) {
77  if(!(timeout <0 || timeout >200)){
78  //timeout is out of telegram usable range, 0 for shortpolling
79  }
80  if(this->isPolling){
81  //throw bot is polling
82  }
83  this->isPolling=true;
84  Polling = std::thread(&Bot::LongPolling,this,timeout);
85 }
86 
88  if(!this->isPolling){
89  //Bot has already stopped
90  }
91  this->isPolling=false;
92  this->Polling.join();
93 }
94 
95 void Bot::LongPolling(long timeout){
96  if(!(timeout <0 || timeout >200)){
97  //timeout is out of telegram usable range, 0 for shortpolling
98  }
99 // int retrys_availlable=5;
100  CURL* curl = curl_easy_init();
101  Json::Reader reader;
102  string readBuffer;
103  string apiURL("https://api.telegram.org/bot"+token.getToken()+"/getUpdates");
104  curl_easy_setopt(curl,CURLOPT_URL,apiURL.c_str());
105  curl_easy_setopt(curl,CURLOPT_TIMEOUT, timeout);//100 sekunden?
106  curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,WriteCallback);
107  curl_easy_setopt(curl,CURLOPT_WRITEDATA,&readBuffer);
108  CURLcode res = CURLE_OK;
109  Update last(0);//Latest Dummy Update
110  do{
111  string offset("timeout="+to_string(timeout)+"&offset="+to_string(last.getUpdate_id()+1));// No NEed to get them again
112  curl_easy_setopt(curl,CURLOPT_POSTFIELDS,offset.c_str());
113  res = curl_easy_perform(curl);
114  Json::Value Response;
115  reader.parse(readBuffer,Response);
116  if(Response["ok"].asBool()){
117  // parse string, and enque updates
118  unique_lock<mutex> lock(m);
119  for(int i=0;i<Response["result"].size();i++){
120  Json::Value Update_json;
121  Update_json = Response["result"][i];
122  Update update = fromJson<Update>(Update_json);
123  pendingUpdates.push(update);
124  pendingUpdatesAvailable.notify_one();
125  last = update;
126  }
127  }
128  else{
129  cerr << "Response was not ok" << readBuffer << endl;
130  curl_easy_cleanup(curl);
131  throw telegram_api_error(Response["error_code"].asInt(),Response["description"].asString());
132  }
133  readBuffer.clear();
134  Response.clear();
135  }
136  while(isPolling && !res);
137  if(res != CURLE_OK){
138  throw curl_error(res,curl_easy_strerror(res));
139 // cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << endl;
140  }
141  curl_easy_cleanup(curl);
142 }
143 
144 
146 // Update Notify Section //
148 
150  this->isUpdating=true;
151  Updating = std::thread(&Bot::NotifyRegisteredListeners,this);
152 
153 }
154 
156  this->isUpdating=false;
157  this->Updating.join();
158 }
159 
161  //todo not check whom all wants, pre check then notify
162 
163  std::unique_lock<std::mutex> lock(m);
164  while(isUpdating)
165  {
166  pendingUpdatesAvailable.wait(lock);
167  while(!pendingUpdates.empty()){
168 // cout << "Removing From Queue";
169  Update U = pendingUpdates.front();
170  //On Update Listeners
171  for(function<void(Update)> L: OnUpdateListeners){
172  L(U);
173  }
174  //On Message Listeners
175  for(function<void(Message)> L: OnMessageListener){
176  if(U.getMessage()){
177  L(U.getMessage().value());
178  }
179  }
180 
181  //On Message Edited
182  if(U.getEdited_message()){
183  for(function<void(Message)> L: OnMessageEditedListener){
184  L(U.getEdited_message().value());
185  }
186  }
187  //On Channel Post
188  for(function<void(Message)> L: OnChannelPostListener){
189  if(U.getChannel_post()){
190  L(U.getChannel_post().value());
191  }
192  }
193  //On Channel Post Edited
194  for(function<void(Message)> L: OnChannelPostEditedListener){
195  if(U.getEdited_channel_post()){
196  L(U.getEdited_channel_post().value());
197  }
198  }
199  //On Inline Query
200  if(U.getInlineQuery()){
201  for(function<void(InlineQuery)> L: OnInlineQueryListener){
202  L(U.getInlineQuery().value());
203  }
204  }
205  pendingUpdates.pop();
206  }
207  }
208 }
209 
211 // Callback Section //
213 
214 
215 void Bot::addOnUpdateListener(function<void(Update)> Listener) {
216  OnUpdateListeners.push_back(Listener);
217 }
218 void Bot::addOnMessageBotCommandListener(std::function<void(Message,MessageEntity)> Listener) {
219  OnMessageCommandListener.push_back(Listener);
220 }
221 
222 void Bot::addOnMessageListener(std::function<void(Message)> Listener) {
223  OnMessageListener.push_back(Listener);
224 }
225 
226 void Bot::addOnMessageEditedListener(function<void(Message)> Listener) {
227  OnMessageEditedListener.push_back(Listener);
228 }
229 
230 void Bot::addOnChannelPostListener(function<void(Message)> Listener) {
231  OnChannelPostListener.push_back(Listener);
232 }
233 
234 void Bot::addOnChannelPostEditedListener(std::function<void(Message)> Listener) {
235  OnChannelPostEditedListener.push_back(Listener);
236 }
237 
238 void Bot::addOnInlineQueryListener(std::function<void(InlineQuery)> Listener) {
239  OnInlineQueryListener.push_back(Listener);
240 }
241 
243 // "Outgoing" Section //
245 
246 const User Bot::getMe() const {
247  auto GM = yatbcpp::getMe();
249  return u;
250 }
251 
252 
253 const Message Bot::send(sendMessage sm) const{
255 
256 }
std::int32_t getUpdate_id() const
Definition: Update.cc:56
void stopUpdating()
Definition: Bot.cc:155
void startUpdating()
Definition: Bot.cc:149
std::vector< std::function< void(InlineQuery)> > OnInlineQueryListener
Definition: Bot.h:90
void addOnMessageListener(std::function< void(Message)> Listener)
Definition: Bot.cc:222
const User getMe() const
Definition: Bot.cc:246
std::mutex m
Definition: Bot.h:80
std::vector< std::function< void(Message)> > OnMessageListener
Definition: Bot.h:86
const std::optional< Message > & getEdited_message() const
Definition: Update.cc:64
std::vector< std::function< void(Message)> > OnChannelPostEditedListener
Definition: Bot.h:89
void addOnMessageEditedListener(std::function< void(Message)> Listener)
Definition: Bot.cc:226
void addOnUpdateListener(std::function< void(Update)> Listener)
Definition: Bot.cc:215
std::vector< std::function< void(Update)> > OnUpdateListeners
Definition: Bot.h:84
void addOnChannelPostListener(std::function< void(Message)> Listener)
Definition: Bot.cc:230
bool isUpdating
Definition: Bot.h:75
bool isPolling
Definition: Bot.h:74
void addOnChannelPostEditedListener(std::function< void(Message)> Listener)
Definition: Bot.cc:234
std::queue< Update > pendingUpdates
Definition: Bot.h:81
Definition: Bot.h:27
void NotifyRegisteredListeners()
Definition: Bot.cc:160
void join()
Definition: Bot.cc:44
void stopLongPoll()
Definition: Bot.cc:87
std::thread Polling
Definition: Bot.h:71
std::condition_variable pendingUpdatesAvailable
Definition: Bot.h:82
std::vector< std::function< void(Message)> > OnChannelPostListener
Definition: Bot.h:88
const Message send(sendMessage sendMessage) const
Definition: Bot.cc:253
static RETURNTYPE perform_requestJSON(Token T, telegram_methodJSON< RETURNTYPE > &method_body)
std::vector< std::function< void(Message)> > OnMessageEditedListener
Definition: Bot.h:87
std::vector< std::function< void(Message, MessageEntity)> > OnMessageCommandListener
Definition: Bot.h:85
const std::optional< Message > & getMessage() const
Definition: Update.cc:60
const std::optional< InlineQuery > & getInlineQuery() const
Definition: Update.cc:76
Bot(Token &T)
Definition: Bot.cc:31
const std::optional< Message > & getChannel_post() const
Definition: Update.cc:68
void addOnMessageBotCommandListener(std::function< void(Message, MessageEntity)> Listener)
Definition: Bot.cc:218
const Token token
Definition: Bot.h:67
const std::optional< Message > & getEdited_channel_post() const
Definition: Update.cc:72
void addOnInlineQueryListener(std::function< void(InlineQuery)> Listener)
Definition: Bot.cc:238
void startLongPoll()
Definition: Bot.cc:72
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *stringptr)
Definition: Bot.cc:60
const std::string getToken() const
Definition: Token.cc:23
void LongPolling(long timeout)
Definition: Bot.cc:95
std::thread Updating
Definition: Bot.h:72