mirror of
https://github.com/BushlanovDev/max-bot-api-client-php.git
synced 2026-08-21 22:13:41 +00:00
105 lines
3.2 KiB
PHP
105 lines
3.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace BushlanovDev\MaxMessengerBot;
|
|
|
|
use BushlanovDev\MaxMessengerBot\Exceptions\NetworkException;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
/**
|
|
* Handles receiving updates via long polling.
|
|
*/
|
|
final readonly class LongPollingHandler
|
|
{
|
|
/**
|
|
* @param Api $api
|
|
* @param UpdateDispatcher $dispatcher The update dispatcher.
|
|
* @param LoggerInterface $logger PSR LoggerInterface.
|
|
* @codeCoverageIgnore
|
|
*/
|
|
public function __construct(
|
|
private Api $api,
|
|
private UpdateDispatcher $dispatcher,
|
|
private LoggerInterface $logger,
|
|
) {
|
|
if (!(\PHP_SAPI === 'cli')) {
|
|
throw new \RuntimeException('LongPollingHandler can only be used in CLI mode.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Processes a single batch of updates. Useful for custom loop implementations or for testing.
|
|
*
|
|
* @param int $timeout Timeout for the getUpdates call.
|
|
* @param int|null $marker The marker for which updates to fetch.
|
|
* @return int|null The new marker to be used for the next iteration.
|
|
* @throws \Exception Re-throws exceptions from the API or dispatcher.
|
|
*/
|
|
public function processUpdates(int $timeout, ?int $marker): ?int
|
|
{
|
|
$updateList = $this->api->getUpdates(timeout: $timeout, marker: $marker);
|
|
|
|
foreach ($updateList->updates as $update) {
|
|
try {
|
|
$this->dispatcher->dispatch($update);
|
|
} catch (\Throwable $e) {
|
|
$this->logger->error('Error dispatching update', [
|
|
'message' => $e->getMessage(),
|
|
'exception' => $e,
|
|
]);
|
|
}
|
|
}
|
|
|
|
return $updateList->marker;
|
|
}
|
|
|
|
/**
|
|
* Starts a long-polling loop to process updates.
|
|
* This method will run indefinitely until the script is terminated.
|
|
*
|
|
* @param int $timeout Timeout in seconds for long polling (0-90).
|
|
* @param int|null $marker Initial marker. Pass `null` to get updates you didn't get yet.
|
|
*/
|
|
public function handle(int $timeout = 90, ?int $marker = null): void
|
|
{
|
|
$this->listenSignals();
|
|
// @phpstan-ignore-next-line
|
|
while (true) {
|
|
try {
|
|
$marker = $this->processUpdates($timeout, $marker);
|
|
} catch (NetworkException $e) {
|
|
$this->logger->error(
|
|
'Long-polling network error: {message}',
|
|
['message' => $e->getMessage(), 'exception' => $e],
|
|
);
|
|
sleep(5);
|
|
} catch (\Exception $e) {
|
|
$this->logger->error(
|
|
'An error occurred during long-polling: {message}',
|
|
['message' => $e->getMessage(), 'exception' => $e],
|
|
);
|
|
sleep(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @codeCoverageIgnore
|
|
*/
|
|
protected function listenSignals(): void
|
|
{
|
|
if (extension_loaded('pcntl')) {
|
|
pcntl_async_signals(true);
|
|
|
|
$kill = static function () {
|
|
exit(0);
|
|
};
|
|
|
|
pcntl_signal(SIGINT, $kill);
|
|
pcntl_signal(SIGQUIT, $kill);
|
|
pcntl_signal(SIGTERM, $kill);
|
|
}
|
|
}
|
|
}
|