Git Product home page Git Product logo

banana's Introduction

Hi there ๐Ÿ‘‹

Github Stats Top Langs

Visitor Badge

banana's People

Contributors

gabrielepongelli avatar smertig avatar ultracoderru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

banana's Issues

Allow setting custom retries number/timeout/ssl settings for connectors.

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?

Support `InputFile`

Just for now banana doesn't support sending files (see InputFile API section). We need a solution that is:

  • Optional - do not require every agent to support file uploading
  • Simple - single customization point for every to-be-supported agent (like agent::request<T>, but for file uploading)
  • Generic - support both blocking, async and coroutine-based agents
  • Isolated - do not modify existing API methods

Add fully asynchronous backend support.

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:

  1. CPR allows calling synchronous libcurl from std::async, which isn't fully asynchronous.
  2. boost::beast allows async requests, however coroutines may not be needed.

Solution:

  1. Asynchronous libcurl looks like a good addition to the backend bundles - https://curl.se/libcurl/c/libcurl-multi.html;
  2. Also boost beast without coroutines can be adopted here - https://www.boost.org/doc/libs/1_76_0/libs/beast/example/http/client/async/http_client_async.cpp

IMPROVEMENT: decouple cpp connector files to avoid C1128.

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?

Link error on windows 64 bits

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

Examples outdated? How to use the library?

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

QUESTION: Why to ignore all the socket closing errors in beast.cpp?

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.

MSC 2019 Compiling error

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	

Saving and providing failure error codes.

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:

  1. 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.

  2. 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...

Adding cpp-httplib based bundle.

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?

  1. Thread-safe access;
  2. SSL, proxy, error-codes, timeout;
  3. Extensive support and usage - 5.1k stars;
  4. One-header only;

Here are some drawbacks of such addition:

  1. Non-blocking requests aren't supported by default, but there exists a solution mentioned here(https://github.com/rtrahan504/cpp-httplib/tree/nonblocking_server) and here(yhirose/cpp-httplib#875), which allows them. Adding blocking-only requests might be a good start.
  2. Overkill for telegram and banana purposes. Are you thinking of extending the existing 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.
  3. C++11 - there is a cpp17 branch in the dev state - https://github.com/yhirose/cpp-httplib/tree/cpp17.

I am not claiming this is necessary, just thinking loudly and pointing out to such a library...

Adding TODO list.

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.

Is using connectors for doing requests thread-safe?

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.

Lazy-like deserialization or status-only response.

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.

Making serialization isolated and extendable with custom types.

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...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.