Update to layer 82, implement media DC key exchange, revert logger API change, fix pretty TL traces, implement message splitting for parse_mode messages, fix TOS flow

This commit is contained in:
Daniil Gentili 2018-06-29 18:15:17 +02:00
parent c07ab02c66
commit 855045099e
16 changed files with 1359 additions and 38 deletions

1
.gitignore vendored
View File

@ -109,3 +109,4 @@ phar7
phar5
madeline.phar
madeline.phar.version
big

View File

@ -43,9 +43,9 @@ $docs = [
'readme' => false,
],
[
'tl_schema' => ['telegram' => __DIR__.'/src/danog/MadelineProto/TL_telegram_v81.tl', 'calls' => __DIR__.'/src/danog/MadelineProto/TL_calls.tl', 'secret' => __DIR__.'/src/danog/MadelineProto/TL_secret.tl', 'td' => __DIR__.'/src/danog/MadelineProto/TL_td.tl'],
'title' => 'MadelineProto API documentation (layer 81)',
'description' => 'MadelineProto API documentation (layer 81)',
'tl_schema' => ['telegram' => __DIR__.'/src/danog/MadelineProto/TL_telegram_v82.tl', 'calls' => __DIR__.'/src/danog/MadelineProto/TL_calls.tl', 'secret' => __DIR__.'/src/danog/MadelineProto/TL_secret.tl', 'td' => __DIR__.'/src/danog/MadelineProto/TL_td.tl'],
'title' => 'MadelineProto API documentation (layer 82)',
'description' => 'MadelineProto API documentation (layer 82)',
'output_dir' => __DIR__.'/docs/docs/API_docs',
'readme' => false,
],

2
docs

@ -1 +1 @@
Subproject commit 173bd0ee30b1c9b374377473851d18e643344594
Subproject commit da3160351138eec872ec2f840f6bd51c99fde17e

View File

@ -709,6 +709,15 @@ interface contacts
* @return Vector_of_SavedContact
*/
public function getSaved();
/**
* @param array params [
* Bool enabled,
* ]
*
* @return bool
*/
public function toggleTopPeers(array $params);
}
interface messages
@ -729,6 +738,7 @@ interface messages
* int offset_id,
* InputPeer offset_peer,
* int limit,
* int hash,
* ]
*
* @return messages_Dialogs
@ -1746,6 +1756,21 @@ interface messages
* @return Vector_of_MessageRange
*/
public function getSplitRanges();
/**
* @param array params [
* boolean unread,
* InputDialogPeer peer,
* ]
*
* @return bool
*/
public function markDialogUnread(array $params);
/**
* @return Vector_of_DialogPeer
*/
public function getDialogUnreadMarks();
}
interface updates

View File

@ -4408,6 +4408,35 @@ class Lang
'object_savedPhoneContact_param_date_type_int' => '',
'object_account.takeout' => '',
'object_account.takeout_param_id_type_long' => '',
'method_contacts.toggleTopPeers' => 'Toggle top peers',
'method_contacts.toggleTopPeers_param_enabled_type_Bool' => 'Enable or disable top peer',
'method_messages.getDialogs_param_hash_type_int' => '$MadelineProto->gen_vector_hash(ids of previously fetched dialogs or [])',
'method_messages.markDialogUnread' => 'Mark dialog as unread ',
'method_messages.markDialogUnread_param_unread_type_true' => 'Should it be marked or unmarked as read',
'method_messages.markDialogUnread_param_peer_type_InputDialogPeer' => 'The dialog to mark as unread',
'method_messages.getDialogUnreadMarks' => 'Get dialogs marked as unread manually',
'object_inputMediaContact_param_vcard_type_string' => '',
'object_messageMediaContact_param_vcard_type_string' => '',
'object_dialog_param_unread_mark_type_true' => '',
'object_geoPoint_param_access_hash_type_long' => '',
'object_messages.dialogsNotModified' => '',
'object_messages.dialogsNotModified_param_count_type_int' => '',
'object_updateDialogUnreadMark' => '',
'object_updateDialogUnreadMark_param_unread_type_true' => '',
'object_updateDialogUnreadMark_param_peer_type_DialogPeer' => '',
'object_config_param_dc_txt_domain_name_type_string' => '',
'object_config_param_gif_search_username_type_string' => '',
'object_config_param_venue_search_username_type_string' => '',
'object_config_param_img_search_username_type_string' => '',
'object_config_param_static_maps_provider_type_string' => '',
'object_config_param_caption_length_max_type_int' => '',
'object_config_param_message_length_max_type_int' => '',
'object_config_param_webfile_dc_id_type_int' => '',
'object_inputBotInlineMessageMediaContact_param_vcard_type_string' => '',
'object_botInlineMessageMediaContact_param_vcard_type_string' => '',
'object_contacts.topPeersDisabled' => '',
'object_draftMessageEmpty_param_date_type_int' => '',
'object_inputWebFileGeoPointLocation_param_access_hash_type_long' => '',
),
);
@ -8662,5 +8691,34 @@ class Lang
'object_savedPhoneContact_param_date_type_int' => '',
'object_account.takeout' => '',
'object_account.takeout_param_id_type_long' => '',
'method_contacts.toggleTopPeers' => 'Toggle top peers',
'method_contacts.toggleTopPeers_param_enabled_type_Bool' => 'Enable or disable top peer',
'method_messages.getDialogs_param_hash_type_int' => '$MadelineProto->gen_vector_hash(ids of previously fetched dialogs or [])',
'method_messages.markDialogUnread' => 'Mark dialog as unread ',
'method_messages.markDialogUnread_param_unread_type_true' => 'Should it be marked or unmarked as read',
'method_messages.markDialogUnread_param_peer_type_InputDialogPeer' => 'The dialog to mark as unread',
'method_messages.getDialogUnreadMarks' => 'Get dialogs marked as unread manually',
'object_inputMediaContact_param_vcard_type_string' => '',
'object_messageMediaContact_param_vcard_type_string' => '',
'object_dialog_param_unread_mark_type_true' => '',
'object_geoPoint_param_access_hash_type_long' => '',
'object_messages.dialogsNotModified' => '',
'object_messages.dialogsNotModified_param_count_type_int' => '',
'object_updateDialogUnreadMark' => '',
'object_updateDialogUnreadMark_param_unread_type_true' => '',
'object_updateDialogUnreadMark_param_peer_type_DialogPeer' => '',
'object_config_param_dc_txt_domain_name_type_string' => '',
'object_config_param_gif_search_username_type_string' => '',
'object_config_param_venue_search_username_type_string' => '',
'object_config_param_img_search_username_type_string' => '',
'object_config_param_static_maps_provider_type_string' => '',
'object_config_param_caption_length_max_type_int' => '',
'object_config_param_message_length_max_type_int' => '',
'object_config_param_webfile_dc_id_type_int' => '',
'object_inputBotInlineMessageMediaContact_param_vcard_type_string' => '',
'object_botInlineMessageMediaContact_param_vcard_type_string' => '',
'object_contacts.topPeersDisabled' => '',
'object_draftMessageEmpty_param_date_type_int' => '',
'object_inputWebFileGeoPointLocation_param_access_hash_type_long' => '',
);
}

View File

@ -54,7 +54,7 @@ class Logger
self::$default = new self($mode, $optional, $prefix, $level, $max_size);
}
public function __construct($mode, $optional, $prefix, $level, $max_size)
public function __construct($mode, $optional = null, $prefix = '', $level = self::NOTICE, $max_size = 100*1024*1024)
{
if ($mode === null) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['no_mode_specified']);

File diff suppressed because one or more lines are too long

View File

