Performance improvements
This commit is contained in:
parent
17bacd1389
commit
f8ea85a551
@ -11,7 +11,6 @@
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"danog/primemodule": "^1",
|
||||
"danog/magicalserializer": "^1.0",
|
||||
"danog/tgseclib": "^3",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"ext-mbstring": "*",
|
||||
@ -31,7 +30,8 @@
|
||||
"danog/dns-over-https": "^0.2",
|
||||
"amphp/http-client-cookies": "^1",
|
||||
"amphp/uri": "^0.1",
|
||||
"danog/tg-file-decoder": "^0.1"
|
||||
"danog/tg-file-decoder": "^0.1",
|
||||
"danog/magicalserializer": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"vlucas/phpdotenv": "^3",
|
||||
|
@ -97,7 +97,7 @@ abstract class AbstractAPIFactory extends AsyncConstruct
|
||||
public function __call(string $name, array $arguments)
|
||||
{
|
||||
$yielded = Tools::call($this->__call_async($name, $arguments));
|
||||
$async = $this->lua === false && (\is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async && $name !== 'loop');
|
||||
$async = !$this->lua && (\end($arguments)['async'] ?? ($this->async && $name !== 'loop'));
|
||||
if ($async) {
|
||||
return $yielded;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ namespace danog\MadelineProto;
|
||||
|
||||
use Amp\ByteStream\ClosedException;
|
||||
use Amp\Deferred;
|
||||
use Amp\Promise;
|
||||
use danog\MadelineProto\Loop\Connection\CheckLoop;
|
||||
use danog\MadelineProto\Loop\Connection\HttpWaitLoop;
|
||||
use danog\MadelineProto\Loop\Connection\PingLoop;
|
||||
@ -116,7 +115,7 @@ class Connection extends Session
|
||||
*
|
||||
* @var MTProto
|
||||
*/
|
||||
protected $API;
|
||||
public $API;
|
||||
/**
|
||||
* Shared connection instance.
|
||||
*
|
||||
|
@ -479,8 +479,10 @@ class DataCenterConnection implements JsonSerializable
|
||||
$count = \count($backup);
|
||||
$this->API->logger->logger("Restoring {$count} messages to DC {$this->datacenter}");
|
||||
foreach ($backup as $message) {
|
||||
if (isset($message['body'])) {
|
||||
Tools::callFork($this->getConnection()->sendMessage($message, false));
|
||||
}
|
||||
}
|
||||
$this->flush();
|
||||
}
|
||||
/**
|
||||
|
@ -40,7 +40,7 @@ class Exception extends \Exception
|
||||
if (\strpos($message, 'socket_accept') === false) {
|
||||
\danog\MadelineProto\Logger::log($message . ' in ' . \basename($this->file) . ':' . $this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
|
||||
}
|
||||
if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/phpseclib'])) {
|
||||
if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/tgseclib'])) {
|
||||
return;
|
||||
}
|
||||
if (\strpos($message, 'pg_query') !== false || \strpos($message, 'Undefined variable: ') !== false || \strpos($message, 'socket_write') !== false || \strpos($message, 'socket_read') !== false || \strpos($message, 'Received request to switch to DC ') !== false || \strpos($message, "Couldn't get response") !== false || \strpos($message, 'Re-executing query...') !== false || \strpos($message, "Couldn't find peer by provided") !== false || \strpos($message, 'id.pwrtelegram.xyz') !== false || \strpos($message, 'Please update ') !== false || \strpos($message, 'posix_isatty') !== false) {
|
||||
|
@ -4224,7 +4224,7 @@ class InternalDoc extends APIFactory
|
||||
* @param array $args Arguments
|
||||
* @param array $aargs Additional arguments
|
||||
*
|
||||
* @return Promise
|
||||
* @return \Generator
|
||||
*/
|
||||
public function methodCall(string $method, $args = [
|
||||
], array $aargs = [
|
||||
@ -4240,7 +4240,7 @@ class InternalDoc extends APIFactory
|
||||
* @param array $args Arguments
|
||||
* @param array $aargs Additional arguments
|
||||
*
|
||||
* @return Promise
|
||||
* @return \Generator
|
||||
*/
|
||||
public function methodCallWrite(string $method, $args = [
|
||||
], array $aargs = [
|
||||
@ -4725,13 +4725,13 @@ class InternalDoc extends APIFactory
|
||||
/**
|
||||
* Unpack bot API file ID.
|
||||
*
|
||||
* @param string $file_id Bot API file ID
|
||||
* @param string $fileId Bot API file ID
|
||||
*
|
||||
* @return array Unpacked file ID
|
||||
*/
|
||||
public function unpackFileId(string $file_id): array
|
||||
public function unpackFileId(string $fileId): array
|
||||
{
|
||||
return $this->API->unpackFileId($file_id);
|
||||
return $this->API->unpackFileId($fileId);
|
||||
}
|
||||
/**
|
||||
* Get mime type from file extension.
|
||||
@ -5310,7 +5310,7 @@ class InternalDoc extends APIFactory
|
||||
*
|
||||
* @return \Generator
|
||||
*/
|
||||
public function discardCall(array $call, string $reason, array $rating = [
|
||||
public function discardCall(array $call, array $reason, array $rating = [
|
||||
], bool $need_debug = true, array $extra = [])
|
||||
{
|
||||
return $this->__call(__FUNCTION__, [$call, $reason, $rating, $need_debug, $extra]);
|
||||
@ -5585,6 +5585,17 @@ class InternalDoc extends APIFactory
|
||||
{
|
||||
$this->API->stop();
|
||||
}
|
||||
/**
|
||||
* Start MadelineProto's update handling loop in background, or run the provided async callable.
|
||||
*
|
||||
* @param callable $callback Async callable to run
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function loopFork($callback = null): void
|
||||
{
|
||||
$this->API->loopFork($callback);
|
||||
}
|
||||
/**
|
||||
* Close connection with client, connected via web.
|
||||
*
|
||||
|
@ -5629,6 +5629,108 @@ Contains the reason why access to a certain object must be restricted. Clients a
|
||||
'object_message_param_reactions_type_MessageReactions' => '',
|
||||
'object_message_param_restriction_reason_type_string' => '',
|
||||
'object_messageReactions_param_results_type_Vector t' => '',
|
||||
'method_auth.exportLoginToken' => '',
|
||||
'method_auth.exportLoginToken_param_api_id_type_int' => '',
|
||||
'method_auth.exportLoginToken_param_api_hash_type_string' => '',
|
||||
'method_auth.exportLoginToken_param_except_ids_type_Vector t' => '',
|
||||
'method_auth.importLoginToken' => '',
|
||||
'method_auth.importLoginToken_param_token_type_bytes' => '',
|
||||
'method_auth.acceptLoginToken' => '',
|
||||
'method_auth.acceptLoginToken_param_token_type_bytes' => '',
|
||||
'method_account.createTheme_param_settings_type_InputThemeSettings' => '',
|
||||
'method_account.updateTheme_param_settings_type_InputThemeSettings' => '',
|
||||
'method_account.setContentSettings' => '',
|
||||
'method_account.setContentSettings_param_sensitive_enabled_type_true' => '',
|
||||
'method_account.getContentSettings' => '',
|
||||
'method_account.getMultiWallPapers' => '',
|
||||
'method_account.getMultiWallPapers_param_wallpapers_type_Vector t' => '',
|
||||
'method_messages.getPollVotes' => '',
|
||||
'method_messages.getPollVotes_param_peer_type_InputPeer' => '',
|
||||
'method_messages.getPollVotes_param_id_type_int' => '',
|
||||
'method_messages.getPollVotes_param_option_type_bytes' => '',
|
||||
'method_messages.getPollVotes_param_offset_type_string' => '',
|
||||
'method_messages.getPollVotes_param_limit_type_int' => '',
|
||||
'method_upload.getFile_param_cdn_supported_type_true' => '',
|
||||
'method_channels.getInactiveChannels' => '',
|
||||
'object_inputMediaPoll_param_correct_answers_type_Vector t' => '',
|
||||
'object_wallPaperNoFile' => '',
|
||||
'object_wallPaperNoFile_param_default_type_true' => '',
|
||||
'object_wallPaperNoFile_param_dark_type_true' => '',
|
||||
'object_wallPaperNoFile_param_settings_type_WallPaperSettings' => '',
|
||||
'object_updateGeoLiveViewed' => '',
|
||||
'object_updateGeoLiveViewed_param_peer_type_Peer' => '',
|
||||
'object_updateGeoLiveViewed_param_msg_id_type_int' => '',
|
||||
'object_updateLoginToken' => '',
|
||||
'object_updateMessagePollVote' => '',
|
||||
'object_updateMessagePollVote_param_poll_id_type_long' => '',
|
||||
'object_updateMessagePollVote_param_user_id_type_int' => '',
|
||||
'object_updateMessagePollVote_param_options_type_Vector t' => '',
|
||||
'object_webPage_param_attributes_type_Vector t' => '',
|
||||
'object_keyboardButtonRequestPoll' => '',
|
||||
'object_keyboardButtonRequestPoll_param_quiz_type_Bool' => '',
|
||||
'object_keyboardButtonRequestPoll_param_text_type_string' => '',
|
||||
'object_poll_param_public_voters_type_true' => '',
|
||||
'object_poll_param_multiple_choice_type_true' => '',
|
||||
'object_poll_param_quiz_type_true' => '',
|
||||
'object_pollAnswerVoters_param_correct_type_true' => '',
|
||||
'object_pollResults_param_recent_voters_type_Vector t' => '',
|
||||
'object_inputWallPaperNoFile' => '',
|
||||
'object_wallPaperSettings_param_second_background_color_type_int' => '',
|
||||
'object_wallPaperSettings_param_rotation_type_int' => '',
|
||||
'object_autoDownloadSettings_param_video_upload_maxbitrate_type_int' => '',
|
||||
'object_theme_param_settings_type_ThemeSettings' => '',
|
||||
'object_auth.loginToken' => '',
|
||||
'object_auth.loginToken_param_expires_type_int' => '',
|
||||
'object_auth.loginToken_param_token_type_bytes' => '',
|
||||
'object_auth.loginTokenMigrateTo' => '',
|
||||
'object_auth.loginTokenMigrateTo_param_dc_id_type_int' => '',
|
||||
'object_auth.loginTokenMigrateTo_param_token_type_bytes' => '',
|
||||
'object_auth.loginTokenSuccess' => '',
|
||||
'object_auth.loginTokenSuccess_param_authorization_type_auth.Authorization' => '',
|
||||
'object_account.contentSettings' => '',
|
||||
'object_account.contentSettings_param_sensitive_enabled_type_true' => '',
|
||||
'object_account.contentSettings_param_sensitive_can_change_type_true' => '',
|
||||
'object_messages.inactiveChats' => '',
|
||||
'object_messages.inactiveChats_param_dates_type_Vector t' => '',
|
||||
'object_messages.inactiveChats_param_chats_type_Vector t' => '',
|
||||
'object_messages.inactiveChats_param_users_type_Vector t' => '',
|
||||
'object_baseThemeClassic' => '',
|
||||
'object_baseThemeDay' => '',
|
||||
'object_baseThemeNight' => '',
|
||||
'object_baseThemeTinted' => '',
|
||||
'object_baseThemeArctic' => '',
|
||||
'object_inputThemeSettings' => '',
|
||||
'object_inputThemeSettings_param_base_theme_type_BaseTheme' => '',
|
||||
'object_inputThemeSettings_param_accent_color_type_int' => '',
|
||||
'object_inputThemeSettings_param_message_top_color_type_int' => '',
|
||||
'object_inputThemeSettings_param_message_bottom_color_type_int' => '',
|
||||
'object_inputThemeSettings_param_wallpaper_type_InputWallPaper' => '',
|
||||
'object_inputThemeSettings_param_wallpaper_settings_type_WallPaperSettings' => '',
|
||||
'object_themeSettings' => '',
|
||||
'object_themeSettings_param_base_theme_type_BaseTheme' => '',
|
||||
'object_themeSettings_param_accent_color_type_int' => '',
|
||||
'object_themeSettings_param_message_top_color_type_int' => '',
|
||||
'object_themeSettings_param_message_bottom_color_type_int' => '',
|
||||
'object_themeSettings_param_wallpaper_type_WallPaper' => '',
|
||||
'object_webPageAttributeTheme' => '',
|
||||
'object_webPageAttributeTheme_param_documents_type_Vector t' => '',
|
||||
'object_webPageAttributeTheme_param_settings_type_ThemeSettings' => '',
|
||||
'object_messageUserVote' => '',
|
||||
'object_messageUserVote_param_user_id_type_int' => '',
|
||||
'object_messageUserVote_param_option_type_bytes' => '',
|
||||
'object_messageUserVote_param_date_type_int' => '',
|
||||
'object_messageUserVoteInputOption' => '',
|
||||
'object_messageUserVoteInputOption_param_user_id_type_int' => '',
|
||||
'object_messageUserVoteInputOption_param_date_type_int' => '',
|
||||
'object_messageUserVoteMultiple' => '',
|
||||
'object_messageUserVoteMultiple_param_user_id_type_int' => '',
|
||||
'object_messageUserVoteMultiple_param_options_type_Vector t' => '',
|
||||
'object_messageUserVoteMultiple_param_date_type_int' => '',
|
||||
'object_messages.votesList' => '',
|
||||
'object_messages.votesList_param_count_type_int' => '',
|
||||
'object_messages.votesList_param_votes_type_Vector t' => '',
|
||||
'object_messages.votesList_param_users_type_Vector t' => '',
|
||||
'object_messages.votesList_param_next_offset_type_string' => '',
|
||||
],
|
||||
];
|
||||
|
||||
@ -11099,5 +11201,107 @@ Contains the reason why access to a certain object must be restricted. Clients a
|
||||
'object_message_param_reactions_type_MessageReactions' => '',
|
||||
'object_message_param_restriction_reason_type_string' => '',
|
||||
'object_messageReactions_param_results_type_Vector t' => '',
|
||||
'method_auth.exportLoginToken' => '',
|
||||
'method_auth.exportLoginToken_param_api_id_type_int' => '',
|
||||
'method_auth.exportLoginToken_param_api_hash_type_string' => '',
|
||||
'method_auth.exportLoginToken_param_except_ids_type_Vector t' => '',
|
||||
'method_auth.importLoginToken' => '',
|
||||
'method_auth.importLoginToken_param_token_type_bytes' => '',
|
||||
'method_auth.acceptLoginToken' => '',
|
||||
'method_auth.acceptLoginToken_param_token_type_bytes' => '',
|
||||
'method_account.createTheme_param_settings_type_InputThemeSettings' => '',
|
||||
'method_account.updateTheme_param_settings_type_InputThemeSettings' => '',
|
||||
'method_account.setContentSettings' => '',
|
||||
'method_account.setContentSettings_param_sensitive_enabled_type_true' => '',
|
||||
'method_account.getContentSettings' => '',
|
||||
'method_account.getMultiWallPapers' => '',
|
||||
'method_account.getMultiWallPapers_param_wallpapers_type_Vector t' => '',
|
||||
'method_messages.getPollVotes' => '',
|
||||
'method_messages.getPollVotes_param_peer_type_InputPeer' => '',
|
||||
'method_messages.getPollVotes_param_id_type_int' => '',
|
||||
'method_messages.getPollVotes_param_option_type_bytes' => '',
|
||||
'method_messages.getPollVotes_param_offset_type_string' => '',
|
||||
'method_messages.getPollVotes_param_limit_type_int' => '',
|
||||
'method_upload.getFile_param_cdn_supported_type_true' => '',
|
||||
'method_channels.getInactiveChannels' => '',
|
||||
'object_inputMediaPoll_param_correct_answers_type_Vector t' => '',
|
||||
'object_wallPaperNoFile' => '',
|
||||
'object_wallPaperNoFile_param_default_type_true' => '',
|
||||
'object_wallPaperNoFile_param_dark_type_true' => '',
|
||||
'object_wallPaperNoFile_param_settings_type_WallPaperSettings' => '',
|
||||
'object_updateGeoLiveViewed' => '',
|
||||
'object_updateGeoLiveViewed_param_peer_type_Peer' => '',
|
||||
'object_updateGeoLiveViewed_param_msg_id_type_int' => '',
|
||||
'object_updateLoginToken' => '',
|
||||
'object_updateMessagePollVote' => '',
|
||||
'object_updateMessagePollVote_param_poll_id_type_long' => '',
|
||||
'object_updateMessagePollVote_param_user_id_type_int' => '',
|
||||
'object_updateMessagePollVote_param_options_type_Vector t' => '',
|
||||
'object_webPage_param_attributes_type_Vector t' => '',
|
||||
'object_keyboardButtonRequestPoll' => '',
|
||||
'object_keyboardButtonRequestPoll_param_quiz_type_Bool' => '',
|
||||
'object_keyboardButtonRequestPoll_param_text_type_string' => '',
|
||||
'object_poll_param_public_voters_type_true' => '',
|
||||
'object_poll_param_multiple_choice_type_true' => '',
|
||||
'object_poll_param_quiz_type_true' => '',
|
||||
'object_pollAnswerVoters_param_correct_type_true' => '',
|
||||
'object_pollResults_param_recent_voters_type_Vector t' => '',
|
||||
'object_inputWallPaperNoFile' => '',
|
||||
'object_wallPaperSettings_param_second_background_color_type_int' => '',
|
||||
'object_wallPaperSettings_param_rotation_type_int' => '',
|
||||
'object_autoDownloadSettings_param_video_upload_maxbitrate_type_int' => '',
|
||||
'object_theme_param_settings_type_ThemeSettings' => '',
|
||||
'object_auth.loginToken' => '',
|
||||
'object_auth.loginToken_param_expires_type_int' => '',
|
||||
'object_auth.loginToken_param_token_type_bytes' => '',
|
||||
'object_auth.loginTokenMigrateTo' => '',
|
||||
'object_auth.loginTokenMigrateTo_param_dc_id_type_int' => '',
|
||||
'object_auth.loginTokenMigrateTo_param_token_type_bytes' => '',
|
||||
'object_auth.loginTokenSuccess' => '',
|
||||
'object_auth.loginTokenSuccess_param_authorization_type_auth.Authorization' => '',
|
||||
'object_account.contentSettings' => '',
|
||||
'object_account.contentSettings_param_sensitive_enabled_type_true' => '',
|
||||
'object_account.contentSettings_param_sensitive_can_change_type_true' => '',
|
||||
'object_messages.inactiveChats' => '',
|
||||
'object_messages.inactiveChats_param_dates_type_Vector t' => '',
|
||||
'object_messages.inactiveChats_param_chats_type_Vector t' => '',
|
||||
'object_messages.inactiveChats_param_users_type_Vector t' => '',
|
||||
'object_baseThemeClassic' => '',
|
||||
'object_baseThemeDay' => '',
|
||||
'object_baseThemeNight' => '',
|
||||
'object_baseThemeTinted' => '',
|
||||
'object_baseThemeArctic' => '',
|
||||
'object_inputThemeSettings' => '',
|
||||
'object_inputThemeSettings_param_base_theme_type_BaseTheme' => '',
|
||||
'object_inputThemeSettings_param_accent_color_type_int' => '',
|
||||
'object_inputThemeSettings_param_message_top_color_type_int' => '',
|
||||
'object_inputThemeSettings_param_message_bottom_color_type_int' => '',
|
||||
'object_inputThemeSettings_param_wallpaper_type_InputWallPaper' => '',
|
||||
'object_inputThemeSettings_param_wallpaper_settings_type_WallPaperSettings' => '',
|
||||
'object_themeSettings' => '',
|
||||
'object_themeSettings_param_base_theme_type_BaseTheme' => '',
|
||||
'object_themeSettings_param_accent_color_type_int' => '',
|
||||
'object_themeSettings_param_message_top_color_type_int' => '',
|
||||
'object_themeSettings_param_message_bottom_color_type_int' => '',
|
||||
'object_themeSettings_param_wallpaper_type_WallPaper' => '',
|
||||
'object_webPageAttributeTheme' => '',
|
||||
'object_webPageAttributeTheme_param_documents_type_Vector t' => '',
|
||||
'object_webPageAttributeTheme_param_settings_type_ThemeSettings' => '',
|
||||
'object_messageUserVote' => '',
|
||||
'object_messageUserVote_param_user_id_type_int' => '',
|
||||
'object_messageUserVote_param_option_type_bytes' => '',
|
||||
'object_messageUserVote_param_date_type_int' => '',
|
||||
'object_messageUserVoteInputOption' => '',
|
||||
'object_messageUserVoteInputOption_param_user_id_type_int' => '',
|
||||
'object_messageUserVoteInputOption_param_date_type_int' => '',
|
||||
'object_messageUserVoteMultiple' => '',
|
||||
'object_messageUserVoteMultiple_param_user_id_type_int' => '',
|
||||
'object_messageUserVoteMultiple_param_options_type_Vector t' => '',
|
||||
'object_messageUserVoteMultiple_param_date_type_int' => '',
|
||||
'object_messages.votesList' => '',
|
||||
'object_messages.votesList_param_count_type_int' => '',
|
||||
'object_messages.votesList_param_votes_type_Vector t' => '',
|
||||
'object_messages.votesList_param_users_type_Vector t' => '',
|
||||
'object_messages.votesList_param_next_offset_type_string' => '',
|
||||
];
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class CheckLoop extends ResumableSignalLoop
|
||||
}
|
||||
}
|
||||
if ($connection->hasPendingCalls()) {
|
||||
$last_msgid = $connection->getMaxId(true);
|
||||
$last_msgid = $connection->msgIdHandler->getMaxId(true);
|
||||
$last_chunk = $connection->getLastChunk();
|
||||
if ($shared->hasTempAuthKey()) {
|
||||
$full_message_ids = $connection->getPendingCalls();
|
||||
@ -157,7 +157,7 @@ class CheckLoop extends ResumableSignalLoop
|
||||
if (yield $this->waitSignal($this->pause($timeout))) {
|
||||
return;
|
||||
}
|
||||
if ($connection->getMaxId(true) === $last_msgid && $connection->getLastChunk() === $last_chunk) {
|
||||
if ($connection->msgIdHandler->getMaxId(true) === $last_msgid && $connection->getLastChunk() === $last_chunk) {
|
||||
$API->logger->logger("We did not receive a response for {$timeout} seconds: reconnecting and exiting check loop on DC {$datacenter}");
|
||||
//$this->exitedLoop();
|
||||
Tools::callForkDefer($connection->reconnect());
|
||||
|
@ -155,9 +155,9 @@ class ReadLoop extends SignalLoop
|
||||
$auth_key_id = yield $buffer->bufferRead(8);
|
||||
if ($auth_key_id === "\0\0\0\0\0\0\0\0") {
|
||||
$message_id = yield $buffer->bufferRead(8);
|
||||
if (!\in_array($message_id, [1, 0])) {
|
||||
$connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
||||
}
|
||||
//if (!\in_array($message_id, [\1, \0])) {
|
||||
$connection->msgIdHandler->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
||||
//}
|
||||
$message_length = \unpack('V', yield $buffer->bufferRead(4))[1];
|
||||
$message_data = yield $buffer->bufferRead($message_length);
|
||||
$left = $payload_length - $message_length - 4 - 8 - 8;
|
||||
@ -191,7 +191,7 @@ class ReadLoop extends SignalLoop
|
||||
throw new NothingInTheSocketException();
|
||||
}
|
||||
$message_id = \substr($decrypted_data, 16, 8);
|
||||
$connection->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
||||
$connection->msgIdHandler->checkMessageId($message_id, ['outgoing' => false, 'container' => false]);
|
||||
$seq_no = \unpack('V', \substr($decrypted_data, 24, 4))[1];
|
||||
$message_data_length = \unpack('V', \substr($decrypted_data, 28, 4))[1];
|
||||
if ($message_data_length > \strlen($decrypted_data)) {
|
||||
|
@ -122,7 +122,7 @@ class WriteLoop extends ResumableSignalLoop
|
||||
}
|
||||
$skipped_all = false;
|
||||
$API->logger->logger("Sending {$message['_']} as unencrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId();
|
||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->msgIdHandler->generateMessageId();
|
||||
$length = \strlen($message['serialized_body']);
|
||||
$pad_length = -$length & 15;
|
||||
$pad_length += 16 * \danog\MadelineProto\Tools::randomInt($modulus = 16);
|
||||
@ -209,7 +209,7 @@ class WriteLoop extends ResumableSignalLoop
|
||||
$API->logger->logger('Length overflow, postponing part of payload', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
break;
|
||||
}
|
||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->generateMessageId();
|
||||
$message_id = isset($message['msg_id']) ? $message['msg_id'] : $connection->msgIdHandler->generateMessageId();
|
||||
$API->logger->logger("Sending {$message['_']} as encrypted message to DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $message['serialized_body'], 'seqno' => $connection->generateOutSeqNo($message['contentRelated'])];
|
||||
if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') {
|
||||
@ -262,7 +262,7 @@ class WriteLoop extends ResumableSignalLoop
|
||||
$MTmessage = null;
|
||||
if ($count > 1) {
|
||||
$API->logger->logger("Wrapping in msg_container ({$count} messages of total size {$total_length}) as encrypted message for DC {$datacenter}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$message_id = $connection->generateMessageId();
|
||||
$message_id = $connection->msgIdHandler->generateMessageId();
|
||||
$connection->pending_outgoing[$connection->pending_outgoing_key] = ['_' => 'msg_container', 'container' => \array_values($keys), 'contentRelated' => false, 'method' => false, 'unencrypted' => false];
|
||||
//var_dumP("container ".bin2hex($message_id));
|
||||
$keys[$connection->pending_outgoing_key++] = $message_id;
|
||||
|
@ -134,6 +134,7 @@ trait CallHandler
|
||||
if (isset($args['multiple'])) {
|
||||
unset($args['multiple']);
|
||||
}
|
||||
$promises = [];
|
||||
foreach ($args as $single_args) {
|
||||
$promises[] = Tools::call($this->methodCallAsyncWrite($method, $single_args, $new_aargs));
|
||||
}
|
||||
|
@ -17,84 +17,11 @@
|
||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoSession;
|
||||
use danog\MadelineProto\MTProtoSession\MsgIdHandler\MsgIdHandler32;
|
||||
use danog\MadelineProto\MTProtoSession\MsgIdHandler\MsgIdHandler64;
|
||||
|
||||
/**
|
||||
* Manages message ids.
|
||||
*/
|
||||
trait MsgIdHandler
|
||||
{
|
||||
public $max_incoming_id;
|
||||
public $max_outgoing_id;
|
||||
public function checkMessageId($new_message_id, $aargs)
|
||||
{
|
||||
if (!\is_object($new_message_id)) {
|
||||
$new_message_id = new \tgseclib\Math\BigInteger(\strrev($new_message_id), 256);
|
||||
}
|
||||
$min_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta - 300))->bitwise_leftShift(32);
|
||||
if ($min_message_id->compare($new_message_id) > 0) {
|
||||
$this->API->logger->logger('Given message id (' . $new_message_id . ') is too old compared to the min value (' . $min_message_id . ').', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
$max_message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta + 30))->bitwise_leftShift(32);
|
||||
if ($max_message_id->compare($new_message_id) < 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is too new compared to the max value (' . $max_message_id . '). Consider syncing your date.');
|
||||
}
|
||||
if ($aargs['outgoing']) {
|
||||
if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$zero)) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is not divisible by 4. Consider syncing your date.');
|
||||
}
|
||||
if (!\danog\MadelineProto\Magic::$has_thread && $new_message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', 1);
|
||||
}
|
||||
if (\count($this->outgoing_messages) > $this->API->settings['msg_array_limit']['outgoing']) {
|
||||
\reset($this->outgoing_messages);
|
||||
$key = \key($this->outgoing_messages);
|
||||
if (!isset($this->outgoing_messages[$key]['promise'])) {
|
||||
unset($this->outgoing_messages[$key]);
|
||||
}
|
||||
}
|
||||
$this->max_outgoing_id = $new_message_id;
|
||||
$this->outgoing_messages[\strrev($new_message_id->toBytes())] = [];
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
\class_alias(MsgIdHandler64::class, \danog\MadelineProto\MTProtoSession\MsgIdHandler::class);
|
||||
} else {
|
||||
if (!$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$one) && !$new_message_id->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$three)) {
|
||||
throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
|
||||
}
|
||||
$key = $this->getMaxId($incoming = true);
|
||||
if ($aargs['container']) {
|
||||
if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) >= 0) {
|
||||
$this->API->logger->logger('WARNING: Given message id (' . $new_message_id . ') is bigger than or equal to the current limit (' . $key . '). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
} else {
|
||||
if ($new_message_id->compare($key = $this->getMaxId($incoming = true)) <= 0) {
|
||||
$this->API->logger->logger('WARNING: Given message id (' . $new_message_id . ') is lower than or equal to the current limit (' . $key . '). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
}
|
||||
if (\count($this->incoming_messages) > $this->API->settings['msg_array_limit']['incoming']) {
|
||||
\reset($this->incoming_messages);
|
||||
$key = \key($this->incoming_messages);
|
||||
if (!isset($this->incoming_messages[$key]['promise'])) {
|
||||
unset($this->incoming_messages[$key]);
|
||||
}
|
||||
}
|
||||
$this->max_incoming_id = $new_message_id;
|
||||
$this->incoming_messages[\strrev($new_message_id->toBytes())] = [];
|
||||
}
|
||||
}
|
||||
public function generateMessageId()
|
||||
{
|
||||
$message_id = (new \tgseclib\Math\BigInteger(\time() + $this->time_delta))->bitwise_leftShift(32);
|
||||
if ($message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) {
|
||||
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
|
||||
}
|
||||
$this->checkMessageId($message_id, ['outgoing' => true, 'container' => false]);
|
||||
return \strrev($message_id->toBytes());
|
||||
}
|
||||
public function getMaxId($incoming)
|
||||
{
|
||||
$incoming = $incoming ? 'incoming' : 'outgoing';
|
||||
if (isset($this->{'max_' . $incoming . '_id'}) && \is_object($this->{'max_' . $incoming . '_id'})) {
|
||||
return $this->{'max_' . $incoming . '_id'};
|
||||
}
|
||||
return \danog\MadelineProto\Magic::$zero;
|
||||
}
|
||||
\class_alias(MsgIdHandler32::class, \danog\MadelineProto\MTProtoSession\MsgIdHandler::class);
|
||||
}
|
||||
|
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MsgIdHandler module.
|
||||
*
|
||||
* This file is part of MadelineProto.
|
||||
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoSession\MsgIdHandler;
|
||||
|
||||
use danog\MadelineProto\MTProtoSession\MsgIdHandlerAbstract;
|
||||
|
||||
/**
|
||||
* Manages message ids.
|
||||
*/
|
||||
class MsgIdHandler32 extends MsgIdHandlerAbstract
|
||||
{
|
||||
/**
|
||||
* Maximum incoming ID.
|
||||
*
|
||||
* @var BigInteger
|
||||
*/
|
||||
private $maxIncomingId;
|
||||
/**
|
||||
* Maximum outgoing ID.
|
||||
*
|
||||
* @var BigInteger
|
||||
*/
|
||||
private $maxOutgoingId;
|
||||
/**
|
||||
* Check validity of given message ID.
|
||||
*
|
||||
* @param string $newMessageId New message ID
|
||||
* @param array $aargs Params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkMessageId($newMessageId, array $aargs): void
|
||||
{
|
||||
$newMessageId = \is_object($newMessageId) ? $newMessageId : new \tgseclib\Math\BigInteger(\strrev($newMessageId), 256);
|
||||
|
||||
$minMessageId = (new \tgseclib\Math\BigInteger(\time() + $this->session->time_delta - 300))->bitwise_leftShift(32);
|
||||
if ($minMessageId->compare($newMessageId) > 0) {
|
||||
$this->session->API->logger->logger('Given message id ('.$newMessageId.') is too old compared to the min value ('.$minMessageId.').', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
$maxMessageId = (new \tgseclib\Math\BigInteger(\time() + $this->session->time_delta + 30))->bitwise_leftShift(32);
|
||||
if ($maxMessageId->compare($newMessageId) < 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is too new compared to the max value ('.$maxMessageId.'). Consider syncing your date.');
|
||||
}
|
||||
if ($aargs['outgoing']) {
|
||||
if (!$newMessageId->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$zero)) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is not divisible by 4. Consider syncing your date.');
|
||||
}
|
||||
if ($newMessageId->compare($key = $this->getMaxId($incoming = false)) <= 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', 1);
|
||||
}
|
||||
if (\count($this->session->outgoing_messages) > $this->session->API->settings['msg_array_limit']['outgoing']) {
|
||||
\reset($this->session->outgoing_messages);
|
||||
$key = \key($this->session->outgoing_messages);
|
||||
if (!isset($this->session->outgoing_messages[$key]['promise'])) {
|
||||
unset($this->session->outgoing_messages[$key]);
|
||||
}
|
||||
}
|
||||
$this->maxOutgoingId = $newMessageId;
|
||||
$this->session->outgoing_messages[\strrev($newMessageId->toBytes())] = [];
|
||||
} else {
|
||||
if (!$newMessageId->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$one) && !$newMessageId->divide(\danog\MadelineProto\Magic::$four)[1]->equals(\danog\MadelineProto\Magic::$three)) {
|
||||
throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
|
||||
}
|
||||
$key = $this->getMaxId($incoming = true);
|
||||
if ($aargs['container']) {
|
||||
if ($newMessageId->compare($key = $this->getMaxId($incoming = true)) >= 0) {
|
||||
$this->session->API->logger->logger('WARNING: Given message id ('.$newMessageId.') is bigger than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
} else {
|
||||
if ($newMessageId->compare($key = $this->getMaxId($incoming = true)) <= 0) {
|
||||
$this->session->API->logger->logger('WARNING: Given message id ('.$newMessageId.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
}
|
||||
if (\count($this->session->incoming_messages) > $this->session->API->settings['msg_array_limit']['incoming']) {
|
||||
\reset($this->session->incoming_messages);
|
||||
$key = \key($this->session->incoming_messages);
|
||||
if (!isset($this->session->incoming_messages[$key]['promise'])) {
|
||||
unset($this->session->incoming_messages[$key]);
|
||||
}
|
||||
}
|
||||
$this->maxIncomingId = $newMessageId;
|
||||
$this->session->incoming_messages[\strrev($newMessageId->toBytes())] = [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate message ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateMessageId(): string
|
||||
{
|
||||
$message_id = (new \tgseclib\Math\BigInteger(\time() + $this->session->time_delta))->bitwise_leftShift(32);
|
||||
if ($message_id->compare($key = $this->getMaxId($incoming = false)) <= 0) {
|
||||
$message_id = $key->add(\danog\MadelineProto\Magic::$four);
|
||||
}
|
||||
$this->checkMessageId($message_id, ['outgoing' => true, 'container' => false]);
|
||||
return \strrev($message_id->toBytes());
|
||||
}
|
||||
/**
|
||||
* Get maximum message ID.
|
||||
*
|
||||
* @param boolean $incoming Incoming or outgoing message ID
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMaxId(bool $incoming)
|
||||
{
|
||||
$incoming = $incoming ? 'Incoming' : 'Outgoing';
|
||||
if (isset($this->{'max'.$incoming.'Id'}) && \is_object($this->{'max'.$incoming.'Id'})) {
|
||||
return $this->{'max'.$incoming.'Id'};
|
||||
}
|
||||
return \danog\MadelineProto\Magic::$zero;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset message IDs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset(): void
|
||||
{
|
||||
$this->maxIncomingId = null;
|
||||
$this->maxOutgoingId = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MsgIdHandler module.
|
||||
*
|
||||
* This file is part of MadelineProto.
|
||||
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoSession\MsgIdHandler;
|
||||
|
||||
use danog\MadelineProto\MTProtoSession\MsgIdHandlerAbstract;
|
||||
use danog\MadelineProto\Tools;
|
||||
|
||||
/**
|
||||
* Manages message ids.
|
||||
*/
|
||||
class MsgIdHandler64 extends MsgIdHandlerAbstract
|
||||
{
|
||||
/**
|
||||
* Maximum incoming ID.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $maxIncomingId = 0;
|
||||
/**
|
||||
* Maximum outgoing ID.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $maxOutgoingId = 0;
|
||||
/**
|
||||
* Check validity of given message ID
|
||||
*
|
||||
* @param string $newMessageId New message ID
|
||||
* @param array $aargs Params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkMessageId($newMessageId, array $aargs): void
|
||||
{
|
||||
$newMessageId = is_integer($newMessageId) ? $newMessageId : Tools::unpackSignedLong($newMessageId);
|
||||
$minMessageId = (\time() + $this->session->time_delta - 300) << 32;
|
||||
if ($newMessageId < $minMessageId) {
|
||||
$this->session->API->logger->logger('Given message id ('.$newMessageId.') is too old compared to the min value ('.$minMessageId.').', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
$maxMessageId = (\time() + $this->session->time_delta + 30) << 32;
|
||||
if ($newMessageId > $maxMessageId) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is too new compared to the max value ('.$maxMessageId.'). Consider syncing your date.');
|
||||
}
|
||||
if ($aargs['outgoing']) {
|
||||
if ($newMessageId % 4) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is not divisible by 4. Consider syncing your date.');
|
||||
}
|
||||
if ($newMessageId <= $this->maxOutgoingId) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$newMessageId.') is lower than or equal to the current limit ('.$this->maxOutgoingId.'). Consider syncing your date.');
|
||||
}
|
||||
if (\count($this->session->outgoing_messages) > $this->session->API->settings['msg_array_limit']['outgoing']) {
|
||||
\reset($this->session->outgoing_messages);
|
||||
$key = \key($this->session->outgoing_messages);
|
||||
if (!isset($this->session->outgoing_messages[$key]['promise'])) {
|
||||
unset($this->session->outgoing_messages[$key]);
|
||||
}
|
||||
}
|
||||
$this->maxOutgoingId = $newMessageId;
|
||||
$this->session->outgoing_messages[Tools::packSignedLong($newMessageId)] = [];
|
||||
} else {
|
||||
if (!($newMessageId % 2)) {
|
||||
throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
|
||||
}
|
||||
$key = $this->maxIncomingId;
|
||||
if ($aargs['container']) {
|
||||
if ($newMessageId >= $key) {
|
||||
$this->session->API->logger->logger('WARNING: Given message id ('.$newMessageId.') is bigger than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
} else {
|
||||
if ($newMessageId <= $key) {
|
||||
$this->session->API->logger->logger('WARNING: Given message id ('.$newMessageId.') is lower than or equal to the current limit ('.$key.'). Consider syncing your date.', \danog\MadelineProto\Logger::WARNING);
|
||||
}
|
||||
}
|
||||
if (\count($this->session->incoming_messages) > $this->session->API->settings['msg_array_limit']['incoming']) {
|
||||
\reset($this->session->incoming_messages);
|
||||
$key = \key($this->session->incoming_messages);
|
||||
if (!isset($this->session->incoming_messages[$key]['promise'])) {
|
||||
unset($this->session->incoming_messages[$key]);
|
||||
}
|
||||
}
|
||||
$this->maxIncomingId = $newMessageId;
|
||||
$this->session->incoming_messages[Tools::packSignedLong($newMessageId)] = [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generate message ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateMessageId(): string
|
||||
{
|
||||
$messageId = (\time() + $this->session->time_delta) << 32;
|
||||
if ($messageId <= $this->maxOutgoingId) {
|
||||
$messageId = $this->maxOutgoingId + 4;
|
||||
}
|
||||
$this->checkMessageId($messageId, ['outgoing' => true, 'container' => false]);
|
||||
return Tools::packSignedLong($messageId);
|
||||
}
|
||||
/**
|
||||
* Get maximum message ID.
|
||||
*
|
||||
* @param boolean $incoming Incoming or outgoing message ID
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMaxId(bool $incoming)
|
||||
{
|
||||
return $this->{$incoming ? 'maxIncomingId' : 'maxOutgoingId'};
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MsgIdHandler module.
|
||||
*
|
||||
* This file is part of MadelineProto.
|
||||
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\MTProtoSession;
|
||||
|
||||
/**
|
||||
* Manages message ids.
|
||||
*/
|
||||
abstract class MsgIdHandlerAbstract
|
||||
{
|
||||
/**
|
||||
* Session instance.
|
||||
*
|
||||
* @var Session
|
||||
*/
|
||||
protected $session;
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Session $session Session
|
||||
*/
|
||||
public function __construct(Session $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check validity of given message ID.
|
||||
*
|
||||
* @param string $newMessageId New message ID
|
||||
* @param array $aargs Params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function checkMessageId(string $newMessageId, array $aargs): void;
|
||||
/**
|
||||
* Generate outgoing message ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function generateMessageId(): string;
|
||||
/**
|
||||
* Get maximum message ID.
|
||||
*
|
||||
* @param boolean $incoming Incoming or outgoing message ID
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function getMaxId(bool $incoming);
|
||||
}
|
@ -119,7 +119,7 @@ trait ResponseHandler
|
||||
unset($this->new_incoming[$current_msg_id]);
|
||||
$only_updates = false;
|
||||
foreach ($this->incoming_messages[$current_msg_id]['content']['messages'] as $message) {
|
||||
$this->checkMessageId($message['msg_id'], ['outgoing' => false, 'container' => true]);
|
||||
$this->msgIdHandler->checkMessageId($message['msg_id'], ['outgoing' => false, 'container' => true]);
|
||||
$this->incoming_messages[$message['msg_id']] = ['seq_no' => $message['seqno'], 'content' => $message['body'], 'from_container' => true];
|
||||
$this->new_incoming[$message['msg_id']] = $message['msg_id'];
|
||||
}
|
||||
@ -139,7 +139,7 @@ trait ResponseHandler
|
||||
// Acknowledge that I received the server's response
|
||||
} else {
|
||||
$message = $this->incoming_messages[$current_msg_id]['content'];
|
||||
$this->checkMessageId($message['orig_message']['msg_id'], ['outgoing' => false, 'container' => true]);
|
||||
$this->msgIdHandler->checkMessageId($message['orig_message']['msg_id'], ['outgoing' => false, 'container' => true]);
|
||||
$this->incoming_messages[$message['orig_message']['msg_id']] = ['content' => $this->incoming_messages[$current_msg_id]['content']['orig_message']];
|
||||
$this->new_incoming[$message['orig_message']['msg_id']] = $message['orig_message']['msg_id'];
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ namespace danog\MadelineProto\MTProtoSession;
|
||||
abstract class Session
|
||||
{
|
||||
use AckHandler;
|
||||
use MsgIdHandler;
|
||||
use ResponseHandler;
|
||||
use SeqNoHandler;
|
||||
use CallHandler;
|
||||
@ -38,30 +37,33 @@ abstract class Session
|
||||
public $time_delta = 0;
|
||||
public $call_queue = [];
|
||||
public $ack_queue = [];
|
||||
/**
|
||||
* Message ID handler.
|
||||
*
|
||||
* @var MsgIdHandlerAbstract
|
||||
*/
|
||||
public $msgIdHandler;
|
||||
/**
|
||||
* Reset MTProto session.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetSession()
|
||||
public function resetSession(): void
|
||||
{
|
||||
$this->session_id = \danog\MadelineProto\Tools::random(8);
|
||||
$this->session_in_seq_no = 0;
|
||||
$this->session_out_seq_no = 0;
|
||||
$this->max_incoming_id = null;
|
||||
$this->max_outgoing_id = null;
|
||||
$this->msgIdHandler = new MsgIdHandler($this);
|
||||
}
|
||||
/**
|
||||
* Create MTProto session if needed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createSession()
|
||||
public function createSession(): void
|
||||
{
|
||||
if ($this->session_id === null) {
|
||||
$this->session_id = \danog\MadelineProto\Tools::random(8);
|
||||
$this->session_in_seq_no = 0;
|
||||
$this->session_out_seq_no = 0;
|
||||
$this->resetSession();
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -540,7 +540,7 @@ trait AuthKeyHandler
|
||||
$perm_auth_key_id = $datacenterConnection->getPermAuthKey()->getID();
|
||||
$temp_session_id = $connection->session_id;
|
||||
$message_data = (yield from $this->TL->serializeObject(['type' => ''], ['_' => 'bind_auth_key_inner', 'nonce' => $nonce, 'temp_auth_key_id' => $temp_auth_key_id, 'perm_auth_key_id' => $perm_auth_key_id, 'temp_session_id' => $temp_session_id, 'expires_at' => $expires_at], 'bindTempAuthKey_inner'));
|
||||
$message_id = $connection->generateMessageId();
|
||||
$message_id = $connection->msgIdHandler->generateMessageId();
|
||||
$seq_no = 0;
|
||||
$encrypted_data = \danog\MadelineProto\Tools::random(16) . $message_id . \pack('VV', $seq_no, \strlen($message_data)) . $message_data;
|
||||
$message_key = \substr(\sha1($encrypted_data, true), -16);
|
||||
|
@ -272,6 +272,7 @@ class TL
|
||||
$TL_dict['methods'][$key]['id'] = \danog\MadelineProto\Tools::packSignedInt($TL_dict['methods'][$key]['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($TL_dict) || empty($TL_dict['constructors']) || !isset($TL_dict['methods'])) {
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['src_file_invalid'].$file);
|
||||
}
|
||||
|
@ -131,11 +131,11 @@ class ADNLConnection
|
||||
$buffer = yield $this->stream->getReadBuffer($length);
|
||||
if ($length) {
|
||||
$data = yield $buffer->bufferRead($length);
|
||||
$data = yield $this->TL->deserialize($data);
|
||||
$data = $this->TL->deserialize($data);
|
||||
if ($data['_'] !== 'adnl.message.answer') {
|
||||
throw new Exception('Wrong answer type: ' . $data['_']);
|
||||
}
|
||||
$this->requests[$data['query_id']]->resolve(yield $this->TL->deserialize((string) $data['answer']));
|
||||
$this->requests[$data['query_id']]->resolve($this->TL->deserialize((string) $data['answer']));
|
||||
}
|
||||
}
|
||||
})());
|
||||
|
@ -23,6 +23,12 @@ use danog\MadelineProto\AbstractAPIFactory;
|
||||
|
||||
class APIFactory extends AbstractAPIFactory
|
||||
{
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var http
|
||||
*/
|
||||
public $http;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
|
@ -104,6 +104,22 @@ interface liteServer
|
||||
*/
|
||||
public function getAccountState($params);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Parameters:
|
||||
* * `#` **mode** -
|
||||
* * `tonNode.blockIdExt` **id** -
|
||||
* * `liteServer.accountId` **account** -
|
||||
* * `long` **method_id** -
|
||||
* * `bytes` **params** -.
|
||||
*
|
||||
* @param array $params Parameters
|
||||
*
|
||||
* @return liteServer.RunMethodResult
|
||||
*/
|
||||
public function runSmcMethod($params);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -861,6 +877,39 @@ interface engine
|
||||
public function validator($params);
|
||||
}
|
||||
|
||||
interface http
|
||||
{
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Parameters:
|
||||
* * `int256` **id** -
|
||||
* * `string` **method** -
|
||||
* * `string` **url** -
|
||||
* * `string` **http_version** -
|
||||
* * `[http.header]` **headers** -.
|
||||
*
|
||||
* @param array $params Parameters
|
||||
*
|
||||
* @return http.Response
|
||||
*/
|
||||
public function request($params);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Parameters:
|
||||
* * `int256` **id** -
|
||||
* * `int` **seqno** -
|
||||
* * `int` **max_chunk_size** -.
|
||||
*
|
||||
* @param array $params Parameters
|
||||
*
|
||||
* @return http.PayloadPart
|
||||
*/
|
||||
public function getNextPayloadPart($params);
|
||||
}
|
||||
|
||||
class InternalDoc extends APIFactory
|
||||
{
|
||||
/**
|
||||
@ -917,11 +966,11 @@ class InternalDoc extends APIFactory
|
||||
*
|
||||
* @param array $parameters Parameters
|
||||
*
|
||||
* @return array
|
||||
* @return \Generator
|
||||
*/
|
||||
public function botAPItoMTProto(array $parameters): array
|
||||
public function botAPItoMTProto(array $parameters, array $extra = [])
|
||||
{
|
||||
return $this->API->botAPItoMTProto($parameters);
|
||||
return $this->__call(__FUNCTION__, [$parameters, $extra]);
|
||||
}
|
||||
/**
|
||||
* Get TL method namespaces.
|
||||
|
@ -84,7 +84,7 @@ class Lite
|
||||
$config['_'] = 'liteclient.config.global';
|
||||
$config = Tools::convertJsonTL($config);
|
||||
$config['validator']['init_block'] = $config['validator']['init_block'] ?? $config['validator']['zero_state'];
|
||||
$this->config = yield $this->TL->deserialize(yield from $this->TL->serializeObject(['type' => ''], $config, 'cleanup'));
|
||||
$this->config = $this->TL->deserialize(yield from $this->TL->serializeObject(['type' => ''], $config, 'cleanup'));
|
||||
foreach ($this->config['liteservers'] as $lite) {
|
||||
$this->connections[] = $connection = new ADNLConnection($this->TL);
|
||||
yield from $connection->connect($lite);
|
||||
@ -136,11 +136,12 @@ class Lite
|
||||
*
|
||||
* @param array $parameters Parameters
|
||||
*
|
||||
* @return array
|
||||
* @return \Generator
|
||||
*/
|
||||
public function botAPItoMTProto(array $parameters): array
|
||||
public function botAPItoMTProto(array $parameters): \Generator
|
||||
{
|
||||
return $parameters;
|
||||
yield;
|
||||
}
|
||||
/**
|
||||
* Get TL method namespaces.
|
||||
|
@ -35,6 +35,7 @@ liteServer.blockState id:tonNode.blockIdExt root_hash:int256 file_hash:int256 da
|
||||
liteServer.blockHeader id:tonNode.blockIdExt mode:# header_proof:bytes = liteServer.BlockHeader;
|
||||
liteServer.sendMsgStatus status:int = liteServer.SendMsgStatus;
|
||||
liteServer.accountState id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes proof:bytes state:bytes = liteServer.AccountState;
|
||||
liteServer.runMethodResult mode:# id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:mode.0?bytes proof:mode.0?bytes state_proof:mode.1?bytes init_c7:mode.3?bytes lib_extras:mode.4?bytes exit_code:int result:mode.2?bytes = liteServer.RunMethodResult;
|
||||
liteServer.shardInfo id:tonNode.blockIdExt shardblk:tonNode.blockIdExt shard_proof:bytes shard_descr:bytes = liteServer.ShardInfo;
|
||||
liteServer.allShardsInfo id:tonNode.blockIdExt proof:bytes data:bytes = liteServer.AllShardsInfo;
|
||||
liteServer.transactionInfo id:tonNode.blockIdExt proof:bytes transaction:bytes = liteServer.TransactionInfo;
|
||||
@ -63,6 +64,7 @@ liteServer.getState id:tonNode.blockIdExt = liteServer.BlockState;
|
||||
liteServer.getBlockHeader id:tonNode.blockIdExt mode:# = liteServer.BlockHeader;
|
||||
liteServer.sendMessage body:bytes = liteServer.SendMsgStatus;
|
||||
liteServer.getAccountState id:tonNode.blockIdExt account:liteServer.accountId = liteServer.AccountState;
|
||||
liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult;
|
||||
liteServer.getShardInfo id:tonNode.blockIdExt workchain:int shard:long exact:Bool = liteServer.ShardInfo;
|
||||
liteServer.getAllShardsInfo id:tonNode.blockIdExt = liteServer.AllShardsInfo;
|
||||
liteServer.getOneTransaction id:tonNode.blockIdExt account:liteServer.accountId lt:long = liteServer.TransactionInfo;
|
||||
|
@ -614,3 +614,25 @@ engine.validator.createElectionBid election_date:int election_addr:string wallet
|
||||
engine.validator.checkDhtServers id:int256 = engine.validator.DhtServersStatus;
|
||||
|
||||
engine.validator.controlQuery data:bytes = Object;
|
||||
|
||||
|
||||
---types---
|
||||
|
||||
http.header name:string value:string = http.Header;
|
||||
http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart;
|
||||
http.response http_version:string status_code:int reason:string headers:(vector http.header) = http.Response;
|
||||
|
||||
---functions---
|
||||
|
||||
http.request id:int256 method:string url:string http_version:string headers:(vector http.header) = http.Response;
|
||||
http.getNextPayloadPart id:int256 seqno:int max_chunk_size:int = http.PayloadPart;
|
||||
|
||||
---types---
|
||||
|
||||
|
||||
http.server.dnsEntry domain:string addr:adnl.id.short = http.server.DnsEntry;
|
||||
http.server.host domains:(vector string) ip:int port:int adnl_id:adnl.id.short = http.server.Host;
|
||||
|
||||
http.server.config dhs:(vector http.server.dnsEntry) local_hosts:(vector http.server.host) = http.server.Config;
|
||||
|
||||
---functions---
|
||||
|
@ -8,6 +8,9 @@ bytes = Bytes;
|
||||
secureString = SecureString;
|
||||
secureBytes = SecureBytes;
|
||||
|
||||
object ? = Object;
|
||||
function ? = Function;
|
||||
|
||||
boolFalse = Bool;
|
||||
boolTrue = Bool;
|
||||
|
||||
@ -22,7 +25,7 @@ keyStoreTypeInMemory = KeyStoreType;
|
||||
config config:string blockchain_name:string use_callbacks_for_network:Bool ignore_cache:Bool = Config;
|
||||
|
||||
options config:config keystore_type:KeyStoreType = Options;
|
||||
options.configInfo default_wallet_id:int53 = options.ConfigInfo;
|
||||
options.configInfo default_wallet_id:int64 = options.ConfigInfo;
|
||||
options.info config_info:options.configInfo = options.Info;
|
||||
|
||||
key public_key:string secret:secureBytes = Key;
|
||||
@ -35,52 +38,87 @@ exportedEncryptedKey data:secureBytes = ExportedEncryptedKey;
|
||||
bip39Hints words:vector<string> = Bip39Hints;
|
||||
|
||||
accountAddress account_address:string = AccountAddress;
|
||||
accountRevisionList revisions:vector<int32> = AccountRevisionList;
|
||||
|
||||
unpackedAccountAddress workchain_id:int32 bounceable:Bool testnet:Bool addr:bytes = UnpackedAccountAddress;
|
||||
|
||||
internal.transactionId lt:int64 hash:bytes = internal.TransactionId;
|
||||
|
||||
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState;
|
||||
raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId frozen_hash:bytes sync_utime:int53 = raw.AccountState;
|
||||
ton.blockId workchain:int32 shard:int64 seqno:int32 = internal.BlockId;
|
||||
ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt;
|
||||
|
||||
raw.fullAccountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId block_id:ton.blockIdExt frozen_hash:bytes sync_utime:int53 = raw.FullAccountState;
|
||||
raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes = raw.Message;
|
||||
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
|
||||
raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
|
||||
|
||||
testWallet.initialAccountState public_key:string = testWallet.InitialAccountState;
|
||||
testWallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = testWallet.AccountState;
|
||||
raw.initialAccountState code:bytes data:bytes = InitialAccountState;
|
||||
testGiver.initialAccountState = InitialAccountState;
|
||||
testWallet.initialAccountState public_key:string = InitialAccountState;
|
||||
wallet.initialAccountState public_key:string = InitialAccountState;
|
||||
wallet.v3.initialAccountState public_key:string wallet_id:int64 = InitialAccountState;
|
||||
wallet.highload.v1.initialAccountState public_key:string wallet_id:int64 = InitialAccountState;
|
||||
wallet.highload.v2.initialAccountState public_key:string wallet_id:int64 = InitialAccountState;
|
||||
dns.initialAccountState public_key:string wallet_id:int64 = InitialAccountState;
|
||||
|
||||
wallet.initialAccountState public_key:string = wallet.InitialAccountState;
|
||||
wallet.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = wallet.AccountState;
|
||||
raw.accountState code:bytes data:bytes frozen_hash:bytes = AccountState;
|
||||
testWallet.accountState seqno:int32 = AccountState;
|
||||
wallet.accountState seqno:int32 = AccountState;
|
||||
wallet.v3.accountState wallet_id:int64 seqno:int32 = AccountState;
|
||||
wallet.highload.v1.accountState wallet_id:int64 seqno:int32 = AccountState;
|
||||
wallet.highload.v2.accountState wallet_id:int64 = AccountState;
|
||||
testGiver.accountState seqno:int32 = AccountState;
|
||||
dns.accountState wallet_id:int64 = AccountState;
|
||||
uninited.accountState frozen_hash:bytes = AccountState;
|
||||
|
||||
wallet.v3.initialAccountState public_key:string wallet_id:int53 = wallet.v3.InitialAccountState;
|
||||
wallet.v3.accountState balance:int64 wallet_id:int53 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53 = wallet.v3.AccountState;
|
||||
|
||||
testGiver.accountState balance:int64 seqno:int32 last_transaction_id:internal.transactionId sync_utime:int53= testGiver.AccountState;
|
||||
|
||||
uninited.accountState balance:int64 last_transaction_id:internal.transactionId frozen_hash:bytes sync_utime:int53 = uninited.AccountState;
|
||||
|
||||
//generic.initialAccountStateRaw initital_account_state:raw.initialAccountState = generic.InitialAccountState;
|
||||
//generic.initialAccountStateTestWallet initital_account_state:testWallet.initialAccountState = generic.InitialAccountState;
|
||||
//generic.initialAccountStateWallet initital_account_state:wallet.initialAccountState = generic.InitialAccountState;
|
||||
|
||||
generic.accountStateRaw account_state:raw.accountState = generic.AccountState;
|
||||
generic.accountStateTestWallet account_state:testWallet.accountState = generic.AccountState;
|
||||
generic.accountStateWallet account_state:wallet.accountState = generic.AccountState;
|
||||
generic.accountStateWalletV3 account_state:wallet.v3.accountState = generic.AccountState;
|
||||
generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState;
|
||||
generic.accountStateUninited account_state:uninited.accountState = generic.AccountState;
|
||||
|
||||
sendGramsResult sent_until:int53 body_hash:bytes = SendGramsResult;
|
||||
fullAccountState balance:int64 last_transaction_id:internal.transactionId block_id:ton.blockIdExt sync_utime:int53 account_state:AccountState = FullAccountState;
|
||||
|
||||
syncStateDone = SyncState;
|
||||
syncStateInProgress from_seqno:int32 to_seqno:int32 current_seqno:int32 = SyncState;
|
||||
|
||||
//
|
||||
// MSG
|
||||
//
|
||||
|
||||
msg.dataText text:string = msg.Data;
|
||||
msg.dataEncryptedText text:string = msg.Data;
|
||||
msg.message destination:accountAddress amount:int64 data:msg.Data = msg.Message;
|
||||
|
||||
//
|
||||
// DNS
|
||||
//
|
||||
|
||||
dns.entryDataUnknown bytes:bytes = dns.EntryData;
|
||||
dns.entryDataText text:string = dns.EntryData;
|
||||
dns.entryDataNextResolver resolver:AccountAddress = dns.EntryData;
|
||||
dns.entryDataSmcAddress smc_address:AccountAddress = dns.EntryData;
|
||||
//TODO: other entry types
|
||||
|
||||
dns.entry name:string category:int32 entry:dns.EntryData = dns.Entry;
|
||||
|
||||
dns.actionDeleteAll = dns.Action;
|
||||
// use category = 0 to delete all entries
|
||||
dns.actionDelete name:string category:int32 = dns.Action;
|
||||
dns.actionSet entry:dns.entry = dns.Action;
|
||||
|
||||
dns.resolved entries:vector<dns.entry> = dns.Resolved;
|
||||
|
||||
//
|
||||
// Actions
|
||||
//
|
||||
|
||||
actionNoop = Action;
|
||||
actionMsg messages:vector<msg.Message> allow_send_to_uninited:Bool = Action;
|
||||
actionDns actions:vector<dns.Action> = Action;
|
||||
//actionMultisig actions:vector<multisig.order> = Action;
|
||||
|
||||
fees in_fwd_fee:int53 storage_fee:int53 gas_fee:int53 fwd_fee:int53 = Fees;
|
||||
query.fees source_fees:fees destination_fees:fees = query.Fees;
|
||||
query.fees source_fees:fees destination_fees:vector<fees> = query.Fees;
|
||||
// query.emulationResult exit_code:int32 fees:fees = query.EmulationResult;
|
||||
query.info id:int53 valid_until:int53 body_hash:bytes = query.Info;
|
||||
|
||||
tvm.slice bytes:string = tvm.Slice;
|
||||
tvm.cell bytes:string = tvm.Cell;
|
||||
tvm.slice bytes:bytes = tvm.Slice;
|
||||
tvm.cell bytes:bytes = tvm.Cell;
|
||||
tvm.numberDecimal number:string = tvm.Number;
|
||||
tvm.tuple elements:vector<tvm.StackEntry> = tvm.Tuple;
|
||||
tvm.list elements:vector<tvm.StackEntry> = tvm.List;
|
||||
@ -152,51 +190,41 @@ packAccountAddress account_address:unpackedAccountAddress = AccountAddress;
|
||||
getBip39Hints prefix:string = Bip39Hints;
|
||||
|
||||
//raw.init initial_account_state:raw.initialAccountState = Ok;
|
||||
raw.getAccountAddress initital_account_state:raw.initialAccountState = AccountAddress;
|
||||
raw.getAccountState account_address:accountAddress = raw.AccountState;
|
||||
raw.getTransactions account_address:accountAddress from_transaction_id:internal.transactionId = raw.Transactions;
|
||||
raw.getAccountState account_address:accountAddress = raw.FullAccountState;
|
||||
raw.getTransactions private_key:InputKey account_address:accountAddress from_transaction_id:internal.transactionId = raw.Transactions;
|
||||
raw.sendMessage body:bytes = Ok;
|
||||
raw.createAndSendMessage destination:accountAddress initial_account_state:bytes data:bytes = Ok;
|
||||
raw.createQuery destination:accountAddress init_code:bytes init_data:bytes body:bytes = query.Info;
|
||||
|
||||
testWallet.init private_key:InputKey = Ok;
|
||||
testWallet.getAccountAddress initital_account_state:testWallet.initialAccountState = AccountAddress;
|
||||
testWallet.getAccountState account_address:accountAddress = testWallet.AccountState;
|
||||
testWallet.sendGrams private_key:InputKey destination:accountAddress seqno:int32 amount:int64 message:bytes = SendGramsResult;
|
||||
sync = ton.BlockIdExt;
|
||||
|
||||
wallet.init private_key:InputKey = Ok;
|
||||
wallet.getAccountAddress initital_account_state:wallet.initialAccountState = AccountAddress;
|
||||
wallet.getAccountState account_address:accountAddress = wallet.AccountState;
|
||||
wallet.sendGrams private_key:InputKey destination:accountAddress seqno:int32 valid_until:int53 amount:int64 message:bytes = SendGramsResult;
|
||||
|
||||
wallet.v3.getAccountAddress initital_account_state:wallet.v3.initialAccountState = AccountAddress;
|
||||
|
||||
testGiver.getAccountState = testGiver.AccountState;
|
||||
testGiver.getAccountAddress = AccountAddress;
|
||||
testGiver.sendGrams destination:accountAddress seqno:int32 amount:int64 message:bytes = SendGramsResult;
|
||||
|
||||
sync = Ok;
|
||||
|
||||
//generic.getAccountAddress initital_account_state:generic.InitialAccountState = AccountAddress;
|
||||
generic.getAccountState account_address:accountAddress = generic.AccountState;
|
||||
generic.sendGrams private_key:InputKey source:accountAddress destination:accountAddress amount:int64 timeout:int32 allow_send_to_uninited:Bool message:bytes = SendGramsResult;
|
||||
|
||||
generic.createSendGramsQuery private_key:InputKey source:accountAddress destination:accountAddress amount:int64 timeout:int32 allow_send_to_uninited:Bool message:bytes = query.Info;
|
||||
// revision = 0 -- use default revision
|
||||
// revision = x (x > 0) -- use revision x
|
||||
getAccountAddress initial_account_state:InitialAccountState revision:int32 = AccountAddress;
|
||||
// guessAccountRevision initial_account_state:InitialAccountState = AccountRevisionList;
|
||||
getAccountState account_address:accountAddress = FullAccountState;
|
||||
createQuery private_key:InputKey address:accountAddress timeout:int32 action:Action = query.Info;
|
||||
|
||||
query.send id:int53 = Ok;
|
||||
query.forget id:int53 = Ok;
|
||||
query.estimateFees id:int53 ignore_chksig:Bool = query.Fees;
|
||||
// query.emulate id:int53 ignore_chksig:Bool = query.EmulationResult;
|
||||
query.getInfo id:int53 = query.Info;
|
||||
|
||||
smc.load account_address:accountAddress = smc.Info;
|
||||
//smc.forget id:int53 = Ok;
|
||||
smc.getCode id:int53 = tvm.Cell;
|
||||
smc.getData id:int53 = tvm.Cell;
|
||||
smc.getState id:int53 = tvm.Cell;
|
||||
smc.runGetMethod id:int53 method:smc.MethodId stack:vector<tvm.StackEntry> = smc.RunResult;
|
||||
|
||||
dns.resolve account_address:accountAddress name:string category:int32 = dns.Resolved;
|
||||
|
||||
onLiteServerQueryResult id:int64 bytes:bytes = Ok;
|
||||
onLiteServerQueryError id:int64 error:error = Ok;
|
||||
|
||||
withBlock id:ton.blockIdExt function:Function = Object;
|
||||
|
||||
runTests dir:string = Ok;
|
||||
|
||||
liteServer.getInfo = liteServer.Info;
|
||||
|
@ -178,6 +178,17 @@ trait Loop
|
||||
$this->stopLoop = true;
|
||||
$this->signalUpdate();
|
||||
}
|
||||
/**
|
||||
* Start MadelineProto's update handling loop in background, or run the provided async callable.
|
||||
*
|
||||
* @param callable $callback Async callable to run
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function loopFork($callback = null): void
|
||||
{
|
||||
Tools::callFork($this->loop($callback));
|
||||
}
|
||||
/**
|
||||
* Close connection with client, connected via web.
|
||||
*
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use danog\MadelineProto\Logger;
|
||||
use danog\MadelineProto\TON\API;
|
||||
use danog\MadelineProto\Tools;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user