🍌 C++ Telegram Bot API library

Overview

License: MIT GitHub Actions GitHub Actions

🍌 banana - thin wrapper over Telegram Bot API written in C++17.

Key Features

  • Simple API
  • Single interface for both blocking, non-blocking and even coroutine-based operations
  • Generic in terms of networking backend (bundled support for WinAPI, cpr and boost::beast)
  • Extendable (see custom-connector example)
  • Automatically generated from Telegram Bot API 5.0
  • Cross-platform (tested on Windows, Linux, macOS)

Example

#include <banana/api.hpp>
#include <banana/connector/default.hpp>

int main(int argc, char** argv) {
    banana::connector::default_blocking connector("<TG_BOT_TOKEN>")
    banana::api::send_message(connector, { "@smertig", "Hello, world!" });
}

Documentation

Latest Release

Master

Issues
  • Add fully asynchronous backend support.

    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
    enhancement agent 
    opened by Pilipets 4
  • Making serialization isolated and extendable with custom types.

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

    question wontfix 
    opened by Pilipets 3
  • Link error   on windows 64 bits

    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 >)" ([email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@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 >)" ([email protected][email protected]@[email protected]@@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@z) TesteBanana F:\downloads\banana-master_BUILD_DIR\TesteBanana\teste1.obj 1

    opened by mbsteixeira 1
  • MSC 2019 Compiling error

    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> >)" ([email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@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> >)" ([email protected][email protected]@[email protected]@@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@Z)	TesteBanana	F:\downloads\banana-master\_BUILD_DIR\TesteBanana\teste1.obj	1	
    
    question 
    opened by mbsteixeira 1
  • Adding TODO list.

    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.

    question 
    opened by Pilipets 1
  • IMPROVEMENT: decouple cpp connector files to avoid C1128.

    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?

    agent 
    opened by Pilipets 1
  • Drop hand-written API parser

    Drop hand-written API parser

    Replace low-quality html2json.py with better (probably external) alternative to keep API up-to-date. Possible options:

    • https://github.com/ark0f/tg-bot-api (https://ark0f.github.io/tg-bot-api/custom.json) - supports Bot API 5.3, good quality, markdown style comments
    enhancement api 
    opened by Smertig 0
  • QUESTION: Why to ignore all the socket closing errors in beast.cpp?

    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 https://github.com/boostorg/beast/issues/824, explicit comment pointing that out might be useful.

    opened by Pilipets 0
  • Support `InputFile`

    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
    enhancement help wanted api 
    opened by Smertig 1
  • Adding cpp-httplib based bundle.

    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(https://github.com/yhirose/cpp-httplib/issues/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...

    enhancement help wanted good first issue agent 
    opened by Pilipets 1
  • Saving and providing failure error codes.

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

    enhancement help wanted agent api 
    opened by Pilipets 1
  • Allow setting custom retries number/timeout/ssl settings for connectors.

    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?

    enhancement agent 
    opened by Pilipets 1
  • Lazy-like deserialization or status-only response.

    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.

    enhancement agent api 
    opened by Pilipets 4
  • Is using connectors for doing requests thread-safe?

    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.

    documentation question agent 
    opened by Pilipets 1
Releases(v0.2.0)
  • v0.2.0(Aug 10, 2021)

    What's new

    • ⚠️ [BREAKING] Rename connector -> agent
    • ⚡ Add boost::future-based asynchronous agent (#2) (non-blocking, doesn't require C++20)
    • ⚡ Support telegram bot API v5.3 (#13)
    • ⚡ Update API parser & improve code generation
    • 🔨 Add more reflection utils (meta::api_traits, api::method)
    • 🔨 Rework serialization stuff, use extern templates to speed up compilation
    • 🔨 Rework dynamic_optional<T> to make it more like std::optional<T>
    • 🔨 Close #1 (thanks @gabrielepongelli for PR)

    Docs are available here.

    Commits

    • 3ffd77c: Fix typo in connector docs (Smertig)
    • 5bc773c: Improve generated API docs and types (Smertig)
    • 66c9762: Refactor connector helpers (Smertig)
    • f33ae84: Refactor dynamic_optional (Smertig)
    • 88c8981: Fixed a bug that desn't permit to send or receive a callback_game_t structure even if it must be empty as specified by the official telegram api site. (Gabriele Pongelli) #1
    • b1884b5: Bump cpr version to 1.6.2 (bundled & conan examples) (Smertig)
    • fad74a1: Docs: fix dependencies version (Smertig)
    • 5d31c7f: Fix examples build (Smertig)
    • 8d7ba1b: Move CallbackGame/InputFile types directly to codegen (Smertig)
    • 8b2b233: Update README (Smertig)
    • cdbea62: Remove unused serializer specializations (Smertig)
    • 4ea6954: Make banana::expected default-constructible (Smertig)
    • e299019: Add experimental future-based connector over boost::beast (Smertig)
    • 5cbbd26: Fix CI (/bigobj) (Smertig)
    • 582541a: Update API parser, update to 5.3 Tg Bot API (Smertig)
    • 73afd78: Simplify api.hpp, add response_handler instead of raw callback (Smertig)
    • 41cbb07: Remove deserializer from public interface (Smertig)
    • b36ab21: Rework serialization (Smertig)
    • 0f3da81: Fix typo (Smertig)
    • 03db79c: Make API more generic, add meta::api_traits (Smertig)
    • 31baf11: Refactor file tree (Smertig)
    • 79ff0bd: Small fix (Smertig)
    • 5290aed: Remove banana::api::call from docs (Smertig)
    • b3c542a: Add docs for beast_future{_monadic} connectors (Smertig)
    • 00c25a9: Fix docs (Smertig)
    • 3a569c7: Small fix (Smertig)
    • b6b41ec: Simplify connector interface using method traits (Smertig)
    • 1e79665: Simplify connector interface (empty string instead of nullopt) (Smertig)
    • c8dbf05: Fix build (Smertig)
    • 5178e11: BREAKING: rename connector -> agent (Smertig)
    • add2e80: Bump version -> 0.2.0 (Smertig)
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Mar 30, 2021)

Owner
Alexander
C++ programmer with a pinch of reverse engineering skills
Alexander
Stock market Telegram bot

Stonky Telegram Bot README Stonky is a Telegram bot that provides access to financial informations. It is backed by the publicly available Yahoo Finan

Salvatore Sanfilippo 204 Jun 9, 2022
Send messages to a LED Matrix display through Telegram. Inspired by a tweet from Smarter Every Day

Send messages to a LED Matrix display through Telegram. Inspired by a tweet from Smarter Every Day

Brian Lough 22 Jun 13, 2022
Experimental telegram client based on official Android sources

Catogram Experimental telegram client based on official Android sources Catogram features: Message translator TGX Style of context menu VKUI Icons and

null 179 Jul 28, 2022
Telegram messenger for Android

Telegram is a messaging app with a focus on speed and security. It’s superfast, simple and free. This repo contains the official source code for Telegram App for Android.

Dao Hong Vinh 10 Oct 31, 2021
Custom kernel for sweet based on Delta, builds hosted on @sweet_epsilon on Telegram (GH releases are outdated)

Linux kernel ============ This file was moved to Documentation/admin-guide/README.rst Please notice that there are several guides for kernel develop

Udit Karode 14 Mar 29, 2022
WIP / DIN-rail compatible WiFi security camera with additional features (doorbell detection, magnetic / reed switch door & PIR sensor...) that sends you alerts on Telegram if someone unauthorised breaks into your house.

WIP / DIN-rail compatible WiFi security camera with additional features (doorbell detection, magnetic / reed switch door & PIR sensor...) that sends you alerts on Telegram if someone unauthorised breaks into your house.

François Leparoux 2 Dec 18, 2021
Telegram Desktop messaging app

Telegram Desktop – Official Messenger This is the complete source code and the build instructions for the alpha version of the official desktop client

Telegram Desktop 19.4k Aug 8, 2022
An unofficial Qt-based client for Telegram messenger.

Kutegram Supported platforms Windows XP and higher (maybe even lower?) Linux Symbian 9.2-9.4 Symbian^3 Maemo 5 Fremantle MeeGo Harmattan Current featu

Kutegram 6 Jul 9, 2022
Entertainment bot for Discord made with D++ - the C++ Discord library

Beerist-Bot Entertainment bot for Discord made with D++ - the C++ Discord library Invite Beerist to your Server here! GUIDE FOR BUILDING AND SELFHOSTI

DJ::Ötzi 3 Jun 16, 2022
Optimized, fast and unsafe Uniswap sniping bot for buying new listings.

Optimized, fast and unsafe Uniswap sniping bot for buying new listings. Table of content How does it work? Pregeneration Used libraries Project struct

Sebastian Szczepański 147 Jul 30, 2022
A simple growtopia bot!

CPPBot By DrOreo002 Fixed by Lucy Usage It should be easy to build this, but apparently visual studio wouldn't allow you to. Because sometimes thing c

inf 9 Oct 20, 2021
A 3-D Printed Bot which can talk, cheer, dance and manage your day-to-day schedule.

cheerup A 3-D Printed Bot which can talk, cheer, dance and manage your day-to-day schedule. In childhood many of us have watched this show "SpongeBob

Aniket Dhole 4 Sep 5, 2021
Tetris bot

Lemon Tea Guildline versus tetris bot How to build Notices Lemon Tea makes use of standard library header <bit> available in C++20, so make sure your

null 4 Jan 8, 2022
A Bouncing Seal Discord Bot's Source Code.

A Bouncing Seal It's a fun bot with leveling and funny bouncing seal videos. Information Invite Support Server How to run locally You need DPP, follow

SirObsidian 4 Sep 10, 2021
alie, simplified Discord bot, that's it. As fast and stable as possible.

alie alie, simplified Discord bot, that's it. As fast and stable as possible. Requirements Linux-compatible OS (aka Linux distribution) A C compiler w

mecura 8 Nov 15, 2021
A D++ Discord Bot template for Visual Studio 2019 (x64 and x86)

D++ Windows Bot Template A D++ Discord Bot template for Visual Studio 2019 (x64 and x86, release and debug). The result of this tutorial. This templat

brainbox.cc 19 Jul 16, 2022
Bot for participation to the Lux AI Challenge

Lux AI Challenge This repository is a cleaned version of the official LUX AI Challenge kit that can be found here: https://github.com/Lux-AI-Challenge

AB Normals 2 Dec 6, 2021
Real Time, High performance BOT detection and protection

REAL-TIME BOT PROTECTION CHALLENGE IronFox https://innovera.ir IronFox is a real-time and high performance bot protection, that using Nginx as a reve

Khalegh Salehi 3 Jun 5, 2022
Bot for the Cee.Studio server

cee-bot Bot for the Cee.Studio server. Getting Started Open config.json and match the cee_bot field to your server primitives Head to listeners/ and f

cee.studio 1 Jan 12, 2022