Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5bff732814 | ||
![]() |
c52d2f3601 | ||
![]() |
f9741c250d | ||
![]() |
07ff3c4d2b | ||
![]() |
c4fdd71bdc | ||
![]() |
3c692424f7 | ||
![]() |
8408430ef8 | ||
![]() |
a66f27b5e6 | ||
![]() |
14c1aaaa44 | ||
![]() |
17318e5724 | ||
![]() |
69916fed3e | ||
![]() |
47f47f2110 | ||
![]() |
cb016a7fff | ||
![]() |
ca4bce7052 | ||
![]() |
f3af237d02 | ||
![]() |
1e151f9ce6 | ||
a9b314879a | |||
8c664e8127 |
10 changed files with 147 additions and 151 deletions
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -4,7 +4,35 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [8.0.0] - Ongoing
|
||||
## [8.0.2] - 2024-12-09
|
||||
|
||||
This update introduces some quality of life improvements.
|
||||
|
||||
### Added
|
||||
* Added `containsMedia` method to `Message` object to check if the message contains media.
|
||||
* Add support for handling callback query events
|
||||
|
||||
|
||||
## [8.0.1] - 2024-12-04
|
||||
|
||||
This update introduces bug fixes and improvements
|
||||
|
||||
### Changed
|
||||
* Refactor PollingBot to use PsyncLib for updates
|
||||
* Refactor optional parameters in method signatures
|
||||
* Improve command check with method existence validation
|
||||
|
||||
### Fixed
|
||||
* Reposition debug log for event handler execution.
|
||||
* Improve command check with method existence validation
|
||||
* Allow nullable type for MessageEntity type
|
||||
* Encode arrays as JSON in SendAudio parameters
|
||||
* Refactor fromArray method for null data handling
|
||||
|
||||
|
||||
## [8.0.0] - 2024-11-29
|
||||
|
||||
This is a new major update which makes the previous versions of this library deprecated
|
||||
|
||||
### Added
|
||||
* Added unit tests
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"package": "net.nosial.tgbotlib",
|
||||
"description": "TgBotLib is a library for interacting with the Telegram Bot API",
|
||||
"company": "Nosial",
|
||||
"version": "8.0.0",
|
||||
"version": "8.0.2",
|
||||
"uuid": "b409e036-ab04-11ed-b32e-9d3f57a644ae"
|
||||
},
|
||||
"build": {
|
||||
|
@ -36,6 +36,12 @@
|
|||
"version": "latest",
|
||||
"source_type": "remote",
|
||||
"source": "nosial/libs.opts=latest@n64"
|
||||
},
|
||||
{
|
||||
"name": "net.nosial.psynclib",
|
||||
"version": "latest",
|
||||
"source_type": "remote",
|
||||
"source": "nosial/libs.psync=latest@n64"
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
use TgBotLib\Enums\Types\ChatActionType;
|
||||
use TgBotLib\Enums\Types\ParseMode;
|
||||
use TgBotLib\Enums\Types\StickerFormat;
|
||||
use TgBotLib\Events\CallbackQueryEvent;
|
||||
use TgBotLib\Events\CommandEvent;
|
||||
use TgBotLib\Events\UpdateEvent;
|
||||
use TgBotLib\Exceptions\TelegramException;
|
||||
|
@ -117,9 +118,9 @@
|
|||
* @method bool setChatPhoto(string|int $chat_id, string $photo) Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
|
||||
* @method bool deleteChatPhoto(string|int $chat_id) Use this method to delete a chat photo. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
|
||||
* @method bool setChatTitle(string|int $chat_id, string $title) Use this method to change the title of a chat. Titles can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
|
||||
* @method bool setChatDescription(string|int $chat_id, string $description = null) Use this method to change the description of a group, a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
|
||||
* @method bool pinChatMessage(string|int $chat_id, int $message_id, string $business_connection_id = null, bool $disable_notification = null) Use this method to add a message to the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns True on success.
|
||||
* @method bool unpinChatMessage(string|int $chat_id, string $business_connection_id = null, int $message_id = null) Use this method to remove a message from the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns True on success.
|
||||
* @method bool setChatDescription(string|int $chat_id, ?string $description=null) Use this method to change the description of a group, a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success.
|
||||
* @method bool pinChatMessage(string|int $chat_id, int $message_id, ?string $business_connection_id=null, ?bool $disable_notification=null) Use this method to add a message to the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns True on success.
|
||||
* @method bool unpinChatMessage(string|int $chat_id, ?string $business_connection_id=null, ?int $message_id=null) Use this method to remove a message from the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns True on success.
|
||||
* @method bool unpinAllChatMessages(string|int $chat_id) Use this method to clear the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns True on success.
|
||||
* @method bool leaveChat(string|int $chat_id) Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
|
||||
* @method ChatFullInfo getChat(string|int $chat_id) Use this method to get up-to-date information about the chat. Returns a ChatFullInfo object on success.
|
||||
|
@ -129,8 +130,8 @@
|
|||
* @method bool setChatStickerSet(string|int $chat_id, string $sticker_set_name) Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Use the field can_set_sticker_set optionally returned in getChat requests to check if the bot can use this method. Returns True on success.
|
||||
* @method bool deleteChatStickerSet(string|int $chat_id) Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Use the field can_set_sticker_set optionally returned in getChat requests to check if the bot can use this method. Returns True on success.
|
||||
* @method Sticker[] getForumTopicIconStickers() Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. Requires no parameters. Returns an array of Sticker objects.
|
||||
* @method ForumTopic createForumTopic(string|int $chat_id, string $name, int $icon_color = null, string $icon_custom_emoji_id = null) Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns information about the created topic as a ForumTopic object.
|
||||
* @method bool editForumTopic(string|int $chat_id, int $message_thread_id, string $name = null, string $icon_custom_emoji_id = null) Use this method to edit the name and icon of a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
|
||||
* @method ForumTopic createForumTopic(string|int $chat_id, string $name, ?int $icon_color=null, ?string $icon_custom_emoji_id=null) Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns information about the created topic as a ForumTopic object.
|
||||
* @method bool editForumTopic(string|int $chat_id, int $message_thread_id, ?string $name=null, ?string $icon_custom_emoji_id=null) Use this method to edit the name and icon of a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
|
||||
* @method bool closeForumTopic(string|int $chat_id, int $message_thread_id) Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
|
||||
* @method bool reopenForumTopic(string|int $chat_id, int $message_thread_id) Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. Returns True on success.
|
||||
* @method bool deleteForumTopic(string|int $chat_id, int $message_thread_id) Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_delete_messages administrator rights. Returns True on success.
|
||||
|
@ -141,17 +142,17 @@
|
|||
* @method bool hideGeneralForumTopic(string|int $chat_id) Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. The topic will be automatically closed if it was open. Returns True on success.
|
||||
* @method bool unhideGeneralForumTopic(string|int $chat_id) Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns True on success.
|
||||
* @method bool unpinAllGeneralForumTopicMessages(string|int $chat_id) Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success.
|
||||
* @method bool answerCallbackQuery(string $callback_query_id, string $text = null, bool $show_alert = false, string $url = null, int $cache_time = 0) Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned. Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via @BotFather and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
|
||||
* @method bool answerCallbackQuery(string $callback_query_id, ?string $text=null, ?bool $show_alert=false, ?string $url=null, ?int $cache_time=null) Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned. Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first create a game for your bot via @BotFather and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
|
||||
* @method UserChatBoosts getUserChatBoosts(string|int $chat_id, int $user_id) Use this method to get the list of boosts added to a chat by a user. Requires administrator rights in the chat. Returns a UserChatBoosts object.
|
||||
* @method BusinessConnection getBusinessConnection(string $business_connection_id) Use this method to get information about the connection of the bot with a business account. Returns a BusinessConnection object on success.
|
||||
* @method bool setMyCommands(array $commands, BotCommandScope $scope=null, string $language_code=null) Use this method to change the list of the bot's commands. Returns True on success.
|
||||
* @method bool deleteMyCommands(BotCommandScope $scope = null, string $language_code = null) Use this method to delete the list of the bot's commands for the given scope and user language. After deletion, higher level commands will be shown to affected users. Returns True on success.
|
||||
* @method BotCommand[] getMyCommands(BotCommandScope $scope = null, string $language_code = "") Use this method to get the current list of the bot's commands for the given scope and user language. Returns an array of BotCommand objects. If commands aren't set, an empty list is returned.
|
||||
* @method bool setMyName(string $name = "", string $language_code = "") Use this method to change the bot's name. Returns True on success.
|
||||
* @method bool setMyCommands(array $commands, ?BotCommandScope $scope=null, ?string $language_code=null) Use this method to change the list of the bot's commands. Returns True on success.
|
||||
* @method bool deleteMyCommands(?BotCommandScope $scope=null, ?string $language_code=null) Use this method to delete the list of the bot's commands for the given scope and user language. After deletion, higher level commands will be shown to affected users. Returns True on success.
|
||||
* @method BotCommand[] getMyCommands(?BotCommandScope $scope=null, ?string $language_code=null) Use this method to get the current list of the bot's commands for the given scope and user language. Returns an array of BotCommand objects. If commands aren't set, an empty list is returned.
|
||||
* @method bool setMyName(?string $name=null, ?string $language_code=null) Use this method to change the bot's name. Returns True on success.
|
||||
* @method BotName getMyName(string $language_code) Use this method to get the current bot name for the given user language. Returns BotName on success.
|
||||
* @method bool setMyDescription(?string $description=null, ?string $language_code=null) Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. Returns True on success.
|
||||
* @method BotDescription getMyDescription(?string $language_code=null) Use this method to get the current bot description for the given user language. Returns BotDescription on success.
|
||||
* @method bool setMyShortDescription(string $short_description , string $language_code = "") Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. Returns True on success.
|
||||
* @method bool setMyShortDescription(string $short_description, ?string $language_code=null) Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. Returns True on success.
|
||||
* @method BotShortDescription getMyShortDescription(string $language_code) Use this method to get the current bot short description for the given user language. Returns BotShortDescription on success.
|
||||
* @method bool setChatMenuButton(?int $chat_id=null, ?MenuButton $menu_button=null) Use this method to change the bot's menu button in a private chat, or the default menu button. Returns True on success.
|
||||
* @method MenuButton getChatMenuButton(?int $chat_id=null) Use this method to get the current value of the bot's menu button in a private chat, or the default menu button. Returns MenuButton on success.
|
||||
|
@ -365,7 +366,28 @@
|
|||
/** @var UpdateEvent $eventHandler */
|
||||
foreach($this->eventHandlers as $eventHandler)
|
||||
{
|
||||
if(strtolower($eventHandler::getCommand()) === strtolower($command))
|
||||
if(method_exists($eventHandler, 'getCommand') && strtolower($eventHandler::getCommand()) === strtolower($command))
|
||||
{
|
||||
$results[] = $eventHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @method array getEventHandlersByCallbackQuery(string $callbackData) Retrieves an array of event handlers whose callback data matches the given parameter.
|
||||
* @param string $callbackData The callback data to match against the registered event handlers.
|
||||
* @return array An array of matching event handler instances.
|
||||
*/
|
||||
public function getEventHandlersByCallbackQuery(string $callbackData): array
|
||||
{
|
||||
$results = [];
|
||||
/** @var UpdateEvent $eventHandler */
|
||||
foreach($this->eventHandlers as $eventHandler)
|
||||
{
|
||||
if(method_exists($eventHandler, 'getCallbackData') && $eventHandler::getCallbackData() === $callbackData)
|
||||
{
|
||||
$results[] = $eventHandler;
|
||||
}
|
||||
|
@ -428,7 +450,6 @@
|
|||
$command = $update?->getAnyMessage()?->getCommand();
|
||||
if($command !== null)
|
||||
{
|
||||
$commandExecuted = false;
|
||||
Logger::getLogger()->debug(sprintf('Executing command %s for update %s', $command, $update->getUpdateId()));
|
||||
|
||||
/** @var CommandEvent $eventHandler */
|
||||
|
@ -437,7 +458,6 @@
|
|||
try
|
||||
{
|
||||
(new $eventHandler($update))->handle($this);
|
||||
$commandExecuted = true;
|
||||
}
|
||||
catch(TelegramException $e)
|
||||
{
|
||||
|
@ -448,10 +468,28 @@
|
|||
Logger::getLogger()->error(sprintf('Exception occurred: %s', $e->getMessage()), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($commandExecuted)
|
||||
$callbackData = $update?->getCallbackQuery()?->getData();
|
||||
if($callbackData !== null)
|
||||
{
|
||||
return;
|
||||
Logger::getLogger()->debug(sprintf('Executing callback query %s for update %s', $callbackData, $update->getUpdateId()));
|
||||
|
||||
/** @var CallbackQueryEvent $eventHandler */
|
||||
foreach($this->getEventHandlersByCallbackQuery($callbackData) as $eventHandler)
|
||||
{
|
||||
try
|
||||
{
|
||||
(new $eventHandler($update))->handle($this);
|
||||
}
|
||||
catch(TelegramException $e)
|
||||
{
|
||||
Logger::getLogger()->error(sprintf('Telegram exception occurred: %s', $e->getMessage()), $e);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
Logger::getLogger()->error(sprintf('Exception occurred: %s', $e->getMessage()), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,9 +523,9 @@
|
|||
|
||||
// Execute all event handlers that match the update type
|
||||
/** @var UpdateEvent $eventHandler */
|
||||
Logger::getLogger()->debug(sprintf('Executing event handler for type %s for update %s', $eventHandler::getEventType()->value, $update->getUpdateId()));
|
||||
foreach($eventHandlers as $eventHandler)
|
||||
{
|
||||
Logger::getLogger()->debug(sprintf('Executing event handler for type %s for update %s', $eventHandler::getEventType()->value, $update->getUpdateId()));
|
||||
try
|
||||
{
|
||||
(new $eventHandler($update))->handle($this);
|
||||
|
@ -503,6 +541,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an array of updates.
|
||||
*
|
||||
* @param array $updates An array containing update objects to be handled. Each update will be individually processed by calling the handleUpdate method.
|
||||
* @return void This method does not return a value.
|
||||
*/
|
||||
public function handleUpdates(array $updates): void
|
||||
{
|
||||
foreach($updates as $update)
|
||||
{
|
||||
$this->handleUpdate($update);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request by executing the specified method with the given parameters.
|
||||
*
|
||||
|
|
|
@ -115,11 +115,6 @@
|
|||
return EventType::SHIPPING_QUERY;
|
||||
}
|
||||
|
||||
if($update->getCallbackQuery() !== null)
|
||||
{
|
||||
return EventType::CALLBACK_QUERY;
|
||||
}
|
||||
|
||||
if($update->getChosenInlineResult() !== null)
|
||||
{
|
||||
return EventType::CHOSEN_INLINE_RESULT;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace TgBotLib\Events;
|
||||
|
||||
use LogicException;
|
||||
use TgBotLib\Enums\EventType;
|
||||
use TgBotLib\Objects\CallbackQuery;
|
||||
|
||||
|
@ -15,6 +16,13 @@
|
|||
return EventType::CALLBACK_QUERY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data associated with the callback.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public abstract static function getCallbackData(): string;
|
||||
|
||||
/**
|
||||
* New incoming callback query
|
||||
*
|
||||
|
|
|
@ -48,12 +48,12 @@
|
|||
$entities[] = $entity;
|
||||
}
|
||||
}
|
||||
$parameters['caption_entities'] = $entities;
|
||||
$parameters['caption_entities'] = json_encode($entities);
|
||||
}
|
||||
|
||||
if(isset($parameters['reply_parameters']) && $parameters['reply_parameters'] instanceof ReplyParameters)
|
||||
if(isset($parameters['reply_parameters']) && $parameters['reply_parameters'] instanceof ObjectTypeInterface)
|
||||
{
|
||||
$parameters['reply_parameters'] = $parameters['reply_parameters']->toArray();
|
||||
$parameters['reply_parameters'] = json_encode($parameters['reply_parameters']->toArray());
|
||||
}
|
||||
|
||||
if (isset($parameters['reply_markup']))
|
||||
|
|
|
@ -317,7 +317,7 @@ class ExternalReplyInfo implements ObjectTypeInterface
|
|||
* @inheritDoc
|
||||
* @noinspection DuplicatedCode
|
||||
*/
|
||||
public static function fromArray(array $data): ObjectTypeInterface
|
||||
public static function fromArray(?array $data): ?ExternalReplyInfo
|
||||
{
|
||||
$object = new self();
|
||||
|
||||
|
|
|
@ -1061,6 +1061,16 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any media content is present in the message.
|
||||
*
|
||||
* @return bool True if media content is present, false otherwise.
|
||||
*/
|
||||
public function containsMedia(): bool
|
||||
{
|
||||
return $this->getPhoto() !== null || $this->getAnimation() !== null || $this->getAudio() !== null || $this->getDocument() !== null || $this->getSticker() !== null || $this->getVideo() !== null || $this->getVideoNote() !== null || $this->getVoice() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
class MessageEntity implements ObjectTypeInterface
|
||||
{
|
||||
private MessageEntityType $type;
|
||||
private ?MessageEntityType $type;
|
||||
private int $offset;
|
||||
private int $length;
|
||||
private ?string $url;
|
||||
|
@ -23,9 +23,9 @@
|
|||
* (monowidth block), “text_link” (for clickable text URLs), “text_mention” (for users without usernames),
|
||||
* “custom_emoji” (for inline custom emoji stickers)
|
||||
*
|
||||
* @return MessageEntityType
|
||||
* @return ?MessageEntityType
|
||||
*/
|
||||
public function getType(): MessageEntityType
|
||||
public function getType(): ?MessageEntityType
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
@ -33,10 +33,10 @@
|
|||
/**
|
||||
* Sets the type of the entity
|
||||
*
|
||||
* @param MessageEntityType $type
|
||||
* @param ?MessageEntityType $type
|
||||
* @return MessageEntity
|
||||
*/
|
||||
public function setType(MessageEntityType $type): MessageEntity
|
||||
public function setType(?MessageEntityType $type): MessageEntity
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
|
@ -223,7 +223,7 @@
|
|||
}
|
||||
|
||||
$object = new self();
|
||||
$object->type = MessageEntityType::tryFrom($data['type']);
|
||||
$object->type = is_null($data['type']) ? null : MessageEntityType::tryFrom($data['type']);
|
||||
$object->offset = $data['offset'] ?? null;
|
||||
$object->length = $data['length'] ?? null;
|
||||
$object->url = $data['url'] ?? null;
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace TgBotLib;
|
||||
|
||||
use RuntimeException;
|
||||
use function RuntimeException;
|
||||
use PsyncLib\Psync;
|
||||
|
||||
/**
|
||||
* PollingBot class that extends Bot for handling updates using polling.
|
||||
|
@ -14,8 +13,6 @@
|
|||
private int $limit;
|
||||
private int $timeout;
|
||||
private array $allowedUpdates;
|
||||
private bool $fork;
|
||||
private array $childPids;
|
||||
|
||||
/**
|
||||
* Constructor for the class, initializing with a Bot instance.
|
||||
|
@ -30,8 +27,6 @@
|
|||
$this->limit = 100;
|
||||
$this->timeout = 0;
|
||||
$this->allowedUpdates = [];
|
||||
$this->fork = false;
|
||||
$this->childPids = [];
|
||||
|
||||
// Register signal handler for child processes
|
||||
if (function_exists('pcntl_signal'))
|
||||
|
@ -115,6 +110,11 @@
|
|||
$this->allowedUpdates = $allowedUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of allowed updates.
|
||||
*
|
||||
* @return array Returns an array containing the allowed updates.
|
||||
*/
|
||||
public function getAllowedUpdates(): array
|
||||
{
|
||||
return $this->allowedUpdates;
|
||||
|
@ -137,55 +137,14 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the fork value.
|
||||
* Polls for updates and processes them. Installs a signal handler if
|
||||
* needed, fetches updates, tracks the highest update ID, updates the
|
||||
* polling offset, and handles the updates using the Psync mechanism.
|
||||
*
|
||||
* @param bool $fork The fork value to set.
|
||||
* @return void
|
||||
* @return void This method does not return any value.
|
||||
*/
|
||||
public function setFork(bool $fork): void
|
||||
public function poll(): void
|
||||
{
|
||||
$this->fork = $fork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current fork setting.
|
||||
*
|
||||
* @return bool The configured fork value.
|
||||
*/
|
||||
public function getFork(): bool
|
||||
{
|
||||
return $this->fork;
|
||||
}
|
||||
|
||||
private function signalHandler(int $signal): void
|
||||
{
|
||||
if ($signal === SIGCHLD)
|
||||
{
|
||||
$i = -1;
|
||||
while (($pid = pcntl_wait($i, WNOHANG)) > 0)
|
||||
{
|
||||
$key = array_search($pid, $this->childPids);
|
||||
if ($key !== false)
|
||||
{
|
||||
unset($this->childPids[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming updates by fetching and processing them with appropriate event handlers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handleUpdates(): void
|
||||
{
|
||||
// Install signal handler
|
||||
if ($this->fork && function_exists('pcntl_signal_dispatch'))
|
||||
{
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
|
||||
$updates = $this->getUpdates(offset: ($this->offset ?: 0), limit: $this->limit, timeout: $this->timeout, allowed_updates: $this->retrieveAllowedUpdates());
|
||||
|
||||
if (empty($updates))
|
||||
|
@ -195,7 +154,6 @@
|
|||
|
||||
// Track the highest update ID we've seen
|
||||
$maxUpdateId = null;
|
||||
|
||||
foreach ($updates as $update)
|
||||
{
|
||||
// Update the maximum update ID as we go
|
||||
|
@ -203,56 +161,6 @@
|
|||
{
|
||||
$maxUpdateId = $update->getUpdateId();
|
||||
}
|
||||
|
||||
if ($this->fork)
|
||||
{
|
||||
// Clean up any finished processes
|
||||
if (function_exists('pcntl_signal_dispatch'))
|
||||
{
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
|
||||
$pid = pcntl_fork();
|
||||
|
||||
if ($pid == -1)
|
||||
{
|
||||
// Fork failed
|
||||
throw new RuntimeException('Failed to fork process for update handling');
|
||||
}
|
||||
elseif ($pid)
|
||||
{
|
||||
// Parent process
|
||||
$this->childPids[] = $pid;
|
||||
|
||||
// If we have too many child processes, wait for some to finish
|
||||
$maxChildren = 32; // Adjust this value based on your system's capabilities
|
||||
while (count($this->childPids) >= $maxChildren)
|
||||
{
|
||||
if (function_exists('pcntl_signal_dispatch'))
|
||||
{
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
|
||||
usleep(10000); // Sleep for 10ms to prevent CPU hogging
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Child process
|
||||
try
|
||||
{
|
||||
$this->handleUpdate($update);
|
||||
}
|
||||
finally
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->handleUpdate($update);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the offset based on the highest update ID we've seen
|
||||
|
@ -261,20 +169,9 @@
|
|||
$this->offset = $maxUpdateId + 1;
|
||||
}
|
||||
|
||||
// If forking is enabled, ensure we clean up any remaining child processes
|
||||
if ($this->fork)
|
||||
{
|
||||
// Wait for remaining child processes to finish
|
||||
while (!empty($this->childPids))
|
||||
{
|
||||
if (function_exists('pcntl_signal_dispatch'))
|
||||
{
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
|
||||
usleep(10000); // Sleep for 10ms to prevent CPU hogging
|
||||
}
|
||||
}
|
||||
// Pass the method name as a string and the object
|
||||
Psync::do([$this, 'handleUpdates'], [$updates]);
|
||||
Psync::clean();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue