irazasyed / telegram-bot-sdk

🤖 Telegram Bot API PHP SDK. Lets you build Telegram Bots easily! Supports Laravel out of the box.
https://telegram-bot-sdk.com
BSD 3-Clause "New" or "Revised" License
3.05k stars 673 forks source link

Command matching bot username #41

Closed vynes closed 9 years ago

vynes commented 9 years ago

In /Commands/CommandBus.php#L148 I'd like to change the regex for parsing commands from: preg_match('/^\/([^\s@]+)@?(\S+)?\s?(.*)$/', $text, $matches); to: preg_match('/^(?:\/|@)([^\s@]+)@?(\S+)?\s?(.*)$/i', $text, $matches); so that @botusername_bot is also matched as a command This way any arguments can be parsed that are passed as @botusername_bot arg1 arg2.

Unless this is handled some other way?

Edit: This works in a group. Ideally, when typing anything in a one-on-one session with the bot should also parse these arguments. Why else would you type anything directly to a bot? A request is coming in from telegram in both cases (@botname args in a group and any message with one-on-one). It just needs to be handled somehow.

jonnywilliamson commented 9 years ago

@vynes - I'm sorry I can't follow what you are asking for.

Could you give a simple example? Why is the current regex not working?

vynes commented 9 years ago

@jonnywilliamson So it looks like I did not understand very well how the telegram API works. Sorry for the confusion. I'd still like to capture a message given in the form of @somename_bot [message] (without a specific /command) which would not be a problem.

vynes commented 9 years ago

Also related: If I want my bot to listen to all messages (i.e. my bot is in non-privacy mode) for instance, I'd have to make a separate command handler for it, as the sdk only checks for specific commands such as /command [args] or /command@botname [args].

I feel the sdk should be able to handle it. Am I making any sense?

vynes commented 9 years ago

So just for reference, below is how I'm working around this at the moment.

With this change 2 additional commands need to be created. The first will be using the name of the bot (BotnameCommand) for all messages directed as @botname [message]. The second is called 'general' (GeneralCommand) for capture of all messages and delegating them to different commands (or possibly bots) in non-privacy mode.

Everything else still works as it should. Also tested in non-privacy mode.

@@ -145,7 +145,16 @@ class CommandBus

             throw new \InvalidArgumentException('Message is empty, Cannot parse for command');
         }

-        preg_match('/^\/([^\s@]+)@?(\S+)?\s?(.*)$/', $text, $matches);
+        if (!preg_match('/^\/([^\s@]+)@?(\S+)?\s?(.*)$/', $text, $matches)) {
+            if (preg_match('/@([^\s\/]+)\s?(.+)?/i', $text, $matches)) {
+                // Direct chatterbox style message in the form `@botname [message]`
+                $matches = [$matches[0], $matches[1], $matches[1], $matches[2]];  //[match, command(botname), bot, message]
+            }else{
+                // Non-privacy mode, handle all.
+                $matches[1] = 'general';
+                $matches[3] = $text;
+            }
+        }

         return $matches;
     }
jonnywilliamson commented 9 years ago

Let me rather ask this question first: How does the bot handle messages in the form of @somename_bot [args]?

The Telegram Docs state

A bot running in privacy mode will not receive all messages that people send to the group. Instead, it will only receive:

All messages that start with a slash ‘/’ (see Commands above) Messages that @mention the bot by username Replies to the bot's own messages Service messages (people added or removed from the group, etc.)

No-where does it state that the bot should respond to a message with @botname_bot arg1 arg2 arg3.

The only thing that happens is that if a message has @botname_bot within it, it WILL be sent to either your webhook / or you can poll for it and it will be available.

It would be up to you to parse the message and detect what you want to do.

For example. say someone writes this message.

"Hey this @botname_name is pretty cool"

Should we try and parse that for a command of @botname_name and arguments of 1) is 2) pretty 3) cool

No I don't think so. That shouldn't be part of this package.

Remember though that you can easily pass each Update object after it's been parsed for normal commands to whatever system YOU would like to use to deal with a message that has the BOT mentioned in it.

I'll assume you're using Laravel and that you are using a webhook, but the same applies to polling etc.

In this case, when Telegram hits our server it gets handled by the telegramCallback() method:

<?php
use Telegram\Bot\Api;
use App\Http\Requests;
use Telegram\Bot\Objects\Update;

class TelegramBotController extends Controller
{
    protected $telegram;

    public function __construct(Api $telegram)
    {
        $this->telegram = $telegram;
    }

    public function telegramCallback()
    {
        $update = $this->telegram->commandsHandler(true);
       //Commands have been processed. Lets deal with @mentions

        if ($update->getMessage()->has('text') && str_contains($update->getMessage()->getText(), '@botname_bot')) {

          //Parse and do what you need to do here with the message.

        }

        return response('ok');
    }

}

So unless I'm missing something, I don't see that regex change as being a good idea.

vynes commented 9 years ago

Alright, thanks for the reply.

I'll close this now.

jonnywilliamson commented 9 years ago

Remember I'm not the author of this package! Maybe @irazasyed will think differently :)