@ -528,25 +528,28 @@ trait AuthKeyHandler
try {
foreach ($this->datacenter->sockets as $id => $socket) {
$cdn = strpos($id, 'cdn');
if (strpos($id, 'media') !== false && !$cdn) {
continue;
}
if ($socket->session_id === null) {
$socket->session_id = $this->random(8);
$socket->session_in_seq_no = 0;
$socket->session_out_seq_no = 0;
}
$cdn = strpos($id, 'cdn');
$media = strpos($id, 'media');
if ($socket->temp_auth_key === null || $socket->auth_key === null) {
$dc_config_number = isset($this->settings['connection_settings'][$id]) ? $id : 'all';
if ($socket->auth_key === null && !$cdn) {
if ($socket->auth_key === null && !$cdn && !$media) {
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['gen_perm_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE);
$socket->auth_key = $this->create_auth_key(-1, $id);
$socket->authorized = false;
} else if ($socket->auth_key === null && $media) {
$socket->auth_key = $this->datacenter->sockets[intval($id)]->auth_key;
$socket->authorized = $this->datacenter->sockets[intval($id)]->authorized;
}
if ($this->settings['connection_settings'][$dc_config_number]['pfs']) {
if (!$cdn) {
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['gen_temp_auth_key'], $id), \danog\MadelineProto\Logger::NOTICE);
$socket->temp_auth_key = null;
$socket->temp_auth_key = $this->create_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id);
$this->bind_temp_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id);
$config = $this->method_call('help.getConfig', [], ['datacenter' => $id]);

View File

@ -41,9 +41,13 @@ trait CallHandler
$this->logger->logger("Didn't serialize in a while, doing that now...");
$this->wrapper->serialize($this->wrapper->session);
}
if (isset($args['message']) && is_string($args['message']) && $this->mb_strlen($args['message']) > 4096 && !isset($args['parse_mode'])) {
$message_chunks = $this->split_to_chunks($args['message']);
$args['message'] = array_shift($message_chunks);
if (isset($aargs['file']) && $aargs['file'] && isset($this->datacenter->sockets[$aargs['datacenter'].'_media'])) {
\danog\MadelineProto\Logger::log('Using media DC');
$aargs['datacenter'] .= '_media';
}
if (isset($args['message']) && is_string($args['message']) && $this->mb_strlen($args['message']) > 4096) {
$arg_chunks = $this->split_to_chunks($args);
$args = array_shift($arg_chunks);
}
$args = $this->botAPI_to_MTProto($args);
if (isset($args['ping_id']) && is_int($args['ping_id'])) {
@ -302,10 +306,9 @@ trait CallHandler
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['connection_inited'] = true;
}
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id] = [];
if (isset($message_chunks) && count($message_chunks)) {
if (isset($arg_chunks) && count($arg_chunks)) {
$server_answer = [$server_answer];
foreach ($message_chunks as $message) {
$args['message'] = $message;
foreach ($arg_chunks as $args) {
$server_answer[] = $this->method_call($method, $args, $aargs);
}
}

View File

@ -69,7 +69,7 @@ trait Files
$bytes = $ige->encrypt(str_pad($bytes, $part_size, chr(0)));
}
hash_update($ctx, $bytes);
if (!$this->method_call($method, ['file_id' => $file_id, 'file_part' => $part_num++, 'file_total_parts' => $part_total_num, 'bytes' => $bytes], ['heavy' => true, 'datacenter' => &$datacenter])) {
if (!$this->method_call($method, ['file_id' => $file_id, 'file_part' => $part_num++, 'file_total_parts' => $part_total_num, 'bytes' => $bytes], ['heavy' => true, 'file' => false, 'datacenter' => &$datacenter])) {
throw new \danog\MadelineProto\Exception('An error occurred while uploading file part '.$part_num);
}
$cb(ftell($f) * 100 / $file_size);
@ -393,7 +393,7 @@ trait Files
}
try {
$res = $cdn ? $this->method_call('upload.getCdnFile', ['file_token' => $message_media['file_token'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]) : $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => &$datacenter]);
$res = $cdn ? $this->method_call('upload.getCdnFile', ['file_token' => $message_media['file_token'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'file' => false, 'datacenter' => $datacenter]) : $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'file' => false, 'datacenter' => &$datacenter]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
if (strpos($e->rpc, 'FLOOD_WAIT_') === 0) {
//if (isset($message_media['MessageMedia']) && !$this->get_self()['bot']) $this->method_call('messages.sendMedia', ['peer' => '@danogentili', 'media' => $message_media['MessageMedia'], 'message' => 'This is broken'], ['datacenter' => $this->datacenter->curdc]);

View File

@ -49,7 +49,9 @@ trait ResponseHandler
foreach ($this->datacenter->sockets[$datacenter]->new_incoming as $current_msg_id) {
$unset = false;
$this->logger->logger((isset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ').$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].' from DC '.$datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
//$this->logger->logger($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
//var_dump($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
switch ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_']) {
case 'msgs_ack':
unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]);
@ -333,6 +335,12 @@ trait ResponseHandler
case 303:
$this->datacenter->curdc = $aargs['datacenter'] = (int) preg_replace('/[^0-9]+/', '', $server_answer['error_message']);
if (isset($aargs['file']) && $aargs['file'] && isset($this->datacenter->sockets[$aargs['datacenter'].'_media'])) {
\danog\MadelineProto\Logger::log('Using media DC');
$aargs['datacenter'] .= '_media';
}
throw new \danog\MadelineProto\Exception('Received request to switch to DC '.$this->datacenter->curdc);
case 401:
switch ($server_answer['error_message']) {

View File

@ -442,11 +442,11 @@ trait BotAPI
if (isset($arguments['parse_mode']['_'])) {
$arguments['parse_mode'] = str_replace('textParseMode', '', $arguments['parse_mode']['_']);
}
if (preg_match('/markdown/i', $arguments['parse_mode'])) {
if (stripos($arguments['parse_mode'], 'markdown') !== false) {
$arguments['message'] = \Parsedown::instance()->line($arguments['message']);
$arguments['parse_mode'] = 'HTML';
}
if (preg_match('/html/i', $arguments['parse_mode'])) {
if (stripos($arguments['parse_mode'], 'html') !== false) {
$new_message = '';
$arguments['message'] = $this->html_fixtags($arguments['message']);
@ -473,12 +473,17 @@ trait BotAPI
return $arguments;
}
public function split_to_chunks($text)
public function split_to_chunks($args)
{
$args = $this->parse_mode($args);
$multiple_args_base = array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']);
$multiple_args = [$multiple_args_base];
$max_length = 4096;
$text_arr = [];
foreach ($this->multipleExplodeKeepDelimiters(["\n"], $text) as $word) {
if (strlen($word) > $max_length) {
foreach ($this->multipleExplodeKeepDelimiters(["\n"], $args['message']) as $word) {
if ($this->mb_strlen($word) > $max_length) {
foreach (str_split($word, $max_length) as $vv) {
$text_arr[] = $vv;
}
@ -487,17 +492,44 @@ trait BotAPI
}
}
$i = 0;
$message = [''];
foreach ($text_arr as $word) {
if (strlen($message[$i].$word) <= $max_length) {
$message[$i] .= $word;
if ($this->mb_strlen($multiple_args[$i]['message'].$word) <= $max_length) {
$multiple_args[$i]['message'] .= $word;
} else {
$i++;
$message[$i] = $word;
$multiple_args[$i] = $multiple_args_base;
$multiple_args[$i]['message'] .= $word;
}
}
return $message;
$i = 0;
$offset = 0;
foreach ($args['entities'] as $entity) {
do {
while ($entity['offset'] > $offset+$this->mb_strlen($multiple_args[$i]['message'])) {
$offset += $this->mb_strlen($multiple_args[$i]['message']);
$i++;
}
$entity['offset'] -= $offset;
if ($entity['offset']+$entity['length'] > $this->mb_strlen($multiple_args[$i]['message'])) {
$newentity = $entity;
$newentity['length'] = $entity['length']-($this->mb_strlen($multiple_args[$i]['message'])-$entity['offset']);
$entity['length'] = $this->mb_strlen($multiple_args[$i]['message'])-$entity['offset'];
$multiple_args[$i]['entities'][] = $entity;
$offset += $this->mb_strlen($multiple_args[$i]['message']);
$newentity['offset'] = $offset;
$i++;
$entity = $newentity;
continue;
} else {
$multiple_args[$i]['entities'][] = $entity;
break;
}
} while (true);
}
return $multiple_args;
}
public function multipleExplodeKeepDelimiters($delimiters, $string)
@ -506,9 +538,9 @@ trait BotAPI
$finalArray = [];
$delimOffset = 0;
foreach ($initialArray as $item) {
$delimOffset += strlen($item);
if (strlen($item) > 0) {
$finalArray[] = $item.($delimOffset < strlen($string) ? $string[$delimOffset] : '');
$delimOffset += $this->mb_strlen($item);
if ($this->mb_strlen($item) > 0) {
$finalArray[] = $item.($delimOffset < $this->mb_strlen($string) ? $string[$delimOffset] : '');
}
$delimOffset++;
}

View File

@ -28,7 +28,7 @@ trait PrettyException
foreach (array_reverse($this->getTrace()) as $k => $frame) {
if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) {
if ($frame['args'][2] !== '') {
$this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2].PHP_EOL;
$this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2];
$tl = true;
}
} else {

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ trait TOS
{
public function check_tos()
{
if ($this->authorized === self::LOGGED_IN) {
if ($this->authorized === self::LOGGED_IN && !$this->get_self()['bot']) {
if ($this->tos['expires'] < time()) {
$this->logger->logger('Fetching TOS...');
$this->tos = $this->method_call('help.getTermsOfServiceUpdate', [], ['datacenter' => $this->datacenter->curdc]);

View File

@ -45,6 +45,10 @@ echo 'Loading MadelineProto...'.PHP_EOL;
$MadelineProto = new \danog\MadelineProto\API(getcwd().'/testing.madeline', $settings);
$MadelineProto->messages->sendMessage(['peer' => '@pwrtelegramgroupita', 'message' => '<b>'.str_repeat('a b c d', 700).'</b>', 'parse_mode' => 'markdown']);
try {
$MadelineProto->get_self();
} catch (\danog\MadelineProto\Exception $e) {
@ -248,6 +252,12 @@ $message = 'yay';
$mention = $MadelineProto->get_info(getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
$mention = $mention['user_id']; // Selects only the numeric user id
/*
$t = time();
$MadelineProto->upload('big');
var_dump(time()-$t);
*/
foreach (json_decode(getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => mb_strlen($message), 'user_id' => $mention]]]);
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
@ -262,3 +272,5 @@ foreach (json_decode(getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => mb_strlen($message), 'user_id' => $mention]]]);
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
}