🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more

telegram-bot-api-c

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

telegram-bot-api-c

Lightweight, Simple, Fastest module for Telegram Bot without Dependencies

19.5.0
latest
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created

Codacy NodeSecurity

npm -g install telegram-bot-api-c
git clone https://github.com/Daeren/telegram-bot-api-c.git
require("telegram-bot-api-c").call("TK", "sendMessage", [0, "+"])
require("telegram-bot-api-c")("TK").api.sendMessage({chat_id: 0, text: "+"})
require("telegram-bot-api-c")("TK").polling(bot => bot.answer().html("+").send())
> tg-bot --token TK --method sendMessage --chat_id 0 --text "+"

Telegram Bot API, Bot API 2.x, Bot API 3.5

  • Proxy: +
  • Array and Map as a data source (.call, .callJson, .api[method]): +
  • Analytics: tgb-pl-botanio
  • Added: tgBot.api[sendMethod] => error.retryAfter
  • Added: sendMediaGroup (doesn't support "attach://")
- All methods in the Bot API are case-insensitive (method: .call, .callJson)

- message:                                             buffer, stream, string
- location|venue|contact:                              buffer, string
- photo|audio|voice|video|document|sticker|video_note: buffer, stream, file_id, path, url
- certificate:                                         buffer, stream, path, url

Goals:

  • High stability;
  • Low memory usage;
  • Maximum performance;
  • Flexibility.

Index

architecture

const rTgBot    = require("telegram-bot-api-c");

const gBot      = rTgBot(process.env.TELEGRAM_BOT_TOKEN),
      gApi      = gBot.api;

//----------------------------]>

gBot.promise(require("bluebird"));

//----------------------------]>

gApi
    .sendMessage(["0", "Hi"])
    .then(console.info, console.error);
    
gApi.sendMessage(["0", "Hi"], (e, data) => console.log(e || data));

// e    - Error: request/JSON.parse/response.ok
// data - JSON: response.result or null

//-------]>

gBot.callJson("sendMessage", ["0", "Hi"], (e, data, res) => console.log(e || data));

// e    - Error: request/JSON.parse
// data - JSON: response or null
// res  - Class: http.IncomingMessage or null

//-------]>

gBot.call("sendMessage", ["0", "Hi"], (e, data, res) => console.log(e || data));

// e    - Error: request
// data - Buffer: response or null
// res  - Class: http.IncomingMessage or null

//------------]>

/*
  e.code           - gApi.sendMessage( ...
  data.error_code  - callJson("sendMessage" ...

  rTgBot or gBot

  gBot.ERR_INTERNAL_SERVER
  gBot.ERR_NOT_FOUND
  gBot.ERR_FORBIDDEN
  gBot.ERR_MESSAGE_LIMITS
  gBot.ERR_USED_WEBHOOK
  gBot.ERR_INVALID_TOKEN

  gBot.ERR_BAD_REQUEST
  gBot.ERR_BAD_PROXY
  gBot.ERR_FAILED_PARSE_DATA
*/

//----------------------------]>

gBot
    .polling(onDefault)
    .catch(onError)
    
    .use(bot => "syncGotoMyMenu")
    .use((bot, data, next) => next(new Error("never get")))
    .use("/start", bot => { })

    .on("/start", onCmdStart_1)
    .on("/start", onCmdStart_2)
    .on("/start", onCmdStart_3)

    .on("enterChat", onEnterChat)
    .on("text:syncGotoMyMenu", onText)
    .on("photo document", onPhotoOrDoc)
    .on("pinnedMessage", onPinnedMessage)

    .on(/^id\s+(\d+)/i, onTextRegEx)
    .on(/^(id)\s+(\d+)/i, "type id", onTextRegEx)
    .on(/^(login)\s+(\w+)/i, ["type", "login"], onTextRegEx);


function onDefault(bot) { }
function onError(error) { }

function onCmdStart_1(bot, params, next) { next(); } // <-- Async
function onCmdStart_2(bot, params) { }               // <-- Sync
function onCmdStart_3(bot, params) { }               // <-- Sync | end

function onEnterChat(bot, member) { }
function onText(bot, text) { }
function onPhotoOrDoc(bot, data) { }
function onPinnedMessage(bot, message) { }

function onTextRegEx(bot, data) { }

//-----------]>

/*
  bot                               | gBot -> Sugar -> CtxPerRequest
  bot instanceof gBot.constructor   | true
  
  bot.command.type                  | common or private
  
  /start [text]         -> common
  /start@bot [text]     -> private
  @bot /start [text]    -> private
*/

Proxy

const gBot      = rBot(process.env.TELEGRAM_BOT_TOKEN);

const gProxyStr = "127.0.0.1:1337", // <-- Only HTTPS
      gProxyArr = ["127.0.0.1", "1337"],
      gProxyObj = {
          "host": "127.0.0.1",
          "port": 1337
      };

//------------------]>

function getMe(callback) { gBot.api.getMe(callback); }

//------------------]>

gBot.proxy(gProxyObj);

getMe(t => {
    objBot.proxy(gProxyStr);

    getMe(t => {
        objBot.proxy(); // <-- Remove
        getMe();
    });
});

rBot.callJson({
    "token":    process.env.TELEGRAM_BOT_TOKEN,
    "method":   "getMe",
    "proxy":    gProxyArr
}, (e, d) => {});

rBot.callJson(process.env.TELEGRAM_BOT_TOKEN, "getMe", (e, d) => {}, gProxyObj);

Polling

const gBot      = rBot(process.env.TELEGRAM_BOT_TOKEN);

const gOptions  = {
    "limit":    100,
    "timeout":  0,
    "interval": 2 // <-- Default / Sec.
};

//------------------]>

const gSrv = gBot
    .polling(gOptions, onMsg)
    .on("/stop", onCmdStop);
    
//------------------]>

function onMsg(bot) {
    const msg = bot.isGroup && bot.isReply ? ">_>" : "Stop me: /stop";
    bot.answer().isReply().text(msg).send();
}

function onCmdStop(bot, params) {
    gSrv.stop();
    bot.answer().text(JSON.stringify(params)).send();
}

HTTP

const rBot = require("telegram-bot-api-c");

//-----------------------------------------------------

const gSrvOptions   = {
    // For Self-signed certificate, you need to upload your public key certificate
    // "selfSigned":  "fullPath/stream/buffer",  // <-- If you use Auto-Webhook

    "certDir":  "/www/site",

    "key":       "/3_site.xx.key",
    "cert":      "/2_site.xx.crt",
    "ca":       [
        "/AddTrustExternalCARoot.crt",
        "/COMODORSAAddTrustCA.crt",
        "/COMODORSADomainValidationSecureServerCA.crt"
    ],

    "host":     "site.xx"
};

//------------------]>

const gBotFather    = rBot();

const gMyBot        = rBot(process.env.TG_BOT_TOKEN_MY),
      gOtherBot     = rBot(process.env.TG_BOT_TOKEN_OTHER);

const gSrv          = gBotFather.http(gSrvOptions);

gSrv
    .bot(gMyBot)                                    // <-- Auto-Webhook: "/tg_bot_<sha256(token)>"
    .on("/start", onCmdStart)
    .on("/stop", onCmdStop);

gSrv
    .bot(gOtherBot, "/urlOtherBot", onMsgOtherBot); // <-- Auto-Webhook
    
//------------------]>

function onMsgOtherBot(bot) { }

function onCmdStart(bot, params) { }
function onCmdStop(bot, params) { }

Virtual

const gBot = rBot(process.env.TELEGRAM_BOT_TOKEN);

const gSrv = gBot
    .virtual(function(bot) {
        bot.answer().text("Not found!").send();
    })
    .on("photo", console.log);

//----[Proxy: express]----}>

gBot
    .api
    .setWebhook({"url": "https://site.xx/dev-bot"})
    .then(function(isOk) {
        const rExpress      = require("express"),
              rBodyParser   = require("body-parser");

        rExpress()
            .use(rBodyParser.json())
            .post("/dev-bot", gSrv.middleware)
            .listen(3000, "localhost");
    });
    
//----[Stress Tests]----}>

gSrv.input(null, {
    "update_id": 0,
    "message": {
        "message_id": 0,

        "from": {
            "id": 0,
            "first_name": "D",
            "username": ""
        },

        "chat": {
            "id": 0,
            "first_name": "D",
            "username": "",
            "type": "private"
        },

        "date": 0,
        "text": "Hello"
    }
});

mServer

const gBot = rBot(process.env.TELEGRAM_BOT_TOKEN);

gBot
    .api
    .setWebhook({"url": "https://site.xx/myBot"})
    .then(function(isOk) {
        if(!isOk) {
            throw new Error("Oops...problem with the webhook...");
        }

        gBot.http(gSrvOptions, cbMsg);
    });

NGINX + Node.js

const gBot          = rBot();
const gSrvOptions   = {
    "ssl":          false,

    "autoWebhook":  "site.xx:88", // <-- Default: (host + port); `false` - disable

    "host":         "localhost",
    "port":         1490
};

gBot.http(gSrvOptions, onMsg);

//----[DEFAULT]----}>

gBot.http();
gBot.http(onMsg);

// host: localhost
// port: 1488
// autoWebhook: false
// ssl: false

Response Builder

objSrv
    .use(function(bot) {
        bot
            .answer() // <-- Builder + Queue

            .chatAction("typing") // <-- Element

            .text("https://google.com", "markdown") // <-- Element
            //.parseMode("markdown")
            .disableWebPagePreview() // <-- Modifier (for the last element)
            .keyboard([["X"], ["Y"]]) // <-- Modifier
            
            .markdown("*text*") // <-- Element
            .html("<a>text</a>")

            .chatAction("upload_photo")
            
            .photo("https://www.google.ru/images/logos/ps_logo2.png", "myCaption")
            .caption("#2EASY") // <-- Modifier
            .keyboard("old")
            .keyboard("new", "selective") // <-- Uses: bot.mid (selective)

            .location(69, 96)
            .latitude(13)
            .keyboard() // <-- Hide

            .send() // <-- Uses: bot.cid

            .then(console.log);  // <-- Return: array | results
        
        //------[ONE ELEMENT]------}>
        
        const customKb = {
            "keyboard":         [["1"], ["2"], ["3"]],
            "resize_keyboard":  true
        };

        bot
            .answer()
            .text("Hi")
            .keyboard(customKb)
            .send((e, r) => console.log(e || r));  // <-- Return: hashTable | result

        //------[RENDER]------}>
        
        const template = "Hi, {name}!";
        const buttons = [["{btnMenu}", "{btnOptions}"]];
        const input = {
            "name":         "MiElPotato",

            "btnMenu":      "Menu +",
            "btnOptions":   "Options"
        };

        bot
            .answer()
            .text(template)
            .keyboard(buttons, "resize")
            .render(input) // <-- text + keyboard
            .send();
            
        bot
            .answer()
            .text("Msg: {0} + {1}")
            .render(["H", "i"]) // <-- text
            .keyboard([["X: {0}", "Y: {1}"]])
            .send();
    });
NameArgs
-
htmltext, disable_web_page_preview, disable_notification, reply_to_message_id, reply_markup
markdowntext, disable_web_page_preview, disable_notification, reply_to_message_id, reply_markup
-
texttext, parse_mode, disable_web_page_preview, disable_notification, reply_to_message_id, reply_markup
photophoto, caption, disable_notification, reply_to_message_id, reply_markup
audioaudio, performer, title, duration, caption, disable_notification, reply_to_message_id, reply_markup
documentdocument, caption, disable_notification, reply_to_message_id, reply_markup
stickersticker, disable_notification, reply_to_message_id, reply_markup
videovideo, width, height, duration, caption, disable_notification, reply_to_message_id, reply_markup
voicevoice, duration, caption, disable_notification, reply_to_message_id, reply_markup
videoNotevideoNote, duration, length, disable_notification, reply_to_message_id, reply_markup
locationlatitude, longitude, disable_notification, reply_to_message_id, reply_markup
venuelatitude, longitude, title, address, foursquare_id, disable_notification, reply_to_message_id, reply_markup
contactphone_number, first_name, last_name, disable_notification, reply_to_message_id, reply_markup
chatActionaction
gamegame_short_name, disable_notification, reply_to_message_id, reply_markup
invoicetitle ... ... reply_markup
-
inlineQueryresults, next_offset, is_personal, cache_time, switch_pm_text, switch_pm_parameter
callbackQuerytext, show_alert
shippingQueryok, shipping_options, error_message
preCheckoutQueryok, error_message

Tg Upload

gBot.enable("tgUrlUpload");

gBot
    .polling()
    .on("text", function(bot, url) {
        bot.answer().photo(url).send();
    });
    
/*
Added the option to specify an HTTP URL for a file in all methods where InputFile or file_id can be used (except voice messages).
Telegram will get the file from the specified URL and send it to the user.
Files must be smaller than 5 MB for photos and smaller than 20 MB for all other types of content.
*/

Plugin

gSrv
    .use(function(bot, data, next) {
        console.log("Async | Type: any");

        if(data === "next") {
            next();
        }
    })
    .use("text", function(bot) {
        console.log("F:Sync | Type: text");

        bot.user = {};
    })
    .use(function(bot) {
        bot.user.id = 1;
    });
    
gSrv
    .on("text", function(bot, data) {
        bot.user.id;
    });

Goto

gSrv
    .use(function(bot, data, next) {
        next(data === "room" ? "room.menu" : "");
    })
    .use(function(bot) {
        console.log("If not the room");
        
        // return "room.menu";
    })
    
    .on("text", function(bot, data) { })
    .on("text:room.menu", function(bot, data) { });

JS Generators

gBot
    .polling(function* (bot) {
        const result = yield send(bot);
        console.info(result);

        yield error();
    })
    .catch(function* (error) {
        console.error(error);
    })
    
    .use(function* (bot) {
        yield auth("D", "13");
    })
    .use("text", function* (bot, data) {
        yield save();

        if(data === "key") {
            return "eventYield";
        }
    })

    .on("text:eventYield", function* (bot, data) {
        console.log("eventYield:", data);
    });

//----------------]>

function auth(login, password) {
    return new Promise(x => setTimeout(x, 1000));
}

function send(bot) {
    return bot.answer().text("Ok, let's go...").send();
}

Render

//-----[EJS]-----}>

gBot.engine(require("ejs"))

data = {"x": "H", "y": "i"};
bot.render("EJS | Text: <%= x %> + <%= y %>", data);

//-----[DEFAULT]-----}>

data = ["H", "i"];
bot.render("Array | Text: {0} + {1}", data);

data = {"x": "H", "y": "i"};
bot.render("Hashtable | Text: {x} + {y}", data);

Keyboard

const rBot = require("telegram-bot-api-c");

function onMsg(bot) {
    const data = {};
    
    data.chat_id = bot.cid;
    data.text = "Hell Word!";
    
    data.reply_markup = bot.keyboard(); // Or: bot.keyboard.hide()
    data.reply_markup = bot.keyboard([["1", "2"], ["3"]]);
    
    data.reply_markup = bot.keyboard.hOx();
    data.reply_markup = bot.keyboard.inline.hOx();
    
    bot.api.sendMessage(data);
}

rBot.keyboard.numpad(true); // <-- Once
rBot.keyboard.numpad(false, true); // <-- Selective

rBot.keyboard.inline.numpad();

//------------------------------

rBot.keyboard(buttons[, params])
rBot.keyboard.inline(inlButtons, isVertically)

/*
  buttons:    `string`, `array of array` or `false`
  inlButtons: `string`, `array of array` or `object`
  params:     "resize once selective"
  
  v - vertically; h - horizontally;
  
  vOx, hOx, vPn, hPn, vLr, hLr, vGb, hGb
  abcd, numpad, hide
  
  Normal keyboard:
   vOx(once, selective)
   numpad(once, selective)
*/
NameNote
-
_OxO / X
_Pn+ / -
_UdUpwards / Downwards arrow
_LrLeftwards / Rightwards arrow
_GbLike / Dislike
-
abcdABCD
numpad0-9
-
hide

Download

gBot.download("file_id", "dir"/*, callback*/);
gBot.download("file_id", "dir", "name.mp3"/*, callback*/);


gBot
    .download("file_id")
    .then(function(info) {
        info.stream.pipe(require("fs").createWriteStream("./" + info.name));
    });


gBot
    .download("file_id", function(error, info) {
        info.stream.pipe(require("fs").createWriteStream("./myFile"));
    });

InlineQuery

https://core.telegram.org/bots/inline

gBot
    .polling()
    .on("inlineQuery", function(bot, data) {
        const idx = Date.now().toString(32) + Math.random().toString(24);
        const results = [
            {
                "type":         "article",
                "title":        "Title #1",
                "message_text": "Text...",

                "thumb_url":    "https://pp.vk.me/c627530/v627530230/2fce2/PF9loxF4ick.jpg"
            },

            {
                "type":         "article",
                "title":        "Title #2: " + data.query,
                "message_text": "Text...yeah"
            },

            {
                "type":         "photo",

                "photo_width":  128,
                "photo_height": 128,

                "photo_url":    "https://pp.vk.me/c627530/v627530230/2fce2/PF9loxF4ick.jpg",
                "thumb_url":    "https://pp.vk.me/c627530/v627530230/2fce2/PF9loxF4ick.jpg"
            }
        ]
            .map((t, i) => { t.id = idx + i; return t; });

        // results = {results};

        bot
            .answer()
            .inlineQuery(results)
            .send()
            .then(console.info, console.error);
    });

//------------]>

bot
    .api
    .answerInlineQuery({
        "inline_query_id": 0,
        "results":         results
    })
    .then(console.info, console.error);

Send file as Buffer


const imgBuffer = require("fs").readFileSync(__dirname + "/MiElPotato.jpg");

//------------]>

objSrv
    .use(function(bot, next) {
        bot
            .answer()
            .photo(imgBuffer)
            .filename("MiElPotato.jpg") // <-- It is important
            .filename("/path/MiElPotato.jpg") // <-- Same as above
            .send();
    });
    
//------------]>

api.sendPhoto({
    "chat_id":      0,
    "photo":        imgBuffer,

    "filename":      "MiElPotato.jpg" // <-- It is important
});

api.sendDocument({
    "chat_id":      0,
    "document":     imgBuffer
});

CLI

KeyNote
-
-jinsert white space into the output JSON string for readability purposes
-
--tokenhigh priority
--methodhigh priority
--proxy"ip:port"
// Environment variables: low priority

> set TELEGRAM_BOT_TOKEN=X
> set TELEGRAM_BOT_METHOD=X
> set TELEGRAM_BOT_PROXY=X

...

> tg-bot --token X --method sendMessage --key val -bool
> node telegram-bot-api-c --token X --method sendMessage --key val -bool

...

> tg-bot --token X --method sendMessage --chat_id 0 --text "Hi" -disable_web_page_preview
> tg-bot --token X --method sendMessage < "./examples/msg.json"

> tg-bot --token X --method sendPhoto --chat_id 0 --photo "/path/MiElPotato.jpg"
> tg-bot --token X --method sendPhoto --chat_id 0 --photo "https://www.google.ru/images/logos/ps_logo2.png"

...

> tg-bot
> {"token": "", "method": "sendMessage", "chat_id": 0, "text": "1"}
> <enter>

(result)

> {"chat_id": 0, "text": "2", "j": true, "proxy": "ip:port"}
> <enter>

(result)

Test

npm -g install mocha
npm install chai

set TELEGRAM_BOT_TOKEN=X
set TELEGRAM_CHAT_ID=X
set TELEGRAM_MSG_ID=X

cd <module>

npm test

npm test

Module

MethodArgumentsNote
-
keyboardbuttons[, params]return: object; buttons: string/array; params: "resize once selective"
parseCmdtext[, strict]return: {type, name, text, cmd}; strict: maxLen32 + alphanum + underscore
-
calltoken, method[, data][, callback(error, buffer, response)][, proxy][, tgUrlUpload]
calloptions{token, method, proxy, tgUrlUpload}[, data][, callback]
callJsontoken, method[, data][, callback(error, json, response)][, proxy][, tgUrlUpload]
callJsonoptions{token, method, proxy, tgUrlUpload}[, data][, callback]

Instance

AttributeTypeNote
-
apiobjectSee Telegram Bot API
-
keyboardfunction
parseCmdfunction
MethodArgumentsReturn
-
-
enablekeythis
disablekeythis
enabledkeytrue/false
disabledkeytrue/false
-
engineinstancethis
promiseinstancethis
token[token]this or token
proxy[proxy]this
-
callmethod[, data][, callback(error, buffer, response)]
callJsonmethod[, data][, callback(error, json, response)]
-
rendertemplate, datastring
downloadfid[, dir][, name][, callback(error, info {id,size,file,stream})]promise or undefined
-
http[options][, callback(bot, cmd)]object
polling[options][, callback(bot, cmd)]object
virtual[callback(bot, cmd)]object

Methods: Response Builder

NameArgsNote
-
inlineQuery(results)
callbackQuery([message])
-
render(data)
keyboard(buttons[, params])
inlineKeyboard(buttons[, isVertically])
-
isReply([flag])
send([callback])
-
text
photoExt: jpg, jpeg, gif, tif, png, bmp
audioExt: mp3
document
stickerExt: webp [, jpg, jpeg, gif, tif, png, bmp]
videoExt: mp4
voiceExt: ogg
location
venue
contact
chatAction
game

Methods: Server

NameArgumentsReturn
-
POLLING
-
startthis
stopthis
HTTP
-
botbot[, path][, onMsg(json, request)]new srvInstance
-
VIRTUAL
-
inputerror, data
middleware
-
ALL
-
catchcallback(error)this
use[type], [params], callback(bot[, data, next])this
ontype[, params], callback(data, params[, next])this
off[type][, callback]this

Fields: bot | srv.on('', bot => 0)

NameTypeNote
-
isGroupbooleanbot.isGroup = bot.message.chat.type === [super]group
isReplybooleanbot.isReply = !!bot.message.reply_to_message
-
cidnumberbot.cid = bot.message.chat.id
midnumberbot.mid = bot.message.message_id
qidstringbot.qid = bot.inlineQuery.id
cqidstringbot.cqid = bot.callbackQuery.id
sidstringbot.sid = bot.shipping_query.id
pqidstringbot.pqid = bot.pre_checkout_query.id
-
commandobjectIncoming command
-
updateTypestring
updateSubTypestring
eventTypestring
eventSubTypestring
gotoStatestring
-
fromobjectPersistent
-
messageobjectIncoming message
inlineQueryobjectIncoming inline query
chosenInlineResultobjectThe result of an inline query that was chosen
callbackQueryobjectIncoming callback query
-
answerfunction()Response Builder; message; Uses: cid, mid
answerfunction()Response Builder; inlineQuery; Uses: qid
answerfunction()Response Builder; callbackQuery; Uses: cqid

Events: use / on

NameArgsNote
-
messagebot, message[, next]
editedMessagebot, message[, next]
-
channelPostbot, post[, next]
editedChannelPostbot, post[, next]
-
inlineQuerybot, data[, next]
chosenInlineResultbot, data[, next]
callbackQuerybot, data[, next]
-
pinnedMessagebot, message[, next]
-
invoicebot, data[, next]
successfulPaymentbot, data[, next]
-
enterChatbot, data[, next]
leftChatbot, data[, next]
-
chatTitlebot, data[, next]
chatNewPhotobot, data[, next]
chatDeletePhotobot, data[, next]
-
chatCreatedbot, data[, next]
superChatCreatedbot, data[, next]
channelChatCreatedbot, data[, next]
-
migrateToChatIdbot, data[, next]
migrateFromChatIdbot, data[, next]
-
textbot, data[, next]
photobot, data[, next]
audiobot, data[, next]
documentbot, data[, next]
stickerbot, data[, next]
videobot, data[, next]
voicebot, data[, next]
videoNotebot, data[, next]
locationbot, data[, next]
venuebot, data[, next]
contactbot, data[, next]
gamebot, data[, next]
-
*bot, data[, next]
/[name]bot, params[, next]CMD
-
(regexp)bot, params[, next]

License

MIT

@ Daeren @ Telegram

FAQs

Package last updated on 22 Nov 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts