Stability fixes

This commit is contained in:
Daniil Gentili 2018-02-19 11:48:43 +00:00
parent c0e4afc646
commit ebceeda29b
11 changed files with 90 additions and 115 deletions

View File

@ -37,7 +37,7 @@ while (true) {
case 'updateNewMessage':
case 'updateNewChannelMessage':
if (isset($update['update']['message']['out']) && $update['update']['message']['out']) {
continue;
// continue;
}
$res = json_encode($update, JSON_PRETTY_PRINT);
if ($res == '') {
@ -45,16 +45,16 @@ while (true) {
}
try {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['_'] === 'updateNewMessage' ? $update['update']['message']['from_id'] : $update['update']['message']['to_id'], 'message' => $res, 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
// $MadelineProto->messages->sendMessage(['peer' => $update['update']['_'] === 'updateNewMessage' ? $update['update']['message']['from_id'] : $update['update']['message']['to_id'], 'message' => $res, 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
try {
if (isset($update['update']['message']['media']) && ($update['update']['message']['media']['_'] == 'messageMediaPhoto' || $update['update']['message']['media']['_'] == 'messageMediaDocument')) {
$time = time();
$time = microtime(true);
$file = $MadelineProto->download_to_dir($update['update']['message']['media'], '/tmp');
$MadelineProto->messages->sendMessage(['peer' => isset($update['update']['message']['from_id']) ? $update['update']['message']['from_id'] : $update['update']['message']['to_id'], 'message' => 'Downloaded to '.$file.' in '.(time() - $time).' seconds', 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
$MadelineProto->messages->sendMessage(['peer' => isset($update['update']['message']['from_id']) ? $update['update']['message']['from_id'] : $update['update']['message']['to_id'], 'message' => 'Downloaded to '.$file.' in '.(microtime(true) - $time).' seconds', 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json']]]);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);

View File

@ -54,27 +54,22 @@ if ($MadelineProto === false) {
\danog\MadelineProto\Logger::log(['Registering new user'], \danog\MadelineProto\Logger::NOTICE);
$authorization = $MadelineProto->complete_signup(readline('Please enter your first name: '), readline('Please enter your last name (can be empty): '));
}
echo 'Serializing MadelineProto to s.madeline...'.PHP_EOL;
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('s.madeline', $MadelineProto).' bytes'.PHP_EOL;
} else {
$MadelineProto->bot_login(getenv('BOT_TOKEN'));
}
}
$message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd) (Ngimbonga ngaso sonke isikhathi ukusebenza)' : ('Travis ci tests in progress: commit '.getenv('TRAVIS_COMMIT').', job '.getenv('TRAVIS_JOB_NUMBER').', PHP version: '.getenv('TRAVIS_PHP_VERSION'));
echo 'Serializing MadelineProto to s.madeline...'.PHP_EOL;
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('s.madeline', $MadelineProto).' bytes'.PHP_EOL;
$MadelineProto->session = 's.madeline';
$sent = [-440592694 => true];
$offset = 0;
while (true) {
try {
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
//\danog\MadelineProto\Logger::log([$updates]);
foreach ($updates as $update) {
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('s.madeline', $MadelineProto).' bytes'.PHP_EOL;
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
switch ($update['update']['_']) {
/*case 'updateNewChannelMessage':
@ -87,7 +82,7 @@ while (true) {
}
break;*/
case 'updateNewEncryptedMessage':
//var_dump($MadelineProto->download_to_dir($update['update']['message'], '.'));
var_dump($MadelineProto->download_to_dir($update['update']['message'], '.'));
if (isset($sent[$update['update']['message']['chat_id']])) {
continue;
}
@ -133,7 +128,6 @@ $secret = $update['update']['message']['chat_id'];
while ($i < $argv[1]) {
echo "SENDING MESSAGE $i TO ".$update['update']['message']['chat_id'].PHP_EOL;
$MadelineProto->messages->sendEncrypted(['peer' => $update['update']['message']['chat_id'], 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => (string) ($i++)]]);
\danog\MadelineProto\Serialization::serialize('s.madeline', $MadelineProto);
}
$sent[$update['update']['message']['chat_id']] = true;
}
@ -144,5 +138,4 @@ $secret = $update['update']['message']['chat_id'];
var_dump($e->getMessage());
}
//sleep(1);
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('s.madeline', $MadelineProto).' bytes'.PHP_EOL;
}

View File

@ -45,7 +45,6 @@ if (!extension_loaded('pthreads')) {
{
if (in_array($name, [\SO_RCVTIMEO, \SO_SNDTIMEO])) {
$this->timeout = ['sec' => (int) $value, 'usec' => (int) (($value - (int) $value) * 1000000)];
stream_set_timeout($this->sock, $this->timeout['sec'], $this->timeout['usec']);
return true;
}
@ -83,8 +82,10 @@ if (!extension_loaded('pthreads')) {
if ($this->domain === AF_INET6 && strpos($address, ':') !== false) {
$address = '['.$address.']';
}
$this->sock = fsockopen($this->protocol.'://'.$address, $port);
$errno = 0;
$errstr = '';
$this->sock = fsockopen($this->protocol.'://'.$address, $port, $errno, $errstr, $this->timeout['sec'] + ($this->timeout['usec']/1000000));
stream_set_timeout($this->sock, $this->timeout['sec'], $this->timeout['usec']);
return true;
}

View File

@ -51,7 +51,6 @@ class Connection
public function __magic_construct($proxy, $extra, $ip, $port, $protocol, $timeout, $ipv6)
{
// Can use:
/*
- tcp_full
@ -77,11 +76,11 @@ class Connection
if ($has_proxy && $this->extra !== []) {
$this->sock->setExtra($this->extra);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
if (!$this->sock->connect($ip, $port)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['socket_con_error']);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
$this->sock->setBlocking(true);
$this->write(chr(239));
break;
@ -90,11 +89,11 @@ class Connection
if ($has_proxy && $this->extra !== []) {
$this->sock->setExtra($this->extra);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
if (!$this->sock->connect($ip, $port)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['socket_con_error']);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
$this->sock->setBlocking(true);
$this->write(str_repeat(chr(238), 4));
break;
@ -104,11 +103,11 @@ class Connection
if ($has_proxy && $this->extra !== []) {
$this->sock->setExtra($this->extra);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
if (!$this->sock->connect($ip, $port)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['socket_con_error']);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
$this->sock->setBlocking(true);
$this->out_seq_no = -1;
@ -119,11 +118,11 @@ class Connection
if ($has_proxy && $this->extra !== []) {
$this->sock->setExtra($this->extra);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
if (!$this->sock->connect($ip, $port)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['socket_con_error']);
}
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
$this->sock->setBlocking(true);
do {
$random = $this->random(64);
@ -166,12 +165,10 @@ class Connection
if ($has_proxy && $this->extra !== []) {
$this->sock->setExtra($this->extra);
}
if (!$this->sock->connect($this->parsed['host'], $port)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['socket_con_error']);
}
if (!\danog\MadelineProto\Logger::$has_thread) {
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
if (!$this->sock->connect($this->parsed['host'], $port)) {
throw new Exception(\danog\MadelineProto\Lang::$current_lang['socket_con_error']);
}
$this->sock->setBlocking(true);
break;

View File

@ -63,8 +63,13 @@ class DataCenter
}
$dc_config_number = isset($this->settings[$dc_number]) ? $dc_number : 'all';
$test = $this->settings[$dc_config_number]['test_mode'] ? 'test' : 'main';
$x = 0;
do {
$ipv6 = $this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4';
if (!isset($this->dclist[$test][$ipv6][$dc_number]['ip_address'])) {
unset($this->sockets[$dc_number]);
@ -96,9 +101,8 @@ class DataCenter
$address = $this->settings[$dc_config_number]['protocol'].'://'.$address.'/api';
}
\danog\MadelineProto\Logger::log([sprintf(\danog\MadelineProto\Lang::$current_lang['dc_con_test_start'], $dc_number, $test, $ipv6, $this->settings[$dc_config_number]['protocol'])], \danog\MadelineProto\Logger::VERBOSE);
$x = 0;
do {
foreach (array_unique([$port, 443, 80, 88]) as $port) {
\danog\MadelineProto\Logger::log(['Trying connection on port '.$port.'...'], \danog\MadelineProto\Logger::WARNING);
try {
if (isset($this->sockets[$dc_number]->old)) {
$this->sockets[$dc_number]->__construct($this->settings[$dc_config_number]['proxy'], $this->settings[$dc_config_number]['proxy_extra'], $address, $port, $this->settings[$dc_config_number]['protocol'], $this->settings[$dc_config_number]['timeout'], $this->settings[$dc_config_number]['ipv6']);
@ -107,39 +111,23 @@ class DataCenter
$this->sockets[$dc_number] = new Connection($this->settings[$dc_config_number]['proxy'], $this->settings[$dc_config_number]['proxy_extra'], $address, $port, $this->settings[$dc_config_number]['protocol'], $this->settings[$dc_config_number]['timeout'], $this->settings[$dc_config_number]['ipv6']);
}
\danog\MadelineProto\Logger::log(['OK!'], \danog\MadelineProto\Logger::WARNING);
return true;
} catch (\danog\MadelineProto\Exception $e) {
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
}
}
switch ($x) {
case 0:
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection on port 443...'], \danog\MadelineProto\Logger::WARNING);
$port = 443;
$this->settings[$dc_config_number]['ipv6'] = !$this->settings[$dc_config_number]['ipv6'];
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection with '.($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4').'...'], \danog\MadelineProto\Logger::WARNING);
continue;
case 1:
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection on port 80...'], \danog\MadelineProto\Logger::WARNING);
$port = 80;
$this->settings[$dc_config_number]['proxy'] = '\Socket';
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection without the proxy with '.($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4').'...'], \danog\MadelineProto\Logger::WARNING);
continue;
case 2:
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection on port 88...'], \danog\MadelineProto\Logger::WARNING);
$port = 88;
continue;
case 3:
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection on port 443 without the proxy...'], \danog\MadelineProto\Logger::WARNING);
$port = 443;
$this->settings[$dc_config_number]['proxy'] = '\Socket';
continue;
case 4:
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection on port 80 without the proxy...'], \danog\MadelineProto\Logger::WARNING);
$port = 80;
$this->settings[$dc_config_number]['proxy'] = '\Socket';
continue;
case 5:
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection on port 88 without the proxy...'], \danog\MadelineProto\Logger::WARNING);
$port = 88;
$this->settings[$dc_config_number]['proxy'] = '\Socket';
$this->settings[$dc_config_number]['ipv6'] = !$this->settings[$dc_config_number]['ipv6'];
\danog\MadelineProto\Logger::log(['Connection failed, retrying connection without the proxy with '.($this->settings[$dc_config_number]['ipv6'] ? 'ipv6' : 'ipv4').'...'], \danog\MadelineProto\Logger::WARNING);
continue;
default:
return false;

View File

@ -46,7 +46,7 @@ class MTProto
/*
const V = 71;
*/
const V = 89;
const V = 90;
const NOT_LOGGED_IN = 0;
const WAITING_CODE = 1;

View File

@ -22,6 +22,7 @@ trait AuthKeyHandler
{
public function create_auth_key($expires_in, $datacenter)
{
$req_pq = strpos($datacenter, 'cdn') ? 'req_pq' : 'req_pq_multi';
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {
try {
\danog\MadelineProto\Logger::log([\danog\MadelineProto\Lang::$current_lang['req_pq']], \danog\MadelineProto\Logger::VERBOSE);
@ -44,7 +45,7 @@ trait AuthKeyHandler
* ]
*/
$nonce = $this->random(16);
$ResPQ = $this->method_call('req_pq_multi',
$ResPQ = $this->method_call($req_pq,
[
'nonce' => $nonce,
],
@ -370,6 +371,7 @@ trait AuthKeyHandler
$res_authorization['server_salt'] = substr($new_nonce, 0, 8 - 0) ^ substr($server_nonce, 0, 8 - 0);
$res_authorization['auth_key'] = $auth_key_str;
$res_authorization['id'] = substr($auth_key_sha, -8);
$res_authorization['connection_inited'] = false;
\danog\MadelineProto\Logger::log(['Auth key generated'], \danog\MadelineProto\Logger::NOTICE);
@ -398,6 +400,7 @@ trait AuthKeyHandler
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...'], \danog\MadelineProto\Logger::WARNING);
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log(['An exception occurred while generating the authorization key: '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Retrying...'], \danog\MadelineProto\Logger::WARNING);
$req_pq = $req_pq === 'req_pq_multi' ? 'req_pq' : 'req_pq_multi';
} catch (\danog\MadelineProto\RPCErrorException $e) {
if ($e->rpc === 'RPC_CALL_FAIL') {
throw $e;
@ -595,16 +598,18 @@ trait AuthKeyHandler
$socket->temp_auth_key = $this->create_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id);
if (!$cdn) {
$this->bind_temp_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id);
$config = $this->write_client_info('help.getConfig', [], ['datacenter' => $id]);
$config = $this->method_call('help.getConfig', [], ['datacenter' => $id]);
$this->sync_authorization($id);
$this->get_config($config);
}
} else {
$socket->temp_auth_key = $socket->auth_key;
$config = $this->write_client_info('help.getConfig', [], ['datacenter' => $id]);
if (!$cdn) {
$config = $this->method_call('help.getConfig', [], ['datacenter' => $id]);
$this->sync_authorization($id);
$this->get_config($config);
}
}
} elseif (!$cdn) {
$this->sync_authorization($id);
}

View File

@ -349,10 +349,10 @@ trait Files
if (isset($message_media['cdn_key'])) {
$ivec = substr($message_media['cdn_iv'], 0, 12).pack('N', $offset >> 4);
$res['bytes'] = $this->ctr_encrypt($res['bytes'], $message_media['cdn_key'], $ivec);
$this->check_cdn_hash($message_media['file_token'], $offset, $res['bytes'], $datacenter);
}
if (isset($message_media['key'])) {
$res['bytes'] = $ige->decrypt($res['bytes']);
$this->check_cdn_hash($message_media['file_token'], $offset, $res['bytes'], $datacenter);
}
if ($start_at) {
$res['bytes'] = substr($res['bytes'], $start_at);
@ -399,17 +399,19 @@ trait Files
private function check_cdn_hash($file, $offset, $data, &$datacenter)
{
while (strlen($data)) {
if (!isset($this->cdn_hashes[$file][$offset])) {
$this->add_cdn_hashes($this->method_call('upload.getCdnFileHashes', ['file_token' => $file, 'offset' => $offset], ['datacenter' => &$datacenter]));
}
if (!isset($this->cdn_hashes[$file][$offset])) {
throw new \danog\MadelineProto\Exception('Could not fetch CDN hashes for offset '.$offset);
}
if (hash('sha256', $data, true) !== $this->cdn_hashes[$file][$offset]['hash']) {
throw new \danog\MadelineProto\SecurityException('CDN hashe mismatch for offset '.$offset);
if (hash('sha256', substr($data, 0, $this->cdn_hashes[$file][$offset]['limit']), true) !== $this->cdn_hashes[$file][$offset]['hash']) {
throw new \danog\MadelineProto\SecurityException('CDN hash mismatch for offset '.$offset);
}
$data = substr($data, $this->cdn_hashes[$file][$offset]['limit']);
$offset += $this->cdn_hashes[$file][$offset]['limit'];
}
unset($this->cdn_hashes[$file][$offset]);
return true;
}

View File

@ -246,7 +246,7 @@ trait ResponseHandler
case 'Updates':
unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]);
$unset = true;
$this->handle_updates($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']);
if (strpos($datacenter, 'cdn') === false) $this->handle_updates($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']);
$only_updates = true && $only_updates;
break;
default:

View File

@ -473,11 +473,11 @@ trait BotAPI
public function split_to_chunks($text)
{
$total_length = 4096;
$max_length = 4096;
$text_arr = [];
foreach ($this->multipleExplodeKeepDelimiters(["\n"], $text) as $word) {
if (strlen($word) > 4096) {
foreach (str_split($word, 4096) as $vv) {
if (strlen($word) > $max_length) {
foreach (str_split($word, $max_length) as $vv) {
$text_arr[] = $vv;
}
} else {
@ -485,21 +485,13 @@ trait BotAPI
}
}
$i = 0;
$message[0] = '';
$message = [''];
foreach ($text_arr as $word) {
if (strlen($message[$i].$word.' ') <= $total_length) {
if ($text_arr[count($text_arr) - 1] == $word) {
if (strlen($message[$i].$word) <= $max_length) {
$message[$i] .= $word;
} else {
$message[$i] .= $word.' ';
}
} else {
$i++;
if ($text_arr[count($text_arr) - 1] == $word) {
$message[$i] = $word;
} else {
$message[$i] = $word.' ';
}
}
}
@ -510,10 +502,13 @@ trait BotAPI
{
$initialArray = explode(chr(1), str_replace($delimiters, chr(1), $string));
$finalArray = [];
$delimOffset = 0;
foreach ($initialArray as $item) {
$delimOffset += strlen($item);
if (strlen($item) > 0) {
$finalArray[] = $item.$string[strpos($string, $item) + strlen($item)];
$finalArray[] = $item.($delimOffset < strlen($string) ? $string[$delimOffset] : '');
}
$delimOffset++;
}
return $finalArray;

View File

@ -216,28 +216,22 @@ $time = time();
$inputFile = $MadelineProto->upload('tests/60', 'magic'); // This gets an inputFile object with file name magic
var_dump(time() - $time);
$media['document'] = ['_' => 'inputMediaUploadedDocument', 'file' => $inputFile, 'mime_type' => 'magic/magic', 'caption' => 'This file was uploaded using MadelineProto', 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'magic.magic']]];
$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
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);
foreach ($media as $type => $inputMedia) {
$type = $MadelineProto->messages->sendMedia(['peer' => $peer, 'media' => $inputMedia]);
$type = $MadelineProto->messages->sendMedia(['peer' => $peer, 'media' => $inputMedia, 'message' => '['.$message.'](mention:'.$mention.')', 'parse_mode' => 'markdown']);
}
}
//var_dump($MadelineProto->API->get_updates());
if ($bot_token = getenv('BOT_TOKEN')) {
$MadelineProto = new \danog\MadelineProto\API($settings);
$authorization = $MadelineProto->bot_login($bot_token);
\danog\MadelineProto\Logger::log([$authorization], \danog\MadelineProto\Logger::NOTICE);
}
$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
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);
}
//var_dump($MadelineProto->API->get_updates());
var_dump('HERE');