Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

How many times BuildPayload method should be called? #1405

Open
legreco opened this issue May 9, 2024 · 1 comment
Open

How many times BuildPayload method should be called? #1405

legreco opened this issue May 9, 2024 · 1 comment

Comments

@legreco
Copy link

legreco commented May 9, 2024

  • BotMan Version: 2.8.3
  • PHP Version: 8.1
  • Messaging Service(s): WhatsApp Cloud API
  • PHP Framework: Laravel 10
  • Cache Driver: Redis
  • Additional informations: I use spatie webhook client

Description:

I am working on a WhatsApp Chatbot project. I have created a custom whatsapp custom driver. Due to whatsapp cloud API recommandations, when the program receive a WhatsAPP payload, it acknowledge first with a HTTP OK 200 Response, and then do the necessary processing to answer the message.
I use spatie webhook Client to automatically queue the request payload. After that in specific Job i take the payload and pass it to botman like that:

Steps To Reproduce:

Async Version

public function handle(): void
    {
        $this->init();
        $this->mapBotManCommands($this->botman);
        $this->botman->listen();
    }

  protected function init()
    {
        $this->request =Request::create(
            "",
            "POST",
            [],
            [],
            [],
            [],
            json_encode($this->webhookCall->payload)
        );
       $app = Container::getInstance();
       DriverManager::loadDriver(WhatsAppDriver::class);
$app->scoped('botman', function ($app)  {
 $storage = new FileStorage(storage_path('botman'));
$this->botman = BotManFactory::create(config('botman', []), new LaravelCache(), $this->request,
  $storage);
 $botman->setContainer(new LaravelContainer($app));
          return $botman;
     });
    }

  protected function mapBotManCommands(BotMan $botMan)
    {
        $botMan->hears('test', function (BotMan $bot) {
            $bot->reply("Tell me more!");
        });
    }

In My WhatsAppDriver BuildPayload Method

 public function buildPayload(Request $request)
    {
 
    var_dump(json_decode($request->getContent(),true));  // To see the request content
   
        $this->payload = new ParameterBag((array) json_decode($request->getContent(), true)['entry'][0]['changes'][0]['value']);
        $this->event = Collection::make((array) $this->payload->get('messages') ? (array) $this->payload->get('messages')[0] : $this->payload);
        $this->content = $request->getContent();
      $this->config = Collection::make($this->config->get('whatsapp', []));


    }

observations on the async version

When sending a correct payload to my endpoint
I get an error like the array that i am trying to access is null in this line:

$this->payload = new ParameterBag((array) json_decode($request->getContent(), true)['entry'][0]['changes'][0]['value']);

After digging i realized that the buildPayload Method is called twice
the first time with a valid request object (containing the expected payload), and the second time with an empty request payload which causes the error.
After days and days of trying to understand what happened, i decided to make a Sync version of the endpoint

Sync Version

class BotmanTestController extends Controller
{
/**
* Provision a new web server.
*/
public function __invoke(Request $request)
{
DriverManager::loadDriver(WhatsAppDriver::class);
$storage = new FileStorage(storage_path('botman'));
$botman = BotManFactory::create(config('botman', []), new LaravelCache(), $request, $storage);
$botman->hears('test', function (BotMan $bot) {
$bot->reply("Tell me more!");
});
$botman->listen();
return response()->json(['message'=>'ok']);
}
}

observations on the sync version

The buildpayload method is still called twice but this times with the same request containing the right payload so there is no errors.

My Questions

  1. I've read in botman documentation that buildpayload in called each time a driver is intanciated, is that normal that this method get called twice in the lifecyle of a botman response?
  2. If yes, so what am i doing wrong in the async version of my code?

Thank you

@filippotoso
Copy link
Collaborator

filippotoso commented May 10, 2024

Use https://www.php.net/debug_print_backtrace to check why buildPayload() is called twice.

Please keep in mind that the Telegram Drivers verifies the request before handling it:

https://github.com/botman/driver-telegram/blob/master/src/TelegramDriver.php#L181

In your Async version, you are recreating the request without an URL, but the query parameters are used to validate the hash against the bot token, so you should also handle that part.

Also, you should try following these instructions replacing the Telegram Driver with your own and see if it works correctly:

#1308 (comment)

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

No branches or pull requests

2 participants