Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

how to send messages in order? #192

Closed
wizzard0 opened this issue Sep 25, 2016 · 9 comments
Closed

how to send messages in order? #192

wizzard0 opened this issue Sep 25, 2016 · 9 comments

Comments

@wizzard0
Copy link

when using e.g. C# Telegram.Bot library, I can do successive calls to bot.sendmessage and the user receives them in the order which I used to send. With node-telegram-bot-api, I often get replies in random order.

Repro: create a basic echo bot, verify it works, stop bot, send 3-4 messages, start bot, see messages received by bot in order, but replies in chat in random order.

@alexandercerutti
Copy link
Contributor

alexandercerutti commented Sep 26, 2016

if I understood rightly you problem, receiving replies in various order, happens due to bot.sendMessage asyncronicity.

You can use Promise's .then() method. It accepts only one parameter: a callback with a(n optional) parameter that will contain last sent message details, like message_id.

So you can do:

bot.sendMessage(...).then(() => {
    bot.sendMessage(...);
});

Chaining such this way messages is a bad way, but the only one Imho.

@GochoMugo
Copy link
Collaborator

I am in support of @alexandercerutti's answer.

first approach:

Furthermore, here is another approach you can use to send multiple messages:

var Promise = require('bluebird');

function sendMessages(bot, chatId, messages) {
    return Promise.mapSeries(messages, function(message) {
        return bot.sendMessage(chatId, message);
    });
}

// example usage
sendMessages(bot, chatId, ["first", "second", "third"])
    .then(function() {
        console.log("All messages sent, in series!");
    });

However, the above approach assumes you have the messages prepared in advance.

second approach:

For the use case where you are invoking bot.sendMessage() arbitrarily, you might want to implement it using a queue of messages:

var Promise = require('bluebird');
var queue = [];
var inUseQueue = [];

function _sendMessages() {
    // if we are already sending messages from the queue, or
    // the queue is empty, stop
    if (inUseQueue.length || !queue.length) return;

    console.log("processing queue");
    inUseQueue = queue;
    queue = [];
    Promise.mapSeries(inUseQueue, function(request) {
        var resolve = request.resolve;
        var reject = request.reject;
        var bot = request.bot;
        console.log("sending message '%s'", request.message);
        return bot.sendMessage(request.chatId, request.message)
            .then(resolve)
            .catch(reject);
    }).then(function() {
        console.log("queue processed");
        inUseQueue = [];
        _sendMessages();
    });
}

function sendMessage(bot, chatId, message) {
    var resolve, reject;
    var promise = new Promise(function(promiseResolve, promiseReject) {
        resolve = promiseResolve;
        reject = promiseReject;
    });
    console.log("pushing message '%s' to queue", message);
    queue.push({ bot, chatId, message, resolve, reject });
    process.nextTick(_sendMessages);
    return promise;
}

// example usage
function toLog(message) { return function() { console.log(message); }; };

sendMessage(bot, chatId, "first").then(toLog("first sent!"));

setTimeout(function() {
    sendMessage(bot, chatId, "second").then(toLog("second sent!"));
}, 1000);

setTimeout(function() {
    sendMessage(bot, chatId, "third").then(toLog("third sent!"));
}, 2000);

The above example usage gave me this output:

pushing message 'first' to queue
processing queue
sending message 'first'
pushing message 'second' to queue
pushing message 'third' to queue
first sent!
queue processed
processing queue
sending message 'second'
second sent!
sending message 'third'
third sent!
queue processed

Hope that gives you an idea of how to solve your problem.

(And maybe a PR for this could be awesome!)

@wizzard0
Copy link
Author

wizzard0 commented Sep 26, 2016

oh well. I guess I'll make generic per-user "dispatch queue" where I'd put the messages and it would ensure it wont interleave them... or aggregate, if I accidentally spam it with 100 msgs :)

Thanks for the advice though.

UPD: nice, you added the queue example while I was writing my comment :)

@wizzard0
Copy link
Author

wizzard0 commented Sep 26, 2016

(And maybe a PR for this could be awesome!)

@GochoMugo btw, I noticed we have a fork (node-telegram-bot-api-latest), shall I switch to it and submit PRs there, if any?

@GochoMugo
Copy link
Collaborator

@wizzardo That repo is mainly for merging PRs from this repo. It is just bleeding-edge for kinda-advanced users (and might disappear, if @yagop keeps up with PRs here). Also see the beginning of the README in the fork.

So, please draft your PRs against this repo. I will (most probably) help you perfect it here, then we will have our bot automatically draft it from here to the fork and we merge.

@wizzard0
Copy link
Author

hmmm... given there was a few months since last PR was merged, maybe it's possible to ask @yagop for commit access?

@GochoMugo
Copy link
Collaborator

I might do that some time to come, but I gave him the benefit of doubt: we get busy at times, you know! But I might query him and see the result.

@GochoMugo
Copy link
Collaborator

I have built a wrapper around this library to add higher-level features. Currently, it supports sending messages in order. It is called tgfancy. See https://github.com/GochoMugo/tgfancy for more information.

@GochoMugo
Copy link
Collaborator

/cc @phillipadsmith

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants