smertig / banana Goto Github PK
View Code? Open in Web Editor NEW๐ Modern C++ Telegram Bot API library
Home Page: https://smertig.github.io/banana/master
License: MIT License
๐ Modern C++ Telegram Bot API library
Home Page: https://smertig.github.io/banana/master
License: MIT License
There are various reasons when sending requests are gonna fail - the idea of this suggestion is allowing low-level retries/timeouts for HTTP requests if possible on the bundle.
Also, I noticed, that SSL is enabled in boost::beast by default, though disabled in CPR (the CPR allows it) - uniform behavior is expected, in my opinion. Enabling/disabling SSL configurations will be a valuable addition.
When creating the connector, one can specify those connection parameters.
connector::cpr_blocking_monadic connector(token); // for simple usage as it's now
connector::cpr_blocking_monadic connector(config); // here config is CPR-related class, which allows advanced configuring.
Looks like httplib, CPR already supports timeouts - https://github.com/yhirose/cpp-httplib, https://github.com/whoshuu/cpr; in boost/beast you are setting 30 seconds as constants.
Regarding retries, one might say the programmer should handle it on the upper level. Indeed one can, but won't it create a performance overhead because of the serialization/deserialization taking place?
Just for now banana
doesn't support sending files (see InputFile
API section). We need a solution that is:
agent::request<T>
, but for file uploading)Replace low-quality html2json.py with better (probably external) alternative to keep API up-to-date. Possible options:
How about adding fully asynchronous requests?
This is something that lacks in https://github.com/reo7sp/tgbot-cpp and https://github.com/slowriot/libtelegram.
Problem:
Solution:
There is a problem when building the project with MSVC: C1128: number of sections exceeded object file format limit: compile with /bigobj
.
I tried compiling with beast connector, and that's the error for beast.cpp
.
Setting this option would restrict the number of linkers that can consume the resulting object files - maybe, it worth decoupling the file into several ones?
Compiling the test program :
#include <banana/api.hpp>
#include <banana/agent/cpr.hpp>
#include
static_assert(std::is_same_v<banana::api_result<banana::api::message_t, banana::agent::cpr_async>, std::futurebanana::api::message_t>);
int main(int argc, const char** argv) {
if (argc < 3) {
std::cout << "usage: " << (argc > 0 ? argv[0] : "./self") << " token target [name] [os]\n";
return 2;
}
const std::string token = argv[1];
const std::string target = argv[2];
const std::string name = argc > 3 ? argv[3] : "";
const std::string os = argc > 4 ? argv[4] : "";
const std::string message_text = "Hello from " + name + " at " + os + "!";
try {
banana::agent::cpr_async agent(token);
std::cout << "bot name: " << banana::api::get_me(agent).get().username.value() << "\n";
std::cout << "message sent: " << banana::api::send_message(agent, { target, message_text }).get().message_id << "\n";
}
catch (std::exception& e) {
std::cout << "exception while running " << name << ": " << e.what() << "\n";
return 1;
}
}
with Microsoft Visual Studio Community 2019 Version 16.9.6, gives me the following erros :
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of function template "banana::api::send_message" matches the argument list TesteBanana F:\downloads\banana-master_BUILD_DIR\TesteBanana\teste1.cpp 27
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __cdecl banana::agent::basic_cpr_monadic::basic_cpr_monadic(class std::basic_string<char,struct std::char_traits,class std::allocator >)" (??0basic_cpr_monadic@agent@banana@@qeaa@V?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@@z) referenced in function "public: __cdecl banana::agent::meta::unwrap_blocking::unwrap_blocking(class std::basic_string<char,struct std::char_traits,class std::allocator >)" (??0?$unwrap_blocking@Vbasic_cpr_monadic@agent@banana@@@meta@agent@banana@@qeaa@V?$basic_string@DU?$char_traits@D@std@@v?$allocator@D@2@@std@@@z) TesteBanana F:\downloads\banana-master_BUILD_DIR\TesteBanana\teste1.obj 1
Hi, i would really like to use this library because it has so little dependencies, but i can't get it to work.
None of the examples seem to work, neither the one from the readme, nor the ones in the examples folder. They all include the banana/agent/default.hpp
or something similar, but they don't exist. Only banana/agent/any.hpp
exists but that doesn't work on its own. They kinda do exist in the source folder, is that a mistake? Or are the examples horribly out of date?
It would be really helpful if you could provide a working example for the latest version. I just want to send a message, that's it. I am on Windows.
Thank you in advance,
Florian
Speaking of the code snippet beast.cpp,
// Gracefully close the socket
boost::beast::error_code ec;
stream.shutdown(ec);
what is the reason for ignoring the socket error closing error?
According to the htt_client_sync_example from the boost::beast developers, that error is supposed to be treated as such.
While I agree, the error there isn't important according to the boostorg/beast#824, explicit comment pointing that out might be useful.
Note: should be closed automatically after closing #11
Compiling the test program :
#include <banana/api.hpp>
#include <banana/agent/cpr.hpp>
#include <iostream>
static_assert(std::is_same_v<banana::api_result<banana::api::message_t, banana::agent::cpr_async>, std::future<banana::api::message_t>>);
int main(int argc, const char** argv) {
if (argc < 3) {
std::cout << "usage: " << (argc > 0 ? argv[0] : "./self") << " token target [name] [os]\n";
return 2;
}
const std::string token = argv[1];
const std::string target = argv[2];
const std::string name = argc > 3 ? argv[3] : "<unknown>";
const std::string os = argc > 4 ? argv[4] : "<unknown>";
const std::string message_text = "Hello from " + name + " at " + os + "!";
try {
banana::agent::cpr_async agent(token);
std::cout << "bot name: " << banana::api::get_me(agent).get().username.value() << "\n";
std::cout << "message sent: " << banana::api::send_message(agent, { target, message_text }).get().message_id << "\n";
}
catch (std::exception& e) {
std::cout << "exception while running " << name << ": " << e.what() << "\n";
return 1;
}
}
with Microsoft Visual Studio Community 2019 Version 16.9.6, gives me the following erros :
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of function template "banana::api::send_message" matches the argument list TesteBanana F:\downloads\banana-master\_BUILD_DIR\TesteBanana\teste1.cpp 27
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __cdecl banana::agent::basic_cpr_monadic::basic_cpr_monadic(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0basic_cpr_monadic@agent@banana@@QEAA@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: __cdecl banana::agent::meta::unwrap_blocking<class banana::agent::basic_cpr_monadic>::unwrap_blocking<class banana::agent::basic_cpr_monadic>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0?$unwrap_blocking@Vbasic_cpr_monadic@agent@banana@@@meta@agent@banana@@QEAA@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) TesteBanana F:\downloads\banana-master\_BUILD_DIR\TesteBanana\teste1.obj 1
int main(int argc, char** argv) {
using namespace banana::connector;
beast_blocking_monadic connector("<TG_BOT_TOKEN>")
auto resp = banana::api::send_message(connector, { /* .chat_id = */ "@smertig", /* .text = */ "Hello, world!" });
if (!resp) {
cerr << string(resp.error()) << "\n"; // providing string-based error message
switch(ErrorCode(resp.error()) { // additional error-treatment based on the codes
case ErrorCode::ConnectionTimeout: ...
case ErrorCode::Deserialization: ...
case ErrorCode::RuntimeError: โฆ
case ErrorCode::Serialization: ...
case ErrorCode::ConnectionWrite: ...
case ErrorCode::SSL*: ...
}
}
}
Let's say we want to retry the request for particular failure reasons only or treat the errors differently based on the underlying reason - there is no way to do that at the moment because of string-based errors.
From the client-side, it's substantial to distinguish between connection(SSL, read, write, bind, lookup, timeout) based errors and serialization/deserialization, std::errors,ok =false, other C++ errors.
This issue proposes either of two options:
Creating common failure error codes for all the bundles based on HTTP, libcurl, whatever, allow setting them within the connectors and save as an edition in struct error_t
class. Those error values may not be present, we can store ErrorCode::Unknown by default, but if additional error parsing is available by the bundle - see the CPR as an example, the banana will provide it to the end-user.
You are already converting the error codes to string in cpr.cpp, so in theory, it's possible to preserve error codes as well.
Storing different error-code values based on the chosen connector - this will allow more sophisticated error treatment but might break the idea of the common template-based interface. I would prefer the option which provides more detailed error treatment - if the error codes among bundles can't be kept consistent, so be it.
Let me know your thoughts here...
The purpose of this issue is to create a bundle based on the https://github.com/yhirose/cpp-httplib.
Overall, this is a great library similar to CPR but supports both clients, server connections and doesn't depend on the libcurl. Server-related or any other unused code can be easily deleted since the library is a one-header file only.
Why CPP-httlib?
Here are some drawbacks of such addition:
WinAPI
connector instead? Answering that, we don't need to use all the CPP-httplib in full, but simply extract the minimum needed for SSL, proxy, thread-safety, error-codes, timeouts until a custom replacement solution is available.I am not claiming this is necessary, just thinking loudly and pointing out to such a library...
Is there any functionality from the Telegram API or design-based yet not supported/planned/in progress?
If so, it might be beneficial to point it out explicitly in the README.md/milestones - therefore, potential customers can track the progress and developers contribute.
Assuming I have a multi-threaded environment, where the library is used, which of the implemented (blocking/non-blocking/coroutine) connectors are thread-safe in terms of using them with api::*?
Using CPR-based connector is thread-safe according to the https://github.com/whoshuu/cpr description.
What about boost::beast
connectors?
Maybe, thread-safety is worth mentioning in the README.md
file for potential consumers.
Problem:
My point is there are a lot of cases where the returned by telegram response isn't fully needed - therefore, avoiding its deserialization or deserializing upon the request can speed up the process significantly.
For example, consider sending the message to some chat with auto resp = api::send_message(connector, args);
,
where API can return the following JSON -
{"ok":true,"result":{"message_id":1197,"from":{"id":..,"is_bot":true,"first_name":"Fun Bot","username":"..."},"chat":{"id":..,"title":"simulation","type":"supergroup"},"date":1623916598,"text":"Hello, world!"}}
What banana does, is deserializing the whole returned JSON into message_t
, which is relatively slow, because, in fact, only "ok": true, "result":{}
can be significant for the end client.
Solution:
My suggestion here is to do partial deserialization of the ok, result
fields - similarly to what we can see in the extract_api_result
, but parsing certain depth only and postpone the whole deserialization:
Provide a way to receive status-only responses or do lazy-like deserialization;
auto ok_resp = api::send_message(connector, args, /*lazy=*/true); // by default, lazy = false
if (!ok_resp) { // ok = false or error happened }
else {
cout << string(ok_resp) << "\n"; // json response printed
process(*ok_resp); // here the whole deserialization happens - we might not even call this
}
Let me know your thoughts about such a proposal.
The banana
library already contains a well-structured serialization solution for telegram types - deser.hpp, meta.hpp, core.cpp and serialization.hpp, but the problem is with extensibility.
If a client uses the banana
library and needs a serialization of custom types for some other non-telegram purposes, one needs to reimplement the whole serialization/deserialization again because of the banana
design.
But what I noticed to be extremely beneficial is the ability to reuse and specify serializer behavior with custom-created types. Below I added the example of the desired functionality.
The client only creates the reflector stuff and reuses or extends(in terms of creating new struct serializer<T>:
) logic of the banana
library.
struct Temp {
int64_t x, y;
double z;
};
namespace banana {
namespace meta {
template <>
struct reflector<Temp> {
template <class F>
static void for_each_field(F&& f) {
f(string_view_t("x"), &Temp::x);
f(string_view_t("y"), &Temp::y);
f(string_view_t("z"), &Temp::z);
}
};
template <>
constexpr bool is_reflectable_v<Temp> = true;
template <>
constexpr string_view_t name_of<Temp>("Temp");
}
namespace deser {
template optional_t<string_t> serialize<Temp>(Temp value);
}
}
I agree that because of the template-based serialization, it's not easy to do. However, since you referred to some upcoming changes on the JSON-related part in another issue, I'd like this one to be taken into consideration as well.
P. S. I mentioned only the serialization part here for simplicity but implied deserialization as well.
Let me know your thoughts here...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.