Performance improvements

This commit is contained in:
Daniil Gentili 2020-02-07 21:13:49 +01:00
parent 17bacd1389
commit f8ea85a551
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
29 changed files with 783 additions and 181 deletions

View File

@ -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",

View File

@ -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;
}

View File

@ -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.
*

View File

@ -479,7 +479,9 @@ class DataCenterConnection implements JsonSerializable
$count = \count($backup);
$this->API->logger->logger("Restoring {$count} messages to DC {$this->datacenter}");
foreach ($backup as $message) {
Tools::callFork($this->getConnection()->sendMessage($message, false));
if (isset($message['body'])) {
Tools::callFork($this->getConnection()->sendMessage($message, false));
}
}
$this->flush();
}

View File

@ -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) {

View File

@ -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.
*

View File

@ -12,7 +12,7 @@
* @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
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
namespace danog\MadelineProto;
@ -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' => '',
];
}

View File

@ -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());

View File

@ -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)) {

View File

@ -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;

View File

@ -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));
}

View File

@ -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())] = [];
} 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;
}
if (PHP_INT_SIZE === 8) {
\class_alias(MsgIdHandler64::class, \danog\MadelineProto\MTProtoSession\MsgIdHandler::class);
} else {
\class_alias(MsgIdHandler32::class, \danog\MadelineProto\MTProtoSession\MsgIdHandler::class);
}

View File

@ -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;
}
}

View File

@ -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'};
}
}

View File

@ -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);
}

View File

@ -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'];
}

View File

@ -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();
}
}
/**

View File

@ -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);

View File

@ -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);
}

View 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']));
}
}
})());

View File

@ -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
*

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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---

View File

@ -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;
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;
//
// 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: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;

View File

@ -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.
*

View File

@ -2,6 +2,7 @@
use danog\MadelineProto\Logger;
use danog\MadelineProto\TON\API;
use danog\MadelineProto\Tools;
require 'vendor/autoload.php';

View File

@ -1,13 +1,13 @@
{
"liteservers": [
{
{
"ip": 861606190,
"port": 9999,
"id": {
"@type": "pub.ed25519",
"id": {
"@type": "pub.ed25519",
"key": "T10NJq2tgx6LpTHj734fSNYJ6S2w1hTdFRXJaj5st80"
}
}
}
}
],
"validator": {
"@type": "validator.config.global",