• Stars
    star
    754
  • Rank 60,205 (Top 2 %)
  • Language
    C
  • License
    BSD 3-Clause "New...
  • Created about 1 year ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

C Telegram bot framework

BOTLIB - Telegram C bot framework

Botlib is a C framework to write Telegram bots. It is mainly the sum of two things:

  1. An implementation of a subset of the Telegram bot API, wrapped in an event loop that waits for events from the Telegram API and calls our callback in the context of a new thread. The callback that implements the bot has access to various APIs to perform actions in Telegram.
  2. A set of higher level wrappers for Sqlite3, JSON, and dynamic strings (SDS library).

Why this library is written in C?

  • First of all, this framework makes writing bots in C a lot more higher level than you could expect. Sqlite3 is exported as a high level API and also exported as a key-value store. Callbacks are called with a structure that already has all the informations about the incoming message, and so forth.
  • In the high level languages landscape I had a few bad experiences with libraries changing APIs continuously. A bot is something you write and put online for years: I don't want to babysit code that already works. Bots written with this library will run everywhere as long as you can compile them with make. The only dependencies are libcurl and libsqlite3, which are basically everywhere.
  • In the process of writing a few Telegram bots, I found that many requests are quite long living. Think at a bot that transcribes the audio into text, or that uses another external API to fetch information. So multiplexing is not the way to go most of the times: this is why this library uses a thread for each request. And if you use threads like that, you want each thread to be as bare metal as possible, sharing most of the state with the main thread. C is good at that, and the library is implemented so that all the threading issues are transparent for the bot writer.
  • Certain bots are quite CPU intensive to run. For instance I wrote a bot that performs analysis on the financial market, and C was a good fit to do Montecaro simulations and things like that.

To give you some feeling about how bots are developed with this framework, see this trivial example, implementing a toy bot:

/* ... standard includes here ... */
#include "botlib.h"

/* For each bot command, private message or group message (but this only works
 * if the bot is set as group admin), this function is called in a new thread,
 * with its private state, sqlite database handle and so forth.
 *
 * For group messages, this function is ONLY called if one of the patterns
 * specified as "triggers" in startBot() matched the message. Otherwise we
 * would spawn threads too often :) */
void handleRequest(sqlite3 *dbhandle, BotRequest *br) {
    char buf[256];
    char *where = br->type == TB_TYPE_PRIVATE ? "privately" : "publicly";
    snprintf(buf, sizeof(buf), "I just %s received: %s", where, br->request);

    int64_t sent_chat_id, sent_message_id;
    botSendMessageAndGetInfo(br->target,buf,0,&sent_chat_id,&sent_message_id);
    printf("Sent message IDs: chat_id:%lld message_id:%lld\n",
        (long long) sent_chat_id, (long long) sent_message_id);

    /* Edit message after 1 second. */
    sleep(1);
    snprintf(buf, sizeof(buf), "I just %s received: %s :D", where, br->request);
    botEditMessageText(sent_chat_id,sent_message_id,buf);

    /* Words received in this request. */
    for (int j = 0; j < br->argc; j++)
        printf("%d. %s | ", j, br->argv[j]);
    printf("is was mentioned? %d | ", br->bot_mentioned);
    if (br->mentions) {
        printf("mentions: ");
        for (int j = 0; j < br->num_mentions; j++)
            printf("%s, ",br->mentions[j]);
    }
    printf("\n");

    /* Show if the message has a voice file inside. */
    if (br->file_type == TB_FILE_TYPE_VOICE_OGG) {
        printf("Voice file ID: %s\n", br->file_id);
        botGetFile(br,"audio.oga");
    }

    /* Let's use our key-value store API on top of Sqlite. If the
     * user in a Telegram group tells "foo is bar" we will set the
     * foo key to bar. Then if somebody write "foo?" and we have an
     * associated key, we reply with what "foo" is. */
    if (br->argc >= 3 && !strcasecmp(br->argv[1],"is")) {
        kvSet(dbhandle,br->argv[0],br->request,0);
        /* Note that in this case we don't use 0 as "from" field, so
         * we are sending a reply to the user, not a general message
         * on the channel. */
        botSendMessage(br->target,"Ok, I'll remember.",br->msg_id);
    }

    int reqlen = strlen(br->request);
    if (br->argc == 1 && reqlen && br->request[reqlen-1] == '?') {
        char *copy = strdup(br->request);
        copy[reqlen-1] = 0;
        printf("Looking for key %s\n", copy);
        sds res = kvGet(dbhandle,copy);
        if (res) {
            botSendMessage(br->target,res,0);
        }
        sdsfree(res);
        free(copy);
    }
}

// This is just called every 1 or 2 seconds. */
void cron(sqlite3 *dbhandle) {
    UNUSED(dbhandle);
    printf("."); fflush(stdout);
}

int main(int argc, char **argv) {
    /* Only group messages matching this list of glob patterns
     * are passed to the callback. */
    static char *triggers[] = {
        "Echo *",
        "Hi!",
        "* is *",
        "*\?",
        "!ls",
        NULL,
    };
    startBot(TB_CREATE_KV_STORE, argc, argv, TB_FLAGS_NONE, handleRequest, cron, triggers);
    return 0; /* Never reached. */
}

See further in this README file for the full API specification.

Installation

  1. Create your bot using the Telegram @BotFather.
  2. After obtaining your bot API key, store it into a file called apikey.txt inside the bot working directory. Alternatively you can use the --apikey command line argument to provide your Telegram API key.
  3. Optionally edit mybot.c to personalized the bot.
  4. Build the bot: you need libcurl and libsqlite installed. Just type make.
  5. Run with ./mybot. There is also a debug mode if you run it using the --debug option (add --debug multiple times for even more verbose messages). For a more moderate output use --verbose. Try mybot --help for the full list of command line options.
  6. Add the bot to your Telegram channel.
  7. IMPORTANT: The bot must be an administrator of the channel in order to read all the messages that are sent in such channel. Private messages will work regardless.

By default the bot will create an SQLite database in the working directory. If you want to specify another path for your SQLite db, use the --dbfile command line option.

APIs

... Work in progress ...

For the bot API check mybot.c example itself. The basic usage is pretty simple. However for all the other stuff, like the Sqlite3 abstractions, they are taken from Stonky, so the code there (which is very accessible) will provide some help. I hope to document this project better. For now my main goal was to stop duplicating Stonly to create new bots with all the common code inside.

More Repositories

1

disque

Disque is a distributed message broker
C
7,969
star
2

kilo

A text editor in less than 1000 LOC with syntax highlight and search.
C
6,839
star
3

smallchat

A minimal programming example for a chat server
C
6,606
star
4

sds

Simple Dynamic Strings library for C
C
4,649
star
5

linenoise

A small self-contained alternative to readline and libedit
C
3,348
star
6

dump1090

Dump1090 is a simple Mode S decoder for RTLSDR devices
C
2,232
star
7

neural-redis

Neural networks module for Redis
C
2,218
star
8

lamernews

Lamer News -- an HN style social news site written in Ruby/Sinatra/Redis/JQuery
Ruby
1,357
star
9

hping

hping network tool
C
1,327
star
10

smaz

Small strings compression library
C
1,096
star
11

rax

A radix tree implementation in ANSI C
C
1,043
star
12

load81

SDL based Lua programming environment for kids similar to Codea
C
586
star
13

disque-module

Disque ported as Redis module
C
480
star
14

protoview

Flipper Zero app to display known and unknown signals
C
445
star
15

shapeme

Evolve images using simulated annealing
C
382
star
16

aocla

A small stack based, written to bring Advent of Code 2022 Day 13 puzzle to the extreme consequences
C
371
star
17

retwis

A Twitter-toy clone written in PHP and Redis, used in the early days to introduce Redis data types.
PHP
357
star
18

lua-cmsgpack

A self contained Lua MessagePack C implementation.
C
343
star
19

freakwan

A MicroPython driver for the SX1276 LoRa chip
C++
274
star
20

otree

a simple btree implementation with automatic space reclaiming
C
268
star
21

redis-sampler

Small program to understand the composition of your Redis data set
Ruby
260
star
22

redis-rb-cluster

Redis Cluster Ruby client based on redis-rb
Ruby
246
star
23

stonky

Stock market Telegram bot
C
242
star
24

RESP3

RESP protocol V3 repository. Contains the specification, and other related resource
221
star
25

redlock-rb

Redlock Redis-based distributed locks implementation in Ruby
Ruby
197
star
26

lloogg

LLOOGG realtime web log analyzer
PHP
195
star
27

redis-timeseries

Ruby library for Redis backed time series.
Ruby
195
star
28

redis-tools

Abandoned project "Redis tools". What was relevant is now part of redis-cli & redis-benchmark
C
194
star
29

pngtostl

Turn PNG images into STL 3D models that will "develop" in front of a light source
C
157
star
30

iconping

Icon Ping - visual ping to 4.2.2.2
Objective-C
129
star
31

jsrt

Javascript ray tracing engine
118
star
32

adventofcode2022

A few Advent of Code puzzles (2022 edition) in C
C
102
star
33

redimension

Redis multi-dimensional query library
Ruby
98
star
34

gopher2redis

A Ruby script that translates a directory structure and its files into the Redis keys to be served via Redis Gopher protocol
Ruby
92
star
35

mc-benchmark

Memcache port of Redis benchmark
C
85
star
36

listpack

A serialization format and implementation for backward-traversable lists of strings.
C
79
star
37

visitors

Visitors fast web log analyzer
C
76
star
38

Bigdis

Bigdis - a file-based KV store speaking the Redis protocol
Tcl
76
star
39

book-examples

Redis The Definitive Guide book code examples
Ruby
51
star
40

flipper-asteroids

Asteroids for Flipper Zero
C
50
star
41

Gitan

Gitan is a very basic web interface to create and inspect bare git repositories
Ruby
45
star
42

aspark

ASCII sparklines for the Enterprise
C
41
star
43

Jim

Jim is a small footprint Tcl interpreter, with some changes to the original language but mostly compatible.
40
star
44

nolate

NO LAme TEmplate System for Ruby
Ruby
40
star
45

recidiv

minimal continuous integration framework written in Tcl (used for Redis CI)
Tcl
38
star
46

tclircd

An IRC server I wrote in 2004 for fun, using the Tcl language.
Tcl
37
star
47

partitions

Partitions.tcl is a Tcl program to simulate partitions between physical hosts
Tcl
36
star
48

connect4-montecarlo

Simple connect 4 AI using Monte Carlo method
C
31
star
49

talk32

C program to talk via serial to MicroPython powered ESP32 boards
C
28
star
50

failed-3d-prints-bot

A Telegram bot that detects failed prints and send you an image of your printer
C
22
star
51

iqmeteo

Meteo widget for the Garmin Vivoactive HR powered by Yahoo Weather API
Shell
21
star
52

siphash

A modification of SipHash reference implementation to make it more practical for Redis usage
C
20
star
53

yaku-ns

a DNS server I wrote 10 years ago. Here for historical reasons
C
18
star
54

redisdotphp

Legacy Redis PHP client lib. A best-effort support repository.
18
star
55

strabo

Turns HGT elevation maps into 2D images or 3D models
C
18
star
56

nn-2003

2003 Neural Networks experiments -- when it was not mainstream ;-)
C
17
star
57

zx2040

RP2040 ZX Spectrum emulator
C
15
star
58

crack-checksum

Find checksum (crc8, xor, add) parameters in a set of messages.
C
13
star
59

hiredis

WARNING: hiredis repository moved to http://github.com/redis/hiredis. Just my private fork.
13
star
60

dict-scan-fuzz-tester

Fuzz testing for the SCAN underlying algorithm
C
11
star
61

Siboom

A simple markup system for writing books drafts
Ruby
10
star
62

sbignum

Old code about C library for big numbers plus Tcl bindings
C
9
star
63

codakido

Redirects to Load81 project
8
star
64

redis-cp-rewrite-sim

Redis/Raft snapshotting rewriting simulation
C
8
star
65

cache-mem-tester

Test memory efficiency of Redis / Memcached against values with a given size distribution.
Ruby
7
star
66

rascan

A prototype for a multi processes port scanner I wrote in 1998. Here only to archive it for myself.
C
6
star
67

LLM-FTC-sampling

First token cutoff sampling inference example
Python
6
star
68

micropython-telegram-bot

MicroPython telegram bot library: simple way to put your IoT projects on the cloud
Python
5
star
69

bma423-pure-mp

Pure MicroPython BMA423 accelerometer driver
Python
4
star
70

t-watch-s3-micropython

Minimal MicroPython programming example for the Lilygo T-WATCH S3
Python
4
star
71

simple-language-model

Code for the video on feed-forward language model
Python
4
star
72

gif-pure-tcl

Pure TCL GIF generator
Tcl
4
star
73

bme680-pure-mp

Pure MicroPython Bosch BME680 sensor driver
Python
3
star
74

uc8151_micropython

UC8151 / IL0373 MicroPython e-paper display driver with support for greyscales and fast updates
Python
2
star
75

vl53l0x-nb

Fork of MicroPython driver for vl53l0x TOF sensor to add non-blocking mode.
Python
1
star
76

micropython-ft6x06

Simple driver for FT6x06 capacitive touch sensor in pure Python
Python
1
star