Style fixes

This commit is contained in:
Daniil Gentili 2019-06-04 14:55:58 +02:00 committed by GitHub
parent 832df205c4
commit a1daca04da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 576 additions and 369 deletions

View File

@ -1,28 +1,41 @@
<?php <?php
$not_subbing = []; $not_subbing = [];
foreach (explode("\n", shell_exec("find src -type f -name '*.php'")) as $file) { foreach (explode("\n", shell_exec("find src -type f -name '*.php'")) as $file) {
if (!$file) continue; if (!$file) {
if (in_array(basename($file, '.php'), ['APIFactory', 'API', 'Connection', 'Coroutine', 'ReferenceDatabase', 'ProxySocketPool'])) continue; continue;
if (strpos($file, 'Loop/')) continue; }
if (strpos($file, 'Stream/')) continue; if (in_array(basename($file, '.php'), ['APIFactory', 'API', 'Connection', 'Coroutine', 'ReferenceDatabase', 'ProxySocketPool'])) {
if (strpos($file, 'Server/')) continue; continue;
if (strpos($file, 'Async/')) continue; }
if (strpos($file, 'Loop/')) {
continue;
}
if (strpos($file, 'Stream/')) {
continue;
}
if (strpos($file, 'Server/')) {
continue;
}
if (strpos($file, 'Async/')) {
continue;
}
$to_sub = []; $to_sub = [];
$last_match = null; $last_match = null;
foreach (explode("\n", $filec = file_get_contents($file)) as $number => $line) { foreach (explode("\n", $filec = file_get_contents($file)) as $number => $line) {
if (preg_match("/public function (\w*)[(]/", $line, $matches)) { if (preg_match("/public function (\w*)[(]/", $line, $matches)) {
$last_match = stripos($matches[1], 'async') === false ? $matches[1] : null; $last_match = stripos($matches[1], 'async') === false ? $matches[1] : null;
} }
if (preg_match("/function [(]/", $line) && stripos($line, 'public function') === false) { if (preg_match('/function [(]/', $line) && stripos($line, 'public function') === false) {
$last_match = 0; $last_match = 0;
} }
if (strpos($line, "yield") !== false) { if (strpos($line, 'yield') !== false) {
if ($last_match) { if ($last_match) {
echo ("subbing $last_match for $line at $number in $file".PHP_EOL); echo "subbing $last_match for $line at $number in $file".PHP_EOL;
$to_sub []= $last_match; $to_sub[] = $last_match;
} else if ($last_match === 0) { } elseif ($last_match === 0) {
echo ("============\nNOT SUBBING $last_match for $line at $number in $file\n============".PHP_EOL); echo "============\nNOT SUBBING $last_match for $line at $number in $file\n============".PHP_EOL;
$not_subbing[$file] = $file; $not_subbing[$file] = $file;
} }
} }
@ -30,9 +43,11 @@ foreach (explode("\n", shell_exec("find src -type f -name '*.php'")) as $file) {
$input = []; $input = [];
$output = []; $output = [];
foreach ($to_sub as $func) { foreach ($to_sub as $func) {
$input []= "public function $func("; $input[] = "public function $func(";
$output []= "public function $func"."_async("; $output[] = "public function $func".'_async(';
}
if ($input) {
file_put_contents($file, str_replace($input, $output, $filec));
} }
if ($input) file_put_contents($file, str_replace($input, $output, $filec));
} }
var_dump(array_values($not_subbing)); var_dump(array_values($not_subbing));

15
bot.php
View File

@ -17,7 +17,7 @@ set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelinePro
*/ */
if (!file_exists(__DIR__.'/vendor/autoload.php')) { if (!file_exists(__DIR__.'/vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL; echo 'You did not run composer update, using madeline.php'.PHP_EOL;
define('MADELINE_BRANCH',''); define('MADELINE_BRANCH', '');
if (!file_exists('madeline.php')) { if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
} }
@ -33,8 +33,12 @@ class EventHandler extends \danog\MadelineProto\EventHandler
if (isset($update['message']['out']) && $update['message']['out']) { if (isset($update['message']['out']) && $update['message']['out']) {
return; return;
} }
if ($update['_'] === 'updateReadChannelOutbox') return; if ($update['_'] === 'updateReadChannelOutbox') {
if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') return; return;
}
if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') {
return;
}
$res = json_encode($update, JSON_PRETTY_PRINT); $res = json_encode($update, JSON_PRETTY_PRINT);
if ($res == '') { if ($res == '') {
@ -50,14 +54,15 @@ class EventHandler extends \danog\MadelineProto\EventHandler
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
\danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR); \danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
if (stripos($e->getMessage(), 'invalid constructor given') === false) \danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR); if (stripos($e->getMessage(), 'invalid constructor given') === false) {
\danog\MadelineProto\Logger::log((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
}
//$this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); //$this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} }
} }
} }
$settings = ['logger' => ['logger_level' => 5]]; $settings = ['logger' => ['logger_level' => 5]];
$MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings); $MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings);
$MadelineProto->async(true); $MadelineProto->async(true);
$MadelineProto->loop(function () use ($MadelineProto) { $MadelineProto->loop(function () use ($MadelineProto) {

View File

@ -107,7 +107,7 @@ $order = [
'PROXY', 'PROXY',
'USING_METHODS', 'USING_METHODS',
'CONTRIB', 'CONTRIB',
'TEMPLATES' 'TEMPLATES',
]; ];
$index = ''; $index = '';
$files = glob('docs/docs/docs/*md'); $files = glob('docs/docs/docs/*md');
@ -158,7 +158,7 @@ foreach ($orderedfiles as $key => $filename) {
$url = $matches[3][$key][0] === '#' ? $file.$matches[3][$key] : $matches[3][$key]; $url = $matches[3][$key][0] === '#' ? $file.$matches[3][$key] : $matches[3][$key];
$index .= "$spaces* [$name]($url)\n"; $index .= "$spaces* [$name]($url)\n";
if ($name === 'FULL API Documentation with descriptions') { if ($name === 'FULL API Documentation with descriptions') {
$spaces .= " "; $spaces .= ' ';
preg_match_all('|\* (.*)|', file_get_contents('docs/docs/API_docs/methods/index.md'), $smatches); preg_match_all('|\* (.*)|', file_get_contents('docs/docs/API_docs/methods/index.md'), $smatches);
foreach ($smatches[1] as $key => $match) { foreach ($smatches[1] as $key => $match) {
$match = str_replace('href="', 'href="https://docs.madelineproto.xyz/API_docs/methods/', $match); $match = str_replace('href="', 'href="https://docs.madelineproto.xyz/API_docs/methods/', $match);

View File

@ -1,4 +1,5 @@
<?php <?php
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\TL\TL; use danog\MadelineProto\TL\TL;
@ -24,28 +25,31 @@ if ($argc !== 3) {
die("Usage: {$argv[0]} layernumberold layernumbernew\n"); die("Usage: {$argv[0]} layernumberold layernumbernew\n");
} }
/** /**
* Get TL info of layer * Get TL info of layer.
* *
* @param int $layer Layer number * @param int $layer Layer number
*
* @return void * @return void
*/ */
function getTL($layer) function getTL($layer)
{ {
$layer = __DIR__."/src/danog/MadelineProto/TL_telegram_v$layer.tl"; $layer = __DIR__."/src/danog/MadelineProto/TL_telegram_v$layer.tl";
$layer = new class($layer) $layer = new class($layer) {
{
use TL; use TL;
public function __construct($layer) public function __construct($layer)
{ {
$this->logger = Logger::$default; $this->logger = Logger::$default;
$this->construct_TL(['telegram' => $layer]); $this->construct_TL(['telegram' => $layer]);
} }
}; };
return ['methods' => $layer->methods, 'constructors' => $layer->constructors]; return ['methods' => $layer->methods, 'constructors' => $layer->constructors];
} }
function getUrl($constructor, $type) function getUrl($constructor, $type)
{ {
$changed = str_replace('.', '_', $constructor); $changed = str_replace('.', '_', $constructor);
return "[$constructor](https://docs.madelineproto.xyz/API_docs/$type/$changed.html)"; return "[$constructor](https://docs.madelineproto.xyz/API_docs/$type/$changed.html)";
} }
$old = getTL($argv[1]); $old = getTL($argv[1]);
@ -105,7 +109,6 @@ foreach (['methods', 'constructors'] as $type) {
$res .= "Removed $name\n"; $res .= "Removed $name\n";
} }
} }
} }
echo($res); echo $res;

View File

@ -11,10 +11,10 @@ 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. You should have received a copy of the GNU General Public License along with MadelineProto.
If not, see <http://www.gnu.org/licenses/>. If not, see <http://www.gnu.org/licenses/>.
*/ */
set_include_path(get_include_path() . ':' . realpath(dirname(__FILE__) . '/MadelineProto/')); set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/'));
if (!file_exists(__DIR__ . '/vendor/autoload.php')) { if (!file_exists(__DIR__.'/vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php' . PHP_EOL; echo 'You did not run composer update, using madeline.php'.PHP_EOL;
if (!file_exists('madeline.php')) { if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
} }
@ -27,7 +27,7 @@ if (!file_exists('songs.php')) {
copy('https://github.com/danog/MadelineProto/raw/master/songs.php', 'songs.php'); copy('https://github.com/danog/MadelineProto/raw/master/songs.php', 'songs.php');
} }
echo 'Deserializing MadelineProto from session.madeline...' . PHP_EOL; echo 'Deserializing MadelineProto from session.madeline...'.PHP_EOL;
/*if (!isset($MadelineProto->inputEncryptedFilePhoto) && false) { /*if (!isset($MadelineProto->inputEncryptedFilePhoto) && false) {
$MadelineProto->inputEncryptedFilePhoto = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic $MadelineProto->inputEncryptedFilePhoto = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic
@ -46,7 +46,7 @@ class EventHandler extends \danog\MadelineProto\EventHandler
$call->configuration['enable_NS'] = false; $call->configuration['enable_NS'] = false;
$call->configuration['enable_AGC'] = false; $call->configuration['enable_AGC'] = false;
$call->configuration['enable_AEC'] = false; $call->configuration['enable_AEC'] = false;
$call->configuration['log_file_path'] = '/tmp/logs' . $call->getCallID()['id'] . '.log'; // Default is /dev/null $call->configuration['log_file_path'] = '/tmp/logs'.$call->getCallID()['id'].'.log'; // Default is /dev/null
//$call->configuration["stats_dump_file_path"] = "/tmp/stats".$call->getCallID()['id'].".txt"; // Default is /dev/null //$call->configuration["stats_dump_file_path"] = "/tmp/stats".$call->getCallID()['id'].".txt"; // Default is /dev/null
$call->parseConfig(); $call->parseConfig();
$call->playOnHold($songs); $call->playOnHold($songs);
@ -84,7 +84,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
$this->configureCall($call); $this->configureCall($call);
if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
$this->calls[$call->getOtherID()] = $call; $this->calls[$call->getOtherID()] = $call;
$this->times[$call->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $call->getOtherID(), 'message' => 'Total running calls: ' . count($this->calls) . PHP_EOL . PHP_EOL . $call->getDebugString()])['id']]; $this->times[$call->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $call->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL.$call->getDebugString()])['id']];
} }
} }
if (strpos($message, '/program') === 0) { if (strpos($message, '/program') === 0) {
@ -174,7 +174,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
$this->calls[$update['phone_call']->getOtherID()] = $update['phone_call']; $this->calls[$update['phone_call']->getOtherID()] = $update['phone_call'];
try { try {
$this->times[$update['phone_call']->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $update['phone_call']->getOtherID(), 'message' => 'Total running calls: ' . count($this->calls) . PHP_EOL . PHP_EOL])['id']]; $this->times[$update['phone_call']->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $update['phone_call']->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL])['id']];
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
} }
} }
@ -196,7 +196,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
$this->configureCall($call); $this->configureCall($call);
if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
$this->calls[$call->getOtherID()] = $call; $this->calls[$call->getOtherID()] = $call;
$this->times[$call->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $call->getOtherID(), 'message' => 'Total running calls: ' . count($this->calls) . PHP_EOL . PHP_EOL . $call->getDebugString()])['id']]; $this->times[$call->getOtherID()] = [time(), $this->messages->sendMessage(['peer' => $call->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL.$call->getDebugString()])['id']];
} }
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
try { try {
@ -232,7 +232,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
} }
break; break;
} }
\danog\MadelineProto\Logger::log(count($this->calls) . ' calls running!'); \danog\MadelineProto\Logger::log(count($this->calls).' calls running!');
foreach ($this->calls as $key => $call) { foreach ($this->calls as $key => $call) {
if ($call->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { if ($call->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
try { try {
@ -250,12 +250,12 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
]);*/ ]);*/
$this->messages->sendMedia([ $this->messages->sendMedia([
'reply_to_msg_id' => $this->times[$call->getOtherID()][1], 'reply_to_msg_id' => $this->times[$call->getOtherID()][1],
'peer' => $call->getOtherID(), 'message' => 'Debug info by @magnaluna', 'peer' => $call->getOtherID(), 'message' => 'Debug info by @magnaluna',
'media' => [ 'media' => [
'_' => 'inputMediaUploadedDocument', '_' => 'inputMediaUploadedDocument',
'file' => '/tmp/logs' . $call->getCallID()['id'] . '.log', 'file' => '/tmp/logs'.$call->getCallID()['id'].'.log',
'attributes' => [ 'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'logs' . $call->getCallID()['id'] . '.log'], ['_' => 'documentAttributeFilename', 'file_name' => 'logs'.$call->getCallID()['id'].'.log'],
], ],
], ],
]); ]);
@ -267,14 +267,14 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
echo $e; echo $e;
} }
@unlink('/tmp/logs' . $call->getCallID()['id'] . '.log'); @unlink('/tmp/logs'.$call->getCallID()['id'].'.log');
@unlink('/tmp/stats' . $call->getCallID()['id'] . '.txt'); @unlink('/tmp/stats'.$call->getCallID()['id'].'.txt');
unset($this->calls[$key]); unset($this->calls[$key]);
} elseif (isset($this->times[$call->getOtherID()]) && $this->times[$call->getOtherID()][0] < time()) { } elseif (isset($this->times[$call->getOtherID()]) && $this->times[$call->getOtherID()][0] < time()) {
$this->times[$call->getOtherID()][0] += 30 + count($this->calls); $this->times[$call->getOtherID()][0] += 30 + count($this->calls);
try { try {
$this->messages->editMessage(['id' => $this->times[$call->getOtherID()][1], 'peer' => $call->getOtherID(), 'message' => 'Total running calls: ' . count($this->calls) . PHP_EOL . PHP_EOL . $call->getDebugString()]); $this->messages->editMessage(['id' => $this->times[$call->getOtherID()][1], 'peer' => $call->getOtherID(), 'message' => 'Total running calls: '.count($this->calls).PHP_EOL.PHP_EOL.$call->getDebugString()]);
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
echo $e; echo $e;
} }
@ -283,17 +283,19 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
} }
} }
if (!class_exists('\\danog\\MadelineProto\\VoIPServerConfig')) die('Install the libtgvoip extension: https://voip.madelineproto.xyz'.PHP_EOL); if (!class_exists('\\danog\\MadelineProto\\VoIPServerConfig')) {
die('Install the libtgvoip extension: https://voip.madelineproto.xyz'.PHP_EOL);
}
\danog\MadelineProto\VoIPServerConfig::update( \danog\MadelineProto\VoIPServerConfig::update(
[ [
'audio_init_bitrate' => 100 * 1000, 'audio_init_bitrate' => 100 * 1000,
'audio_max_bitrate' => 100 * 1000, 'audio_max_bitrate' => 100 * 1000,
'audio_min_bitrate' => 10 * 1000, 'audio_min_bitrate' => 10 * 1000,
'audio_congestion_window' => 4 * 1024, 'audio_congestion_window' => 4 * 1024,
] ]
); );
$MadelineProto = new \danog\MadelineProto\API('session.madeline', ['secret_chats' => ['accept_chats' => false], 'logger' => ['logger' => 3, 'logger_level' => 5, 'logger_param' => getcwd() . '/MadelineProto.log']]); $MadelineProto = new \danog\MadelineProto\API('session.madeline', ['secret_chats' => ['accept_chats' => false], 'logger' => ['logger' => 3, 'logger_level' => 5, 'logger_param' => getcwd().'/MadelineProto.log']]);
$MadelineProto->start(); $MadelineProto->start();
if (!isset($MadelineProto->programmed_call)) { if (!isset($MadelineProto->programmed_call)) {

View File

@ -5,7 +5,9 @@ if (PHP_MAJOR_VERSION === 5) {
throw new \Exception('MadelineProto requires at least PHP 5.6 to run'); throw new \Exception('MadelineProto requires at least PHP 5.6 to run');
} }
$newline = PHP_EOL; $newline = PHP_EOL;
if (php_sapi_name() !== 'cli') $newline = '<br>'.$newline; if (php_sapi_name() !== 'cli') {
$newline = '<br>'.$newline;
}
echo "**********************************************************************$newline"; echo "**********************************************************************$newline";
echo "**********************************************************************$newline$newline"; echo "**********************************************************************$newline$newline";
echo "YOU ARE USING AN OLD AND BUGGED VERSION OF PHP, PLEASE UPDATE TO PHP 7$newline"; echo "YOU ARE USING AN OLD AND BUGGED VERSION OF PHP, PLEASE UPDATE TO PHP 7$newline";
@ -39,7 +41,6 @@ function ___install_madeline()
$release_template = 'https://phar.madelineproto.xyz/release%s?v=new'; $release_template = 'https://phar.madelineproto.xyz/release%s?v=new';
$phar_template = 'https://phar.madelineproto.xyz/madeline%s.phar?v=new'; $phar_template = 'https://phar.madelineproto.xyz/madeline%s.phar?v=new';
// Version definition // Version definition
$release_branch = defined('MADELINE_BRANCH') ? '-'.MADELINE_BRANCH : '-old'; $release_branch = defined('MADELINE_BRANCH') ? '-'.MADELINE_BRANCH : '-old';
if ($release_branch === '-') { if ($release_branch === '-') {
@ -50,7 +51,7 @@ function ___install_madeline()
if (PHP_MAJOR_VERSION <= 5) { if (PHP_MAJOR_VERSION <= 5) {
$release_branch = '5'.$release_branch; $release_branch = '5'.$release_branch;
$release_default_branch = '5'; $release_default_branch = '5';
} else if (PHP_MINOR_VERSION >= 3) { } elseif (PHP_MINOR_VERSION >= 3) {
$release_branch = ''; $release_branch = '';
} }

View File

@ -15,14 +15,15 @@
* *
* @link https://docs.madelineproto.xyz MadelineProto documentation * @link https://docs.madelineproto.xyz MadelineProto documentation
*/ */
class YieldReturnValue class YieldReturnValue
{ {
private $value; private $value;
public function __construct($value) public function __construct($value)
{ {
$this->value = $value; $this->value = $value;
} }
public function getReturn() public function getReturn()
{ {
return $this->value; return $this->value;

View File

@ -37,13 +37,14 @@ class API extends APIFactory
{ {
Magic::class_exists(); Magic::class_exists();
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
$deferred = new Deferred; $deferred = new Deferred();
$this->asyncAPIPromise = $deferred->promise(); $this->asyncAPIPromise = $deferred->promise();
$this->asyncAPIPromise->onResolve(function () { $this->asyncAPIPromise->onResolve(function () {
$this->asyncAPIPromise = null; $this->asyncAPIPromise = null;
}); });
$this->setInitPromise($this->__construct_async($params, $settings, $deferred)); $this->setInitPromise($this->__construct_async($params, $settings, $deferred));
} }
public function __construct_async($params, $settings, $deferred) public function __construct_async($params, $settings, $deferred)
{ {
if (is_string($params)) { if (is_string($params)) {
@ -184,10 +185,12 @@ class API extends APIFactory
return implode('_', $ret); return implode('_', $ret);
} }
public function my_get_self() public function my_get_self()
{ {
return $this->API->authorization['user']; return $this->API->authorization['user'];
} }
public function APIFactory() public function APIFactory()
{ {
if ($this->API) { if ($this->API) {

View File

@ -19,7 +19,6 @@
namespace danog\MadelineProto; namespace danog\MadelineProto;
use Amp\Promise;
use danog\MadelineProto\Async\AsyncConstruct; use danog\MadelineProto\Async\AsyncConstruct;
class APIFactory extends AsyncConstruct class APIFactory extends AsyncConstruct
@ -156,10 +155,10 @@ class APIFactory extends AsyncConstruct
{ {
if ($this->asyncInitPromise) { if ($this->asyncInitPromise) {
yield $this->initAsync(); yield $this->initAsync();
$this->API->logger->logger("Finished init asynchronously"); $this->API->logger->logger('Finished init asynchronously');
} }
if (Magic::is_fork() && !Magic::$processed_fork) { if (Magic::is_fork() && !Magic::$processed_fork) {
throw new Exception("Forking not supported, use async logic, instead: https://docs.madelineproto.xyz/docs/ASYNC.html"); throw new Exception('Forking not supported, use async logic, instead: https://docs.madelineproto.xyz/docs/ASYNC.html');
} }
if (isset($this->session) && !is_null($this->session) && time() - $this->serialized > $this->API->settings['serialization']['serialization_interval']) { if (isset($this->session) && !is_null($this->session) && time() - $this->serialized > $this->API->settings['serialization']['serialization_interval']) {
Logger::log("Didn't serialize in a while, doing that now..."); Logger::log("Didn't serialize in a while, doing that now...");
@ -172,7 +171,7 @@ class APIFactory extends AsyncConstruct
} }
if ($this->API->asyncInitPromise) { if ($this->API->asyncInitPromise) {
yield $this->API->initAsync(); yield $this->API->initAsync();
$this->API->logger->logger("Finished init asynchronously"); $this->API->logger->logger('Finished init asynchronously');
} }
$lower_name = strtolower($name); $lower_name = strtolower($name);
@ -215,6 +214,7 @@ class APIFactory extends AsyncConstruct
if ($this->API->asyncInitPromise) { if ($this->API->asyncInitPromise) {
$this->API->init(); $this->API->init();
} }
return $this->API->__construct(array_replace_recursive($this->API->settings, $value)); return $this->API->__construct(array_replace_recursive($this->API->settings, $value));
} }
@ -226,6 +226,7 @@ class APIFactory extends AsyncConstruct
if ($this->asyncAPIPromise) { if ($this->asyncAPIPromise) {
$this->wait($this->asyncAPIPromise); $this->wait($this->asyncAPIPromise);
} }
return isset($this->API->storage[$name]); return isset($this->API->storage[$name]);
} }
@ -236,5 +237,4 @@ class APIFactory extends AsyncConstruct
} }
unset($this->API->storage[$name]); unset($this->API->storage[$name]);
} }
} }

View File

@ -29,6 +29,7 @@ class Absolute
if (($file[0] !== '/') && ($file[1] !== ':') && !in_array(substr($file, 0, 4), ['phar', 'http'])) { if (($file[0] !== '/') && ($file[1] !== ':') && !in_array(substr($file, 0, 4), ['phar', 'http'])) {
$file = Magic::getcwd().'/'.$file; $file = Magic::getcwd().'/'.$file;
} }
return $file; return $file;
} }
} }

View File

@ -31,18 +31,21 @@ class AsyncConstruct
{ {
use Tools; use Tools;
public $asyncInitPromise; public $asyncInitPromise;
public function init() public function init()
{ {
if ($this->asyncInitPromise) { if ($this->asyncInitPromise) {
$this->wait($this->asyncInitPromise); $this->wait($this->asyncInitPromise);
} }
} }
public function initAsync() public function initAsync()
{ {
if ($this->asyncInitPromise) { if ($this->asyncInitPromise) {
yield $this->asyncInitPromise; yield $this->asyncInitPromise;
} }
} }
public function setInitPromise($promise) public function setInitPromise($promise)
{ {
$this->asyncInitPromise = $this->call($promise); $this->asyncInitPromise = $this->call($promise);

View File

@ -54,6 +54,7 @@ class AsyncParameters extends Parameters
public function getParameters() public function getParameters()
{ {
$callable = $this->callable; $callable = $this->callable;
return yield $callable(); return yield $callable();
} }
} }

View File

@ -42,7 +42,6 @@ class CombinedAPI
$realpaths = Serialization::realpaths($session); $realpaths = Serialization::realpaths($session);
$this->session = $realpaths['file']; $this->session = $realpaths['file'];
foreach ($paths as $path => $settings) { foreach ($paths as $path => $settings) {
$this->addInstance($path, $settings); $this->addInstance($path, $settings);
} }

View File

@ -18,6 +18,7 @@
namespace danog\MadelineProto; namespace danog\MadelineProto;
use Amp\ByteStream\ClosedException;
use Amp\Deferred; use Amp\Deferred;
use Amp\Promise; use Amp\Promise;
use danog\MadelineProto\Loop\Connection\CheckLoop; use danog\MadelineProto\Loop\Connection\CheckLoop;
@ -28,7 +29,6 @@ use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\MTProtoTools\MsgIdHandler; use danog\MadelineProto\Stream\MTProtoTools\MsgIdHandler;
use danog\MadelineProto\Stream\MTProtoTools\SeqNoHandler; use danog\MadelineProto\Stream\MTProtoTools\SeqNoHandler;
use Amp\ByteStream\ClosedException;
/** /**
* Connection class. * Connection class.
@ -147,7 +147,6 @@ class Connection
$this->checker->resume(); $this->checker->resume();
} }
$this->waiter->start(); $this->waiter->start();
} }
public function sendMessage($message, $flush = true) public function sendMessage($message, $flush = true)
@ -235,6 +234,7 @@ class Connection
if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') { if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
continue; continue;
} }
return true; return true;
} }
} }

View File

@ -90,12 +90,14 @@ final class Coroutine implements Promise
//public function __destruct() { var_dump($this->s); } //public function __destruct() { var_dump($this->s); }
};*/ };*/
$this->generator = $generator; $this->generator = $generator;
try { try {
$yielded = $this->generator->current(); $yielded = $this->generator->current();
while (!$yielded instanceof Promise) { while (!$yielded instanceof Promise) {
if ($yielded instanceof \YieldReturnValue) { if ($yielded instanceof \YieldReturnValue) {
$this->resolve($yielded->getReturn()); $this->resolve($yielded->getReturn());
$this->generator->next(); $this->generator->next();
return; return;
} }
if (!$this->generator->valid()) { if (!$this->generator->valid()) {
@ -145,6 +147,7 @@ final class Coroutine implements Promise
$this->resolve($yielded->getReturn()); $this->resolve($yielded->getReturn());
$this->onResolve = null; $this->onResolve = null;
$this->generator->next(); $this->generator->next();
return; return;
} }

View File

@ -19,9 +19,10 @@
namespace danog\MadelineProto; namespace danog\MadelineProto;
use Amp\CancellationToken; use Amp\Artax\Cookie\ArrayCookieJar;
use Amp\Artax\DefaultClient; use Amp\Artax\DefaultClient;
use Amp\Artax\HttpSocketPool; use Amp\Artax\HttpSocketPool;
use Amp\CancellationToken;
use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientConnectContext;
use danog\MadelineProto\Stream\Common\BufferedRawStream; use danog\MadelineProto\Stream\Common\BufferedRawStream;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
@ -38,7 +39,6 @@ use danog\MadelineProto\Stream\Transport\DefaultStream;
use danog\MadelineProto\Stream\Transport\WssStream; use danog\MadelineProto\Stream\Transport\WssStream;
use danog\MadelineProto\Stream\Transport\WsStream; use danog\MadelineProto\Stream\Transport\WsStream;
use danog\MadelineProto\TL\Conversion\Exception; use danog\MadelineProto\TL\Conversion\Exception;
use Amp\Artax\Cookie\ArrayCookieJar;
/** /**
* Manages datacenters. * Manages datacenters.
@ -74,8 +74,9 @@ class DataCenter
unset($this->sockets[$key]); unset($this->sockets[$key]);
} }
} }
$this->HTTPClient = new DefaultClient(new ArrayCookieJar, new HttpSocketPool(new ProxySocketPool($this))); $this->HTTPClient = new DefaultClient(new ArrayCookieJar(), new HttpSocketPool(new ProxySocketPool($this)));
} }
public function rawConnectAsync(string $uri, CancellationToken $token = null, ClientConnectContext $ctx = null): \Generator public function rawConnectAsync(string $uri, CancellationToken $token = null, ClientConnectContext $ctx = null): \Generator
{ {
$ctxs = $this->generateContexts(0, $uri, $ctx); $ctxs = $this->generateContexts(0, $uri, $ctx);
@ -83,7 +84,7 @@ class DataCenter
throw new Exception("No contexts for raw connection to URI $uri"); throw new Exception("No contexts for raw connection to URI $uri");
} }
foreach ($ctxs as $ctx) { foreach ($ctxs as $ctx) {
/** @var $ctx \danog\MadelineProto\Stream\ConnectionContext */ /* @var $ctx \danog\MadelineProto\Stream\ConnectionContext */
try { try {
$ctx->setCancellationToken($token); $ctx->setCancellationToken($token);
$result = yield $ctx->getStream(); $result = yield $ctx->getStream();
@ -364,15 +365,15 @@ class DataCenter
unset($this->sockets[$dc_number]); unset($this->sockets[$dc_number]);
$this->API->logger->logger("No info for DC $dc_number", \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger("No info for DC $dc_number", \danog\MadelineProto\Logger::ERROR);
} elseif (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') {
} else if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') {
return [$ctxs[0]]; return [$ctxs[0]];
} }
return $ctxs; return $ctxs;
} }
/** /**
* Get Artax async HTTP client * Get Artax async HTTP client.
* *
* @return \Amp\Artax\DefaultClient * @return \Amp\Artax\DefaultClient
*/ */
@ -380,10 +381,12 @@ class DataCenter
{ {
return $this->HTTPClient; return $this->HTTPClient;
} }
public function fileGetContents($url): \Generator public function fileGetContents($url): \Generator
{ {
return yield (yield $this->getHTTPClient()->request($url))->getBody(); return yield (yield $this->getHTTPClient()->request($url))->getBody();
} }
public function get_dcs($all = true) public function get_dcs($all = true)
{ {
$test = $this->settings['all']['test_mode'] ? 'test' : 'main'; $test = $this->settings['all']['test_mode'] ? 'test' : 'main';

View File

@ -38,6 +38,7 @@ class FileCallback implements FileCallbackInterface
public function __invoke($percent) public function __invoke($percent)
{ {
$callback = $this->callback; $callback = $this->callback;
return $callback($percent); return $callback($percent);
} }
} }

View File

@ -24,8 +24,8 @@ namespace danog\MadelineProto;
use Amp\ByteStream\ResourceOutputStream; use Amp\ByteStream\ResourceOutputStream;
use Amp\Failure; use Amp\Failure;
use function \Amp\ByteStream\getStdout; use function Amp\ByteStream\getStderr;
use function \Amp\ByteStream\getStderr; use function Amp\ByteStream\getStdout;
class Logger class Logger
{ {
@ -100,7 +100,9 @@ class Logger
if ($this->mode === 3) { if ($this->mode === 3) {
$this->stdout = getStdout(); $this->stdout = getStdout();
if (php_sapi_name() !== 'cli') $this->newline = '<br>'.$this->newline; if (php_sapi_name() !== 'cli') {
$this->newline = '<br>'.$this->newline;
}
} elseif ($this->mode === 2) { } elseif ($this->mode === 2) {
$this->stdout = new ResourceOutputStream(fopen($this->optional, 'a+')); $this->stdout = new ResourceOutputStream(fopen($this->optional, 'a+'));
} elseif ($this->mode === 1) { } elseif ($this->mode === 1) {
@ -147,7 +149,7 @@ class Logger
} }
if ($param instanceof \Throwable) { if ($param instanceof \Throwable) {
$param = (string) $param; $param = (string) $param;
} else if (!is_string($param)) { } elseif (!is_string($param)) {
$param = json_encode($param, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); $param = json_encode($param, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
} }
if ($file === null) { if ($file === null) {
@ -171,6 +173,7 @@ class Logger
break; break;
} }
} }
public function __destruct() public function __destruct()
{ {
//$this->wait($this->stdout->write('')); //$this->wait($this->stdout->write(''));

View File

@ -19,7 +19,6 @@
namespace danog\MadelineProto\Loop\Connection; namespace danog\MadelineProto\Loop\Connection;
use Amp\Deferred; use Amp\Deferred;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
/** /**
@ -66,6 +65,7 @@ class CheckLoop extends ResumableSignalLoop
if ($e) { if ($e) {
$API->logger("Got exception in check loop for DC $datacenter"); $API->logger("Got exception in check loop for DC $datacenter");
$API->logger((string) $e); $API->logger((string) $e);
return; return;
} }
$reply = []; $reply = [];

View File

@ -18,8 +18,6 @@
namespace danog\MadelineProto\Loop\Connection; namespace danog\MadelineProto\Loop\Connection;
use Amp\Success;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream;
use danog\MadelineProto\Stream\MTProtoTransport\HttpStream; use danog\MadelineProto\Stream\MTProtoTransport\HttpStream;
@ -40,6 +38,7 @@ class HttpWaitLoop extends ResumableSignalLoop
$this->datacenter = $datacenter; $this->datacenter = $datacenter;
$this->connection = $API->datacenter->sockets[$datacenter]; $this->connection = $API->datacenter->sockets[$datacenter];
} }
public function loop() public function loop()
{ {
$API = $this->API; $API = $this->API;
@ -68,7 +67,6 @@ class HttpWaitLoop extends ResumableSignalLoop
yield $connection->sendMessage(['_' => 'http_wait', 'body' => ['max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'content_related' => true, 'unencrypted' => false, 'method' => false]); yield $connection->sendMessage(['_' => 'http_wait', 'body' => ['max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 0], 'content_related' => true, 'unencrypted' => false, 'method' => false]);
} }
$API->logger->logger("DC $datacenter: request {$connection->http_req_count}, response {$connection->http_res_count}"); $API->logger->logger("DC $datacenter: request {$connection->http_req_count}, response {$connection->http_res_count}");
} }
} }

View File

@ -45,6 +45,7 @@ class ReadLoop extends SignalLoop
$this->datacenter = $datacenter; $this->datacenter = $datacenter;
$this->connection = $API->datacenter->sockets[$datacenter]; $this->connection = $API->datacenter->sockets[$datacenter];
} }
public function loop() public function loop()
{ {
$API = $this->API; $API = $this->API;
@ -92,6 +93,7 @@ class ReadLoop extends SignalLoop
$API->logger->logger("Got NOOP from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING); $API->logger->logger("Got NOOP from DC {$datacenter}", \danog\MadelineProto\Logger::WARNING);
} else { } else {
yield $connection->reconnect(); yield $connection->reconnect();
throw new \danog\MadelineProto\RPCErrorException($error, $error); throw new \danog\MadelineProto\RPCErrorException($error, $error);
} }
@ -114,7 +116,8 @@ class ReadLoop extends SignalLoop
$datacenter = $this->datacenter; $datacenter = $this->datacenter;
$connection = $this->connection; $connection = $this->connection;
if (isset($this->connection->old)) { if (isset($this->connection->old)) {
$API->logger->logger("Not reading because connection is old"); $API->logger->logger('Not reading because connection is old');
throw new NothingInTheSocketException(); throw new NothingInTheSocketException();
} }
@ -203,6 +206,7 @@ class ReadLoop extends SignalLoop
$connection->incoming_messages[$message_id] = ['seq_no' => $seq_no]; $connection->incoming_messages[$message_id] = ['seq_no' => $seq_no];
} else { } else {
$API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Got unknown auth_key id', \danog\MadelineProto\Logger::ERROR);
return -404; return -404;
} }
$deserialized = $API->deserialize($message_data, ['type' => '', 'datacenter' => $datacenter]); $deserialized = $API->deserialize($message_data, ['type' => '', 'datacenter' => $datacenter]);

View File

@ -197,15 +197,15 @@ class WriteLoop extends ResumableSignalLoop
'query' => yield $API->serialize_method_async( 'query' => yield $API->serialize_method_async(
'initConnection', 'initConnection',
[ [
'api_id' => $API->settings['app_info']['api_id'], 'api_id' => $API->settings['app_info']['api_id'],
'api_hash' => $API->settings['app_info']['api_hash'], 'api_hash' => $API->settings['app_info']['api_hash'],
'device_model' => strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['device_model'] : 'n/a', 'device_model' => strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['device_model'] : 'n/a',
'system_version' => strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['system_version'] : 'n/a', 'system_version' => strpos($datacenter, 'cdn') === false ? $API->settings['app_info']['system_version'] : 'n/a',
'app_version' => $API->settings['app_info']['app_version'], 'app_version' => $API->settings['app_info']['app_version'],
'system_lang_code' => $API->settings['app_info']['lang_code'], 'system_lang_code' => $API->settings['app_info']['lang_code'],
'lang_code' => $API->settings['app_info']['lang_code'], 'lang_code' => $API->settings['app_info']['lang_code'],
'lang_pack' => $API->settings['app_info']['lang_pack'], 'lang_pack' => $API->settings['app_info']['lang_pack'],
'query' => $MTmessage['body'], 'query' => $MTmessage['body'],
] ]
), ),
] ]
@ -331,6 +331,7 @@ class WriteLoop extends ResumableSignalLoop
} while (!empty($connection->pending_outgoing) && !$skipped); } while (!empty($connection->pending_outgoing) && !$skipped);
$connection->pending_outgoing_key = 0; $connection->pending_outgoing_key = 0;
return $skipped; return $skipped;
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Generic loop * Generic loop.
* *
* This file is part of MadelineProto. * 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 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.
@ -35,7 +35,7 @@ class GenericLoop extends ResumableSignalLoop
protected $name; protected $name;
/** /**
* Constructor * Constructor.
* *
* The callback will be bound to the GenericLoop instance: this means that you will be able to use `$this` as if the callback were actually the `loop` function (you can access the API property, use the pause/waitSignal methods & so on). * The callback will be bound to the GenericLoop instance: this means that you will be able to use `$this` as if the callback were actually the `loop` function (you can access the API property, use the pause/waitSignal methods & so on).
* The return value of the callable can be: * The return value of the callable can be:
@ -43,10 +43,10 @@ class GenericLoop extends ResumableSignalLoop
* GenericLoop::STOP - The loop will stop * GenericLoop::STOP - The loop will stop
* GenericLoop::PAUSE - The loop will pause forever (or until the `resume` method is called on the loop object from outside the loop) * GenericLoop::PAUSE - The loop will pause forever (or until the `resume` method is called on the loop object from outside the loop)
* GenericLoop::CONTINUE - Return this if you want to rerun the loop without waiting * GenericLoop::CONTINUE - Return this if you want to rerun the loop without waiting
* *
* @param \danog\MadelineProto\API $API Instance of MadelineProto * @param \danog\MadelineProto\API $API Instance of MadelineProto
* @param callback $callback Callback to run * @param callable $callback Callback to run
* @param string $name Fetcher name * @param string $name Fetcher name
*/ */
public function __construct($API, $callback, $name) public function __construct($API, $callback, $name)
{ {
@ -54,6 +54,7 @@ class GenericLoop extends ResumableSignalLoop
$this->callback = $callback->bindTo($this); $this->callback = $callback->bindTo($this);
$this->name = $name; $this->name = $name;
} }
public function loop() public function loop()
{ {
$callback = $this->callback; $callback = $this->callback;
@ -62,7 +63,7 @@ class GenericLoop extends ResumableSignalLoop
$timeout = yield $callback(); $timeout = yield $callback();
if ($timeout === self::PAUSE) { if ($timeout === self::PAUSE) {
$this->API->logger->logger("Pausing $this", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger("Pausing $this", \danog\MadelineProto\Logger::VERBOSE);
} else if ($timeout > 0) { } elseif ($timeout > 0) {
$this->API->logger->logger("Pausing $this for $timeout", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger("Pausing $this for $timeout", \danog\MadelineProto\Logger::VERBOSE);
} }
if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) { if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) {

View File

@ -36,6 +36,7 @@ abstract class Loop implements LoopInterface
private $count = 0; private $count = 0;
public $API; public $API;
public function __construct($API) public function __construct($API)
{ {
$this->API = $API; $this->API = $API;
@ -48,6 +49,7 @@ abstract class Loop implements LoopInterface
return false; return false;
} }
return $this->callFork($this->loopImpl()); return $this->callFork($this->loopImpl());
} }
@ -56,6 +58,7 @@ abstract class Loop implements LoopInterface
//yield ['my_trace' => debug_backtrace(0, 1)[0], (string) $this]; //yield ['my_trace' => debug_backtrace(0, 1)[0], (string) $this];
$this->startedLoop(); $this->startedLoop();
$this->API->logger->logger("Entered $this", Logger::ULTRA_VERBOSE); $this->API->logger->logger("Entered $this", Logger::ULTRA_VERBOSE);
try { try {
yield $this->loop(); yield $this->loop();
} finally { } finally {
@ -81,5 +84,4 @@ abstract class Loop implements LoopInterface
{ {
return $this->count; return $this->count;
} }
} }

View File

@ -54,8 +54,10 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn
$this->resume = new Deferred(); $this->resume = new Deferred();
$pause = $this->pause; $pause = $this->pause;
$this->pause = new Deferred; $this->pause = new Deferred();
if ($pause) Loop::defer([$pause, 'resolve']); if ($pause) {
Loop::defer([$pause, 'resolve']);
}
return $this->resume->promise(); return $this->resume->promise();
} }
@ -82,6 +84,7 @@ abstract class ResumableSignalLoop extends SignalLoop implements ResumableLoopIn
public function resumeDefer() public function resumeDefer()
{ {
Loop::defer([$this, 'resume']); Loop::defer([$this, 'resume']);
return $this->pause ? $this->pause->promise() : null; return $this->pause ? $this->pause->promise() : null;
} }
} }

View File

@ -20,8 +20,8 @@ namespace danog\MadelineProto\Loop\Impl;
use Amp\Deferred; use Amp\Deferred;
use Amp\Promise; use Amp\Promise;
use danog\MadelineProto\Loop\SignalLoopInterface;
use danog\MadelineProto\Coroutine; use danog\MadelineProto\Coroutine;
use danog\MadelineProto\Loop\SignalLoopInterface;
/** /**
* Signal loop helper trait. * Signal loop helper trait.

View File

@ -40,7 +40,7 @@ interface LoopInterface
public function loop(); public function loop();
/** /**
* Get name of the loop * Get name of the loop.
* *
* @return string * @return string
*/ */

View File

@ -19,8 +19,6 @@
namespace danog\MadelineProto\Loop\Update; namespace danog\MadelineProto\Loop\Update;
use Amp\Loop; use Amp\Loop;
use Amp\Success;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
/** /**
@ -41,6 +39,7 @@ class FeedLoop extends ResumableSignalLoop
$this->API = $API; $this->API = $API;
$this->channelId = $channelId; $this->channelId = $channelId;
} }
public function loop() public function loop()
{ {
$API = $this->API; $API = $this->API;
@ -83,9 +82,9 @@ class FeedLoop extends ResumableSignalLoop
$this->parsedUpdates = []; $this->parsedUpdates = [];
$this->API->signalUpdate(); $this->API->signalUpdate();
} }
} }
} }
public function parse($updates) public function parse($updates)
{ {
reset($updates); reset($updates);
@ -110,12 +109,12 @@ class FeedLoop extends ResumableSignalLoop
}; };
$result = $this->state->checkPts($update); $result = $this->state->checkPts($update);
if ($result < 0) { if ($result < 0) {
$logger("PTS duplicate"); $logger('PTS duplicate');
continue; continue;
} }
if ($result > 0) { if ($result > 0) {
$logger("PTS hole"); $logger('PTS hole');
$this->updater->setLimit($this->state->pts() + $result); $this->updater->setLimit($this->state->pts() + $result);
yield $this->updater->resume(); yield $this->updater->resume();
$updates = array_merge($this->incomingUpdates, $updates); $updates = array_merge($this->incomingUpdates, $updates);
@ -124,20 +123,20 @@ class FeedLoop extends ResumableSignalLoop
} }
if (isset($update['message']['id'], $update['message']['to_id']) && !in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage'])) { if (isset($update['message']['id'], $update['message']['to_id']) && !in_array($update['_'], ['updateEditMessage', 'updateEditChannelMessage'])) {
if (!$this->API->check_msg_id($update['message'])) { if (!$this->API->check_msg_id($update['message'])) {
$logger("MSGID duplicate"); $logger('MSGID duplicate');
continue; continue;
} }
} }
$logger("PTS OK"); $logger('PTS OK');
$this->state->pts($update['pts']); $this->state->pts($update['pts']);
} }
$this->save($update); $this->save($update);
} }
} }
public function feed($updates) public function feed($updates)
{ {
$result = []; $result = [];
@ -148,8 +147,10 @@ class FeedLoop extends ResumableSignalLoop
} }
$result[$res] = true; $result[$res] = true;
} }
return $result; return $result;
} }
public function feedSingle($update) public function feedSingle($update)
{ {
$channelId = false; $channelId = false;
@ -173,7 +174,7 @@ class FeedLoop extends ResumableSignalLoop
if ($channelId && !$this->API->getChannelStates()->has($channelId)) { if ($channelId && !$this->API->getChannelStates()->has($channelId)) {
$this->API->loadChannelState($channelId, $update); $this->API->loadChannelState($channelId, $update);
if (!isset($this->API->feeders[$channelId])) { if (!isset($this->API->feeders[$channelId])) {
$this->API->feeders[$channelId] = new FeedLoop($this->API, $channelId); $this->API->feeders[$channelId] = new self($this->API, $channelId);
} }
if (!isset($this->API->updaters[$channelId])) { if (!isset($this->API->updaters[$channelId])) {
$this->API->updaters[$channelId] = new UpdateLoop($this->API, $channelId); $this->API->updaters[$channelId] = new UpdateLoop($this->API, $channelId);
@ -204,7 +205,7 @@ class FeedLoop extends ResumableSignalLoop
} }
if ($to) { if ($to) {
$log .= "to_id ".json_encode($update['message']['to_id']).", "; $log .= 'to_id '.json_encode($update['message']['to_id']).', ';
} }
if ($via_bot) { if ($via_bot) {
@ -212,7 +213,7 @@ class FeedLoop extends ResumableSignalLoop
} }
if ($entities) { if ($entities) {
$log .= "entities ".json_encode($update['message']['entities']).", "; $log .= 'entities '.json_encode($update['message']['entities']).', ';
} }
$this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger("Not enough data: for message update $log, getting difference...", \danog\MadelineProto\Logger::VERBOSE);
@ -233,12 +234,15 @@ class FeedLoop extends ResumableSignalLoop
$this->API->logger->logger('Was fed an update of type '.$update['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger('Was fed an update of type '.$update['_']." in $this...", \danog\MadelineProto\Logger::VERBOSE);
$this->incomingUpdates[] = $update; $this->incomingUpdates[] = $update;
return $this->channelId; return $this->channelId;
} }
public function save($update) public function save($update)
{ {
$this->parsedUpdates[] = $update; $this->parsedUpdates[] = $update;
} }
public function saveMessages($messages) public function saveMessages($messages)
{ {
foreach ($messages as $message) { foreach ($messages as $message) {
@ -270,6 +274,6 @@ class FeedLoop extends ResumableSignalLoop
public function __toString(): string public function __toString(): string
{ {
return !$this->channelId ? "update feed loop generic" : "update feed loop channel {$this->channelId}"; return !$this->channelId ? 'update feed loop generic' : "update feed loop channel {$this->channelId}";
} }
} }

View File

@ -18,8 +18,6 @@
namespace danog\MadelineProto\Loop\Update; namespace danog\MadelineProto\Loop\Update;
use Amp\Success;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
/** /**
@ -38,6 +36,7 @@ class SeqLoop extends ResumableSignalLoop
{ {
$this->API = $API; $this->API = $API;
} }
public function loop() public function loop()
{ {
$API = $this->API; $API = $this->API;
@ -80,6 +79,7 @@ class SeqLoop extends ResumableSignalLoop
} }
} }
} }
public function parse($updates) public function parse($updates)
{ {
reset($updates); reset($updates);
@ -88,8 +88,7 @@ class SeqLoop extends ResumableSignalLoop
$key = key($updates); $key = key($updates);
$update = $updates[$key]; $update = $updates[$key];
unset($updates[$key]); unset($updates[$key]);
$options = $update['options']; $options = $update['options'];
$seq_start = $options['seq_start']; $seq_start = $options['seq_start'];
$seq_end = $options['seq_end']; $seq_end = $options['seq_end'];
@ -117,20 +116,24 @@ class SeqLoop extends ResumableSignalLoop
yield $this->save($update); yield $this->save($update);
} }
} }
public function feed($updates) public function feed($updates)
{ {
$this->API->logger->logger('Was fed updates of type '.$updates['_'].'...', \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger('Was fed updates of type '.$updates['_'].'...', \danog\MadelineProto\Logger::VERBOSE);
$this->incomingUpdates[] = $updates; $this->incomingUpdates[] = $updates;
} }
public function save($updates) public function save($updates)
{ {
$this->pendingWakeups += yield $this->feeder->feed($updates['updates']); $this->pendingWakeups += yield $this->feeder->feed($updates['updates']);
} }
public function addPendingWakeups($wakeups) public function addPendingWakeups($wakeups)
{ {
$this->pendingWakeups += $wakeups; $this->pendingWakeups += $wakeups;
} }
public function has_all_auth() public function has_all_auth()
{ {
if ($this->API->isInitingAuthorization()) { if ($this->API->isInitingAuthorization()) {
@ -148,6 +151,6 @@ class SeqLoop extends ResumableSignalLoop
public function __toString(): string public function __toString(): string
{ {
return "update seq loop"; return 'update seq loop';
} }
} }

View File

@ -18,9 +18,8 @@
namespace danog\MadelineProto\Loop\Update; namespace danog\MadelineProto\Loop\Update;
use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
use Amp\Loop; use Amp\Loop;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
use danog\MadelineProto\RPCErrorException; use danog\MadelineProto\RPCErrorException;
/** /**
@ -41,6 +40,7 @@ class UpdateLoop extends ResumableSignalLoop
$this->API = $API; $this->API = $API;
$this->channelId = $channelId; $this->channelId = $channelId;
} }
public function loop() public function loop()
{ {
$API = $this->API; $API = $this->API;
@ -49,17 +49,18 @@ class UpdateLoop extends ResumableSignalLoop
while (!$this->API->settings['updates']['handle_updates'] || !$this->has_all_auth()) { while (!$this->API->settings['updates']['handle_updates'] || !$this->has_all_auth()) {
if (yield $this->waitSignal($this->pause())) { if (yield $this->waitSignal($this->pause())) {
$API->logger->logger("Exiting $this due to signal"); $API->logger->logger("Exiting $this due to signal");
return; return;
} }
} }
$this->state = $state = $this->channelId === false ? (yield $API->load_update_state_async()) : $API->loadChannelState($this->channelId); $this->state = $state = $this->channelId === false ? (yield $API->load_update_state_async()) : $API->loadChannelState($this->channelId);
$timeout = $API->settings['updates']['getdifference_interval']; $timeout = $API->settings['updates']['getdifference_interval'];
while (true) { while (true) {
while (!$this->API->settings['updates']['handle_updates'] || !$this->has_all_auth()) { while (!$this->API->settings['updates']['handle_updates'] || !$this->has_all_auth()) {
if (yield $this->waitSignal($this->pause())) { if (yield $this->waitSignal($this->pause())) {
$API->logger->logger("Exiting $this due to signal"); $API->logger->logger("Exiting $this due to signal");
return; return;
} }
} }
@ -71,21 +72,24 @@ class UpdateLoop extends ResumableSignalLoop
$this->API->logger->logger('Resumed and fetching '.$this->channelId.' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger('Resumed and fetching '.$this->channelId.' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
if ($state->pts() <= 1) { if ($state->pts() <= 1) {
$limit = 10; $limit = 10;
} else if ($API->authorization['user']['bot']) { } elseif ($API->authorization['user']['bot']) {
$limit = 100000; $limit = 100000;
} else { } else {
$limit = 100; $limit = 100;
} }
$request_pts = $state->pts(); $request_pts = $state->pts();
try { try {
$difference = yield $this->API->method_call_async_read('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $this->API->datacenter->curdc]); $difference = yield $this->API->method_call_async_read('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $this->API->datacenter->curdc]);
} catch (RPCErrorException $e) { } catch (RPCErrorException $e) {
if (in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN'])) { if (in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN'])) {
$feeder->signal(true); $feeder->signal(true);
$API->logger->logger("Channel private, exiting $this"); $API->logger->logger("Channel private, exiting $this");
return true; return true;
} }
throw $e;
throw $e;
} }
if (isset($difference['timeout'])) { if (isset($difference['timeout'])) {
$timeout = $difference['timeout']; $timeout = $difference['timeout'];
@ -99,7 +103,7 @@ class UpdateLoop extends ResumableSignalLoop
break 2; break 2;
case 'updates.channelDifference': case 'updates.channelDifference':
if ($request_pts >= $difference['pts'] && $request_pts > 1) { if ($request_pts >= $difference['pts'] && $request_pts > 1) {
$this->API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested ".$state->pts().", using ".($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested ".$state->pts().', using '.($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE);
$difference['pts'] = $request_pts + 1; $difference['pts'] = $request_pts + 1;
} }
$state->update($difference); $state->update($difference);
@ -175,14 +179,17 @@ class UpdateLoop extends ResumableSignalLoop
if (yield $this->waitSignal($this->pause($timeout))) { if (yield $this->waitSignal($this->pause($timeout))) {
$API->logger->logger("Exiting $this due to signal"); $API->logger->logger("Exiting $this due to signal");
return; return;
} }
} }
} }
public function setLimit($toPts) public function setLimit($toPts)
{ {
$this->toPts = $toPts; $this->toPts = $toPts;
} }
public function has_all_auth() public function has_all_auth()
{ {
if ($this->API->isInitingAuthorization()) { if ($this->API->isInitingAuthorization()) {
@ -200,6 +207,6 @@ class UpdateLoop extends ResumableSignalLoop
public function __toString(): string public function __toString(): string
{ {
return !$this->channelId ? "getUpdate loop generic" : "getUpdate loop channel {$this->channelId}"; return !$this->channelId ? 'getUpdate loop generic' : "getUpdate loop channel {$this->channelId}";
} }
} }

View File

@ -228,10 +228,12 @@ class MTProto extends AsyncConstruct implements TLCallback
{ {
return ['supportUser', 'referenceDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'dh_config', 'chats', 'last_stored', 'qres', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos']; return ['supportUser', 'referenceDatabase', 'channel_participants', 'event_handler', 'event_handler_instance', 'loop_callback', 'web_template', 'encrypted_layer', 'settings', 'config', 'authorization', 'authorized', 'rsa_keys', 'dh_config', 'chats', 'last_stored', 'qres', 'got_state', 'channels_state', 'updates', 'updates_key', 'full_chats', 'msg_ids', 'dialog_params', 'datacenter', 'v', 'constructors', 'td_constructors', 'methods', 'td_methods', 'td_descriptions', 'tl_callbacks', 'temp_requested_secret_chats', 'temp_rekeyed_secret_chats', 'secret_chats', 'hook_url', 'storage', 'authorized_dc', 'tos'];
} }
public function logger(...$params) public function logger(...$params)
{ {
return $this->logger->logger(...$params); return $this->logger->logger(...$params);
} }
public function isAltervista() public function isAltervista()
{ {
return Magic::$altervista; return Magic::$altervista;
@ -246,12 +248,14 @@ class MTProto extends AsyncConstruct implements TLCallback
{ {
return $this->datacenter->getHTTPClient(); return $this->datacenter->getHTTPClient();
} }
public function __wakeup() public function __wakeup()
{ {
$backtrace = debug_backtrace(0, 3); $backtrace = debug_backtrace(0, 3);
$this->asyncInitPromise = true; $this->asyncInitPromise = true;
$this->setInitPromise($this->__wakeup_async($backtrace)); $this->setInitPromise($this->__wakeup_async($backtrace));
} }
public function __wakeup_async($backtrace) public function __wakeup_async($backtrace)
{ {
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']); set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
@ -356,7 +360,6 @@ class MTProto extends AsyncConstruct implements TLCallback
if (isset($full['full'], $full['last_update'])) { if (isset($full['full'], $full['last_update'])) {
$this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']]; $this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']];
} }
} }
foreach ($this->secret_chats as $key => &$chat) { foreach ($this->secret_chats as $key => &$chat) {
if (!is_array($chat)) { if (!is_array($chat)) {
@ -592,9 +595,9 @@ class MTProto extends AsyncConstruct implements TLCallback
2 => [ 2 => [
// The rest will be fetched using help.getConfig // The rest will be fetched using help.getConfig
'ip_address' => '149.154.167.40', 'ip_address' => '149.154.167.40',
'port' => 443, 'port' => 443,
'media_only' => false, 'media_only' => false,
'tcpo_only' => false, 'tcpo_only' => false,
], ],
], ],
'ipv6' => [ 'ipv6' => [
@ -602,9 +605,9 @@ class MTProto extends AsyncConstruct implements TLCallback
2 => [ 2 => [
// The rest will be fetched using help.getConfig // The rest will be fetched using help.getConfig
'ip_address' => '2001:067c:04e8:f002:0000:0000:0000:000e', 'ip_address' => '2001:067c:04e8:f002:0000:0000:0000:000e',
'port' => 443, 'port' => 443,
'media_only' => false, 'media_only' => false,
'tcpo_only' => false, 'tcpo_only' => false,
], ],
], ],
], ],
@ -615,9 +618,9 @@ class MTProto extends AsyncConstruct implements TLCallback
2 => [ 2 => [
// The rest will be fetched using help.getConfig // The rest will be fetched using help.getConfig
'ip_address' => '149.154.167.51', 'ip_address' => '149.154.167.51',
'port' => 443, 'port' => 443,
'media_only' => false, 'media_only' => false,
'tcpo_only' => false, 'tcpo_only' => false,
], ],
], ],
'ipv6' => [ 'ipv6' => [
@ -625,9 +628,9 @@ class MTProto extends AsyncConstruct implements TLCallback
2 => [ 2 => [
// The rest will be fetched using help.getConfig // The rest will be fetched using help.getConfig
'ip_address' => '2001:067c:04e8:f002:0000:0000:0000:000a', 'ip_address' => '2001:067c:04e8:f002:0000:0000:0000:000a',
'port' => 443, 'port' => 443,
'media_only' => false, 'media_only' => false,
'tcpo_only' => false, 'tcpo_only' => false,
], ],
], ],
], ],
@ -648,17 +651,17 @@ class MTProto extends AsyncConstruct implements TLCallback
'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [], 'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [],
// Extra parameters to pass to the proxy class using setExtra // Extra parameters to pass to the proxy class using setExtra
'obfuscated' => false, 'obfuscated' => false,
'transport' => 'tcp', 'transport' => 'tcp',
'pfs' => extension_loaded('gmp'), 'pfs' => extension_loaded('gmp'),
], ],
'default_dc' => 2, 'default_dc' => 2,
], 'app_info' => [ ], 'app_info' => [
// obtained in https://my.telegram.org // obtained in https://my.telegram.org
//'api_id' => you should put an API id in the settings array you provide //'api_id' => you should put an API id in the settings array you provide
//'api_hash' => you should put an API hash in the settings array you provide //'api_hash' => you should put an API hash in the settings array you provide
'device_model' => $device_model, 'device_model' => $device_model,
'system_version' => $system_version, 'system_version' => $system_version,
'app_version' => $app_version, 'app_version' => $app_version,
// 🌚 // 🌚
// 'app_version' => self::V, // 'app_version' => self::V,
'lang_code' => $lang_code, 'lang_code' => $lang_code,
@ -692,10 +695,10 @@ class MTProto extends AsyncConstruct implements TLCallback
*/ */
// write to // write to
'logger_param' => Magic::$script_cwd.'/MadelineProto.log', 'logger_param' => Magic::$script_cwd.'/MadelineProto.log',
'logger' => php_sapi_name() === 'cli' ? 3 : 2, 'logger' => php_sapi_name() === 'cli' ? 3 : 2,
// overwrite previous setting and echo logs // overwrite previous setting and echo logs
'logger_level' => Logger::VERBOSE, 'logger_level' => Logger::VERBOSE,
'max_size' => 100 * 1024 * 1024, 'max_size' => 100 * 1024 * 1024,
// Logging level, available logging levels are: ULTRA_VERBOSE, VERBOSE, NOTICE, WARNING, ERROR, FATAL_ERROR. Can be provided as last parameter to the logging function. // Logging level, available logging levels are: ULTRA_VERBOSE, VERBOSE, NOTICE, WARNING, ERROR, FATAL_ERROR. Can be provided as last parameter to the logging function.
'rollbar_token' => '', 'rollbar_token' => '',
], 'max_tries' => [ ], 'max_tries' => [
@ -706,8 +709,8 @@ class MTProto extends AsyncConstruct implements TLCallback
'response' => 5, 'response' => 5,
], 'flood_timeout' => ['wait_if_lt' => 20], 'msg_array_limit' => [ ], 'flood_timeout' => ['wait_if_lt' => 20], 'msg_array_limit' => [
// How big should be the arrays containing the incoming and outgoing messages? // How big should be the arrays containing the incoming and outgoing messages?
'incoming' => 100, 'incoming' => 100,
'outgoing' => 100, 'outgoing' => 100,
'call_queue' => 200, 'call_queue' => 200,
], 'peer' => [ ], 'peer' => [
'full_info_cache_time' => 3600, 'full_info_cache_time' => 3600,
@ -731,10 +734,10 @@ class MTProto extends AsyncConstruct implements TLCallback
'handler_workers' => 10, 'handler_workers' => 10,
], 'upload' => [ ], 'upload' => [
'allow_automatic_upload' => true, 'allow_automatic_upload' => true,
'part_size' => 512 * 1024, 'part_size' => 512 * 1024,
], 'download' => [ ], 'download' => [
'report_broken_media' => true, 'report_broken_media' => true,
'part_size' => 1024 * 1024, 'part_size' => 1024 * 1024,
], 'pwr' => [ ], 'pwr' => [
'pwr' => false, 'pwr' => false,
// Need info ? // Need info ?
@ -794,7 +797,7 @@ class MTProto extends AsyncConstruct implements TLCallback
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
if (isset($this->settings['logger']['logger_param']) && basename($this->settings['logger']['logger_param']) === 'MadelineProto.log') { if (isset($this->settings['logger']['logger_param']) && basename($this->settings['logger']['logger_param']) === 'MadelineProto.log') {
$this->settings['logger']['logger_param'] = Magic::$script_cwd."/MadelineProto.log"; $this->settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
} }
} }
@ -806,11 +809,11 @@ class MTProto extends AsyncConstruct implements TLCallback
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
try { try {
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set("log_errors", 1); ini_set('log_errors', 1);
ini_set("error_log", Magic::$script_cwd."/MadelineProto.log"); ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
error_log('Enabled PHP logging'); error_log('Enabled PHP logging');
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
$this->logger->logger("Could not enable PHP logging"); $this->logger->logger('Could not enable PHP logging');
} }
} }
} }
@ -886,6 +889,7 @@ class MTProto extends AsyncConstruct implements TLCallback
yield $this->get_phone_config_async(); yield $this->get_phone_config_async();
} }
public function resetUpdateSystem() public function resetUpdateSystem()
{ {
foreach ($this->channels_state->get() as $state) { foreach ($this->channels_state->get() as $state) {
@ -894,6 +898,7 @@ class MTProto extends AsyncConstruct implements TLCallback
} }
$this->startUpdateSystem(); $this->startUpdateSystem();
} }
public function startUpdateSystem() public function startUpdateSystem()
{ {
if ($this->asyncInitPromise) { if ($this->asyncInitPromise) {
@ -922,13 +927,14 @@ class MTProto extends AsyncConstruct implements TLCallback
$this->seqUpdater->resume(); $this->seqUpdater->resume();
} }
} }
public function get_phone_config_async($watcherId = null) public function get_phone_config_async($watcherId = null)
{ {
if ($this->authorized === self::LOGGED_IN && class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal') && !$this->authorization['user']['bot'] && $this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->temp_auth_key !== null) { if ($this->authorized === self::LOGGED_IN && class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal') && !$this->authorization['user']['bot'] && $this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->temp_auth_key !== null) {
$this->logger->logger("Fetching phone config..."); $this->logger->logger('Fetching phone config...');
VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->settings['connection_settings']['default_dc']])); VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]));
} else { } else {
$this->logger->logger("Not fetching phone config"); $this->logger->logger('Not fetching phone config');
} }
} }

View File

@ -519,14 +519,14 @@ trait AuthKeyHandler
$code = yield $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code'); $code = yield $this->datacenter->fileGetContents('http://www.wolframalpha.com/api/v1/code');
$query = 'Do prime factorization of '.$what; $query = 'Do prime factorization of '.$what;
$params = [ $params = [
'async' => true, 'async' => true,
'banners' => 'raw', 'banners' => 'raw',
'debuggingdata' => false, 'debuggingdata' => false,
'format' => 'moutput', 'format' => 'moutput',
'formattimeout' => 8, 'formattimeout' => 8,
'input' => $query, 'input' => $query,
'output' => 'JSON', 'output' => 'JSON',
'proxycode' => json_decode($code, true)['code'], 'proxycode' => json_decode($code, true)['code'],
]; ];
$url = 'https://www.wolframalpha.com/input/json.jsp?'.http_build_query($params); $url = 'https://www.wolframalpha.com/input/json.jsp?'.http_build_query($params);
@ -612,6 +612,7 @@ trait AuthKeyHandler
public function init_authorization_socket_async($id, $socket) public function init_authorization_socket_async($id, $socket)
{ {
$this->init_auth_dcs[$id] = true; $this->init_auth_dcs[$id] = true;
try { try {
if ($socket->session_id === null) { if ($socket->session_id === null) {
$socket->session_id = $this->random(8); $socket->session_id = $this->random(8);

View File

@ -54,7 +54,7 @@ trait CallHandler
$this->ack_outgoing_message_id($message_id, $old_datacenter); $this->ack_outgoing_message_id($message_id, $old_datacenter);
$this->got_response_for_outgoing_message_id($message_id, $old_datacenter); $this->got_response_for_outgoing_message_id($message_id, $old_datacenter);
} else { } else {
$this->logger->logger("Could not resend ".isset($this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['_']) ? $this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['_'] : $message_id); $this->logger->logger('Could not resend '.isset($this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['_']) ? $this->datacenter->sockets[$old_datacenter]->outgoing_messages[$message_id]['_'] : $message_id);
} }
} }
if (!$postpone) { if (!$postpone) {
@ -92,6 +92,7 @@ trait CallHandler
{ {
return $this->call($this->method_call_async_write_generator($method, $args, $aargs)); return $this->call($this->method_call_async_write_generator($method, $args, $aargs));
} }
public function method_call_async_write_generator($method, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]): \Generator public function method_call_async_write_generator($method, $args = [], $aargs = ['msg_id' => null, 'heavy' => false]): \Generator
{ {
if (is_array($args) && isset($args['id']['_']) && isset($args['id']['dc_id']) && $args['id']['_'] === 'inputBotInlineMessageID') { if (is_array($args) && isset($args['id']['_']) && isset($args['id']['dc_id']) && $args['id']['_'] === 'inputBotInlineMessageID') {

View File

@ -20,11 +20,12 @@
namespace danog\MadelineProto\MTProtoTools; namespace danog\MadelineProto\MTProtoTools;
/** /**
* Stores multiple states * Stores multiple states.
*/ */
class CombinedUpdatesState class CombinedUpdatesState
{ {
private $states = []; private $states = [];
public function __construct($init = []) public function __construct($init = [])
{ {
$this->states[false] = new UpdatesState(); $this->states[false] = new UpdatesState();
@ -38,11 +39,13 @@ class CombinedUpdatesState
$this->states[$channel] = $state; $this->states[$channel] = $state;
} }
} }
/** /**
* Update multiple parameters * Update multiple parameters.
* *
* @param array|null $init * @param array|null $init
* @param integer $channel * @param int $channel
*
* @return UpdatesState * @return UpdatesState
*/ */
public function get($channel = null, $init = []) public function get($channel = null, $init = [])
@ -53,12 +56,15 @@ class CombinedUpdatesState
if (!isset($this->states[$channel])) { if (!isset($this->states[$channel])) {
return $this->states[$channel] = new UpdatesState($init, $channel); return $this->states[$channel] = new UpdatesState($init, $channel);
} }
return $this->states[$channel]->update($init); return $this->states[$channel]->update($init);
} }
/** /**
* Remove update state * Remove update state.
*
* @param int $channel
* *
* @param integer $channel
* @return void * @return void
*/ */
public function remove($channel) public function remove($channel)
@ -67,22 +73,26 @@ class CombinedUpdatesState
unset($this->states[$channel]); unset($this->states[$channel]);
} }
} }
/** /**
* Check if update state is present * Check if update state is present.
*
* @param int $channel
* *
* @param integer $channel
* @return void * @return void
*/ */
public function has($channel) public function has($channel)
{ {
return isset($this->states[$channel]); return isset($this->states[$channel]);
} }
/** /**
* Are we currently busy? * Are we currently busy?
* *
* @param integer $channel * @param int $channel
* @param boolean|null $set * @param bool|null $set
* @return boolean *
* @return bool
*/ */
public function syncLoading($channel, $set = null) public function syncLoading($channel, $set = null)
{ {

View File

@ -97,7 +97,7 @@ trait Files
static function () use ($file_id, $part_num, $part_total_num, $part_size, $f, $ctx, $ige, $seekable) { static function () use ($file_id, $part_num, $part_total_num, $part_size, $f, $ctx, $ige, $seekable) {
if ($seekable) { if ($seekable) {
fseek($f, $part_num * $part_size); fseek($f, $part_num * $part_size);
} else if (ftell($f) !== $part_num * $part_size) { } elseif (ftell($f) !== $part_num * $part_size) {
throw new \danog\MadelineProto\Exception('Wrong position!'); throw new \danog\MadelineProto\Exception('Wrong position!');
} }

View File

@ -19,7 +19,6 @@
namespace danog\MadelineProto\MTProtoTools; namespace danog\MadelineProto\MTProtoTools;
use Amp\Loop;
use Amp\Artax\Request; use Amp\Artax\Request;
/** /**
@ -30,7 +29,7 @@ trait PeerHandler
public $caching_simple = []; public $caching_simple = [];
public $caching_simple_username = []; public $caching_simple_username = [];
public $caching_possible_username = []; public $caching_possible_username = [];
public function to_supergroup($id) public function to_supergroup($id)
{ {
return -($id + pow(10, (int) floor(log($id, 10) + 3))); return -($id + pow(10, (int) floor(log($id, 10) + 3)));
@ -65,9 +64,11 @@ trait PeerHandler
}*/ }*/
if (!isset($this->caching_simple[$user['id']]) && !(isset($user['username']) && isset($this->caching_simple_username[$user['username']]))) { if (!isset($this->caching_simple[$user['id']]) && !(isset($user['username']) && isset($this->caching_simple_username[$user['username']]))) {
$this->logger->logger("No access hash with user {$user['id']}, trying to fetch by ID..."); $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by ID...");
if (isset($user['username']) && !isset($this->caching_simple_username[$user['username']])) $this->caching_possible_username[$user['id']] = $user['username']; if (isset($user['username']) && !isset($this->caching_simple_username[$user['username']])) {
$this->caching_possible_username[$user['id']] = $user['username'];
}
$this->cache_pwr_chat($user['id'], false, true); $this->cache_pwr_chat($user['id'], false, true);
} else if (isset($user['username']) && !isset($this->chats[$user['id']]) && !isset($this->caching_simple_username[$user['username']])) { } elseif (isset($user['username']) && !isset($this->chats[$user['id']]) && !isset($this->caching_simple_username[$user['username']])) {
$this->logger->logger("No access hash with user {$user['id']}, trying to fetch by username..."); $this->logger->logger("No access hash with user {$user['id']}, trying to fetch by username...");
$this->cache_pwr_chat($user['username'], false, true); $this->cache_pwr_chat($user['username'], false, true);
} else { } else {
@ -111,15 +112,18 @@ trait PeerHandler
if (!isset($chat['access_hash'])) { if (!isset($chat['access_hash'])) {
if (!isset($this->caching_simple[$bot_api_id]) && !(isset($chat['username']) && isset($this->caching_simple_username[$chat['username']]))) { if (!isset($this->caching_simple[$bot_api_id]) && !(isset($chat['username']) && isset($this->caching_simple_username[$chat['username']]))) {
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by ID..."); $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by ID...");
if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) $this->caching_possible_username[$bot_api_id] = $chat['username']; if (isset($chat['username']) && !isset($this->caching_simple_username[$chat['username']])) {
$this->caching_possible_username[$bot_api_id] = $chat['username'];
}
$this->cache_pwr_chat($bot_api_id, false, true); $this->cache_pwr_chat($bot_api_id, false, true);
} else if (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) { } elseif (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) {
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username..."); $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username...");
$this->cache_pwr_chat($chat['username'], false, true); $this->cache_pwr_chat($chat['username'], false, true);
} else { } else {
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data..."); $this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, tried and failed to fetch data...");
} }
return; return;
} }
if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) { if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) {
@ -141,13 +145,13 @@ trait PeerHandler
public function cache_pwr_chat($id, $full_fetch, $send) public function cache_pwr_chat($id, $full_fetch, $send)
{ {
$this->callFork((function () use ($id, $full_fetch, $send) { $this->callFork((function () use ($id, $full_fetch, $send) {
try { try {
yield $this->get_pwr_chat_async($id, $full_fetch, $send); yield $this->get_pwr_chat_async($id, $full_fetch, $send);
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
$this->logger->logger("While caching: ".$e->getMessage(), \danog\MadelineProto\Logger::WARNING); $this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING);
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger->logger("While caching: ".$e->getMessage(), \danog\MadelineProto\Logger::WARNING); $this->logger->logger('While caching: '.$e->getMessage(), \danog\MadelineProto\Logger::WARNING);
} }
})()); })());
} }
@ -248,6 +252,7 @@ trait PeerHandler
if (!isset($id['from_id']) || $id['to_id']['_'] !== 'peerUser' || $id['to_id']['user_id'] !== $this->authorization['user']['id']) { if (!isset($id['from_id']) || $id['to_id']['_'] !== 'peerUser' || $id['to_id']['user_id'] !== $this->authorization['user']['id']) {
return $this->get_id($id['to_id']); return $this->get_id($id['to_id']);
} }
return $id['from_id']; return $id['from_id'];
case 'updateChannelReadMessagesContents': case 'updateChannelReadMessagesContents':
@ -321,10 +326,13 @@ trait PeerHandler
if (is_string($id)) { if (is_string($id)) {
$id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id; $id = \danog\MadelineProto\Magic::$bigint ? (float) $id : (int) $id;
} }
return $id; return $id;
} }
return false; return false;
} }
public function get_info_async($id, $recursive = true) public function get_info_async($id, $recursive = true)
{ {
if (is_array($id)) { if (is_array($id)) {
@ -345,7 +353,9 @@ trait PeerHandler
} }
} }
$try_id = $this->get_id($id); $try_id = $this->get_id($id);
if ($try_id !== false) $id = $try_id; if ($try_id !== false) {
$id = $try_id;
}
$tried_simple = false; $tried_simple = false;
@ -367,7 +377,9 @@ trait PeerHandler
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING); $this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING);
} finally { } finally {
if (isset($this->caching_simple[$id])) unset($this->caching_simple[$id]); if (isset($this->caching_simple[$id])) {
unset($this->caching_simple[$id]);
}
$tried_simple = true; $tried_simple = true;
} }
} }
@ -384,6 +396,7 @@ trait PeerHandler
} }
if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) { if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true && $recursive) {
$dbres = []; $dbres = [];
try { try {
$dbres = json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true); $dbres = json_decode(yield $this->datacenter->fileGetContents('https://id.pwrtelegram.xyz/db/getusername?id='.$id), true);
} catch (\Throwable $e) { } catch (\Throwable $e) {
@ -400,8 +413,10 @@ trait PeerHandler
$user = $this->caching_possible_username[$id]; $user = $this->caching_possible_username[$id];
unset($this->caching_possible_username[$id]); unset($this->caching_possible_username[$id]);
return yield $this->get_info_async($user); return yield $this->get_info_async($user);
} }
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
} }
if (preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) { if (preg_match('@(?:t|telegram)\.(?:me|dog)/(joinchat/)?([a-z0-9_-]*)@i', $id, $matches)) {
@ -697,6 +712,7 @@ trait PeerHandler
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
if ($e->rpc === 'CHAT_ADMIN_REQUIRED') { if ($e->rpc === 'CHAT_ADMIN_REQUIRED') {
$this->logger->logger($e->rpc); $this->logger->logger($e->rpc);
return $has_more; return $has_more;
} else { } else {
throw $e; throw $e;
@ -759,7 +775,9 @@ trait PeerHandler
$offset += count($gres['participants']); $offset += count($gres['participants']);
} while (count($gres['participants'])); } while (count($gres['participants']));
if ($offset === $limit) return true; if ($offset === $limit) {
return true;
}
return $has_more; return $has_more;
} }
@ -816,7 +834,7 @@ trait PeerHandler
$request = (new Request('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id, 'POST'))->withHeader('content-type', 'application/json')->withBody($payload); $request = (new Request('https://id.pwrtelegram.xyz/db'.$this->settings['pwr']['db_token'].'/addnewmadeline?d=pls&from='.$id, 'POST'))->withHeader('content-type', 'application/json')->withBody($payload);
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody(); $result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody();
$this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger("============ $result =============", \danog\MadelineProto\Logger::VERBOSE);
$this->qres = []; $this->qres = [];
$this->last_stored = time() + 10; $this->last_stored = time() + 10;
@ -838,7 +856,9 @@ trait PeerHandler
return false; return false;
} finally { } finally {
if (isset($this->caching_simple_username[$username])) unset($this->caching_simple_username[$username]); if (isset($this->caching_simple_username[$username])) {
unset($this->caching_simple_username[$username]);
}
} }
if ($res['_'] === 'contacts.resolvedPeer') { if ($res['_'] === 'contacts.resolvedPeer') {
return $res; return $res;

View File

@ -19,9 +19,6 @@
namespace danog\MadelineProto\MTProtoTools; namespace danog\MadelineProto\MTProtoTools;
use Amp\Deferred;
use Amp\Promise;
use Amp\Success;
use danog\MadelineProto\Exception; use danog\MadelineProto\Exception;
use danog\MadelineProto\TL\TLCallback; use danog\MadelineProto\TL\TLCallback;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
@ -85,7 +82,6 @@ class ReferenceDatabase implements TLCallback
'user' => self::USER_PHOTO_ORIGIN, 'user' => self::USER_PHOTO_ORIGIN,
'userFull' => self::USER_PHOTO_ORIGIN, 'userFull' => self::USER_PHOTO_ORIGIN,
'wallPaper' => self::WALLPAPER_ORIGIN, 'wallPaper' => self::WALLPAPER_ORIGIN,
'messages.savedGifs' => self::SAVED_GIFS_ORIGIN, 'messages.savedGifs' => self::SAVED_GIFS_ORIGIN,
@ -214,6 +210,7 @@ class ReferenceDatabase implements TLCallback
} }
if (!isset($location['file_reference'])) { if (!isset($location['file_reference'])) {
$this->API->logger->logger("Object {$location['_']} does not have reference", \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger("Object {$location['_']} does not have reference", \danog\MadelineProto\Logger::ERROR);
return false; return false;
} }
$key = count($this->cacheContexts) - 1; $key = count($this->cacheContexts) - 1;
@ -528,6 +525,7 @@ class ReferenceDatabase implements TLCallback
public function populateReference(array $object) public function populateReference(array $object)
{ {
$object['file_reference'] = yield $this->getReference(self::LOCATION_CONTEXT[$object['_']], $object); $object['file_reference'] = yield $this->getReference(self::LOCATION_CONTEXT[$object['_']], $object);
return $object; return $object;
} }

View File

@ -28,7 +28,7 @@ trait ResponseHandler
{ {
public function send_msgs_state_info_async($req_msg_id, $msg_ids, $datacenter) public function send_msgs_state_info_async($req_msg_id, $msg_ids, $datacenter)
{ {
$this->logger->logger("Sending state info for ".count($msg_ids)." message IDs"); $this->logger->logger('Sending state info for '.count($msg_ids).' message IDs');
$info = ''; $info = '';
foreach ($msg_ids as $msg_id) { foreach ($msg_ids as $msg_id) {
$cur_info = 0; $cur_info = 0;
@ -148,7 +148,7 @@ trait ResponseHandler
// Acknowledge that I received the server's response // Acknowledge that I received the server's response
if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) { if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id']])) {
$this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id'], $datacenter); $this->ack_incoming_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['orig_message']['msg_id'], $datacenter);
// Acknowledge that I received the server's response // Acknowledge that I received the server's response
} else { } else {
$message = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']; $message = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'];
$this->datacenter->sockets[$datacenter]->check_message_id($message['orig_message']['msg_id'], ['outgoing' => false, 'container' => true]); $this->datacenter->sockets[$datacenter]->check_message_id($message['orig_message']['msg_id'], ['outgoing' => false, 'container' => true]);
@ -361,6 +361,7 @@ trait ResponseHandler
if ($response['error_message'] === 'MSG_WAIT_FAILED') { if ($response['error_message'] === 'MSG_WAIT_FAILED') {
$this->datacenter->sockets[$datacenter]->call_queue[$request['queue']] = []; $this->datacenter->sockets[$datacenter]->call_queue[$request['queue']] = [];
$this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]); $this->method_recall('', ['message_id' => $request_id, 'datacenter' => $datacenter, 'postpone' => true]);
return; return;
} }
$this->got_response_for_outgoing_message_id($request_id, $datacenter); $this->got_response_for_outgoing_message_id($request_id, $datacenter);
@ -628,6 +629,7 @@ trait ResponseHandler
$to_id = isset($updates['chat_id']) ? -$updates['chat_id'] : ($updates['out'] ? $updates['user_id'] : $this->authorization['user']['id']); $to_id = isset($updates['chat_id']) ? -$updates['chat_id'] : ($updates['out'] ? $updates['user_id'] : $this->authorization['user']['id']);
if (!yield $this->peer_isset_async($from_id) || !yield $this->peer_isset_async($to_id) || isset($updates['via_bot_id']) && !yield $this->peer_isset_async($updates['via_bot_id']) || isset($updates['entities']) && !yield $this->entities_peer_isset_async($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwd_peer_isset_async($updates['fwd_from'])) { if (!yield $this->peer_isset_async($from_id) || !yield $this->peer_isset_async($to_id) || isset($updates['via_bot_id']) && !yield $this->peer_isset_async($updates['via_bot_id']) || isset($updates['entities']) && !yield $this->entities_peer_isset_async($updates['entities']) || isset($updates['fwd_from']) && !yield $this->fwd_peer_isset_async($updates['fwd_from'])) {
yield $this->updaters[false]->resume(); yield $this->updaters[false]->resume();
return; return;
} }
$message = $updates; $message = $updates;

View File

@ -21,7 +21,6 @@ namespace danog\MadelineProto\MTProtoTools;
use Amp\Artax\Request; use Amp\Artax\Request;
use Amp\Deferred; use Amp\Deferred;
use Amp\Delayed;
use Amp\Loop; use Amp\Loop;
/** /**
@ -98,22 +97,24 @@ trait UpdateHandler
return $updates; return $updates;
} }
public $update_resolved = false; public $update_resolved = false;
public $update_deferred; public $update_deferred;
public function waitUpdate() public function waitUpdate()
{ {
if (!$this->update_deferred) { if (!$this->update_deferred) {
$this->update_deferred = new Deferred; $this->update_deferred = new Deferred();
} }
yield $this->update_deferred->promise(); yield $this->update_deferred->promise();
$this->update_resolved = false; $this->update_resolved = false;
$this->update_deferred = new Deferred; $this->update_deferred = new Deferred();
} }
public function signalUpdate() public function signalUpdate()
{ {
if (!$this->update_deferred) { if (!$this->update_deferred) {
$this->update_deferred = new Deferred; $this->update_deferred = new Deferred();
} }
Loop::defer(function () { Loop::defer(function () {
if (!$this->update_resolved) { if (!$this->update_resolved) {
@ -125,7 +126,10 @@ trait UpdateHandler
public function check_msg_id($message) public function check_msg_id($message)
{ {
if (!isset($message['to_id'])) return true; if (!isset($message['to_id'])) {
return true;
}
try { try {
$peer_id = $this->get_id($message['to_id']); $peer_id = $this->get_id($message['to_id']);
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
@ -152,10 +156,12 @@ trait UpdateHandler
return $this->channels_state->get(false); return $this->channels_state->get(false);
} }
public function loadChannelState($channelId = null, $init = []) public function loadChannelState($channelId = null, $init = [])
{ {
return $this->channels_state->get($channelId, $init); return $this->channels_state->get($channelId, $init);
} }
public function getChannelStates() public function getChannelStates()
{ {
return $this->channels_state; return $this->channels_state;

View File

@ -20,37 +20,37 @@
namespace danog\MadelineProto\MTProtoTools; namespace danog\MadelineProto\MTProtoTools;
/** /**
* Stores the state of updates * Stores the state of updates.
*/ */
class UpdatesState class UpdatesState
{ {
/** /**
* PTS * PTS.
* *
* @var int * @var int
*/ */
private $pts = 1; private $pts = 1;
/** /**
* QTS * QTS.
* *
* @var int * @var int
*/ */
private $qts = -1; private $qts = -1;
/** /**
* Seq * Seq.
* *
* @var int * @var int
*/ */
private $seq = 0; private $seq = 0;
/** /**
* Date * Date.
* *
* @var int * @var int
*/ */
private $date = 1; private $date = 1;
/** /**
* Channel ID * Channel ID.
* *
* @var int|bool * @var int|bool
*/ */
@ -59,23 +59,24 @@ class UpdatesState
/** /**
* Is busy? * Is busy?
* *
* @var boolean * @var bool
*/ */
private $syncLoading = false; private $syncLoading = false;
/** /**
* Init function * Init function.
* *
* @param array $init Initial parameters * @param array $init Initial parameters
* @param boolean $channelId Channel ID * @param bool $channelId Channel ID
*/ */
public function __construct($init = [], $channelId = false) public function __construct($init = [], $channelId = false)
{ {
$this->channelId = $channelId; $this->channelId = $channelId;
$this->update($init); $this->update($init);
} }
/** /**
* Sleep function * Sleep function.
* *
* @return array Parameters to serialize * @return array Parameters to serialize
*/ */
@ -83,17 +84,19 @@ class UpdatesState
{ {
return $this->channelId ? ['pts', 'channelId'] : ['pts', 'qts', 'seq', 'date', 'channelId']; return $this->channelId ? ['pts', 'channelId'] : ['pts', 'qts', 'seq', 'date', 'channelId'];
} }
/** /**
* Is this state relative to a channel? * Is this state relative to a channel?
* *
* @return boolean * @return bool
*/ */
public function isChannel() public function isChannel()
{ {
return (bool) $this->channelId; return (bool) $this->channelId;
} }
/** /**
* Get the channel ID * Get the channel ID.
* *
* @return int|null * @return int|null
*/ */
@ -101,24 +104,28 @@ class UpdatesState
{ {
return $this->channelId; return $this->channelId;
} }
/** /**
* Are we currently busy? * Are we currently busy?
* *
* @param boolean|null $set * @param bool|null $set
* @return boolean *
* @return bool
*/ */
public function syncLoading($set = null) public function syncLoading($set = null)
{ {
if ($set !== null) { if ($set !== null) {
$this->syncLoading = $set; $this->syncLoading = $set;
} }
return $this->syncLoading; return $this->syncLoading;
} }
/** /**
* Update multiple parameters * Update multiple parameters.
* *
* @param array $init * @param array $init
*
* @return self * @return self
*/ */
public function update($init) public function update($init)
@ -128,75 +135,91 @@ class UpdatesState
$this->{$param}($init[$param]); $this->{$param}($init[$param]);
} }
} }
return $this; return $this;
} }
/** /**
* Get/set PTS * Get/set PTS.
* *
* @param integer $set * @param int $set
* @return integer *
* @return int
*/ */
public function pts($set = 0) public function pts($set = 0)
{ {
if ($set !== 0 && $set > $this->pts) { if ($set !== 0 && $set > $this->pts) {
$this->pts = $set; $this->pts = $set;
} }
return $this->pts; return $this->pts;
} }
/** /**
* Get/set QTS * Get/set QTS.
* *
* @param integer $set * @param int $set
* @return integer *
* @return int
*/ */
public function qts($set = 0) public function qts($set = 0)
{ {
if ($set !== 0 && $set > $this->qts) { if ($set !== 0 && $set > $this->qts) {
$this->qts = $set; $this->qts = $set;
} }
return $this->qts; return $this->qts;
} }
/** /**
* Get/set seq * Get/set seq.
* *
* @param integer $set * @param int $set
* @return integer *
* @return int
*/ */
public function seq($set = 0) public function seq($set = 0)
{ {
if ($set !== 0 && $set > $this->seq) { if ($set !== 0 && $set > $this->seq) {
$this->seq = $set; $this->seq = $set;
} }
return $this->seq; return $this->seq;
} }
/** /**
* Get/set date * Get/set date.
* *
* @param integer $set * @param int $set
* @return integer *
* @return int
*/ */
public function date($set = 0) public function date($set = 0)
{ {
if ($set !== 0 && $set > $this->date) { if ($set !== 0 && $set > $this->date) {
$this->date = $set; $this->date = $set;
} }
return $this->date; return $this->date;
} }
/** /**
* Check validity of PTS contained in update * Check validity of PTS contained in update.
* *
* @param array $update * @param array $update
*
* @return int -1 if it's too old, 0 if it's ok, 1 if it's too new * @return int -1 if it's too old, 0 if it's ok, 1 if it's too new
*/ */
public function checkPts($update) public function checkPts($update)
{ {
return $update['pts'] - ($this->pts + $update['pts_count']); return $update['pts'] - ($this->pts + $update['pts_count']);
} }
/** /**
* Check validity of seq contained in update * Check validity of seq contained in update.
* *
* @param int $seq * @param int $seq
*
* @return int -1 if it's too old, 0 if it's ok, 1 if it's too new * @return int -1 if it's too old, 0 if it's ok, 1 if it's too new
*/ */
public function checkSeq($seq) public function checkSeq($seq)

View File

@ -124,10 +124,12 @@ class Magic
} }
$backtrace = debug_backtrace(0); $backtrace = debug_backtrace(0);
self::$script_cwd = self::$cwd = dirname(end($backtrace)['file']); self::$script_cwd = self::$cwd = dirname(end($backtrace)['file']);
try { try {
self::$cwd = getcwd(); self::$cwd = getcwd();
self::$can_getcwd = true; self::$can_getcwd = true;
} catch (\danog\MadelineProto\Exception $e) {} } catch (\danog\MadelineProto\Exception $e) {
}
self::$inited = true; self::$inited = true;
} }
} }
@ -151,6 +153,7 @@ class Magic
return self::$can_getmypid = false; return self::$can_getmypid = false;
} }
} }
public static function getcwd() public static function getcwd()
{ {
return self::$can_getcwd ? getcwd() : self::$cwd; return self::$can_getcwd ? getcwd() : self::$cwd;

View File

@ -40,6 +40,7 @@ class MyTelegramOrgWrapper
{ {
return ['logged', 'hash', 'token', 'number', 'creation_hash', 'settings']; return ['logged', 'hash', 'token', 'number', 'creation_hash', 'settings'];
} }
public function __construct($settings) public function __construct($settings)
{ {
if (!isset($settings['all'])) { if (!isset($settings['all'])) {
@ -58,21 +59,21 @@ class MyTelegramOrgWrapper
'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [], 'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [],
// Extra parameters to pass to the proxy class using setExtra // Extra parameters to pass to the proxy class using setExtra
'obfuscated' => false, 'obfuscated' => false,
'transport' => 'tcp', 'transport' => 'tcp',
'pfs' => extension_loaded('gmp'), 'pfs' => extension_loaded('gmp'),
], ],
]; ];
} }
$this->settings = $settings; $this->settings = $settings;
$this->__wakeup(); $this->__wakeup();
} }
public function __wakeup() public function __wakeup()
{ {
$this->datacenter = new DataCenter( $this->datacenter = new DataCenter(
new class($this->settings) new class($this->settings) {
{
public function __construct($settings) public function __construct($settings)
{ {
$this->logger = new Logger( $this->logger = new Logger(
isset($settings['logger']['logger']) ? $settings['logger']['logger'] : php_sapi_name() === 'cli' ? 3 : 2, isset($settings['logger']['logger']) ? $settings['logger']['logger'] : php_sapi_name() === 'cli' ? 3 : 2,
isset($settings['logger']['logger_param']) ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log', isset($settings['logger']['logger_param']) ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log',
@ -84,6 +85,7 @@ class MyTelegramOrgWrapper
$this->settings['connection_settings'] $this->settings['connection_settings']
); );
} }
public function login_async($number) public function login_async($number)
{ {
$this->number = $number; $this->number = $number;
@ -271,14 +273,17 @@ class MyTelegramOrgWrapper
return $final_headers; return $final_headers;
} }
public function async($async) public function async($async)
{ {
$this->async = $async; $this->async = $async;
} }
public function __call($name, $arguments) public function __call($name, $arguments)
{ {
$name .= '_async'; $name .= '_async';
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async; $async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async;
return $async ? $this->{$name}(...$arguments) : $this->wait($this->{$name}(...$arguments)); return $async ? $this->{$name}(...$arguments) : $this->wait($this->{$name}(...$arguments));
} }
} }

View File

@ -1,4 +1,5 @@
<?php <?php
// Based on AMPHP's default socket pool // Based on AMPHP's default socket pool
namespace danog\MadelineProto; namespace danog\MadelineProto;
@ -8,22 +9,22 @@ use Amp\CancelledException;
use Amp\Failure; use Amp\Failure;
use Amp\Loop; use Amp\Loop;
use Amp\Promise; use Amp\Promise;
use Amp\Struct;
use Amp\Success;
use Amp\Socket\SocketPool;
use function Amp\call;
use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientConnectContext;
use Amp\Socket\ClientSocket; use Amp\Socket\ClientSocket;
use Amp\Socket\SocketPool;
use Amp\Struct;
use Amp\Success;
use League\Uri; use League\Uri;
use function Amp\call;
class ProxySocketPool implements SocketPool class ProxySocketPool implements SocketPool
{ {
use Tools; use Tools;
const ALLOWED_SCHEMES = [ const ALLOWED_SCHEMES = [
'tcp' => null, 'tcp' => null,
'udp' => null, 'udp' => null,
'unix' => null, 'unix' => null,
'udg' => null, 'udg' => null,
]; ];
private $sockets = []; private $sockets = [];
private $socketIdUriMap = []; private $socketIdUriMap = [];
@ -31,35 +32,38 @@ class ProxySocketPool implements SocketPool
private $idleTimeout; private $idleTimeout;
private $socketContext; private $socketContext;
private $dataCenter; private $dataCenter;
public function __construct(DataCenter $dataCenter, int $idleTimeout = 10000, ClientConnectContext $socketContext = null) public function __construct(DataCenter $dataCenter, int $idleTimeout = 10000, ClientConnectContext $socketContext = null)
{ {
$this->idleTimeout = $idleTimeout; $this->idleTimeout = $idleTimeout;
$this->socketContext = $socketContext ?? new ClientConnectContext; $this->socketContext = $socketContext ?? new ClientConnectContext();
$this->dataCenter = $dataCenter; $this->dataCenter = $dataCenter;
} }
/** /**
* @param string $uri * @param string $uri
* *
* @return string
*
* @throws SocketException * @throws SocketException
*
* @return string
*/ */
private function normalizeUri(string $uri): string private function normalizeUri(string $uri): string
{ {
if (\stripos($uri, 'unix://') === 0) { if (\stripos($uri, 'unix://') === 0) {
return $uri; return $uri;
} }
try { try {
$parts = Uri\parse($uri); $parts = Uri\parse($uri);
} catch (\Exception $exception) { } catch (\Exception $exception) {
throw new SocketException("Could not parse URI", 0, $exception); throw new SocketException('Could not parse URI', 0, $exception);
} }
if ($parts['scheme'] === null) { if ($parts['scheme'] === null) {
throw new SocketException("Invalid URI for socket pool; no scheme given"); throw new SocketException('Invalid URI for socket pool; no scheme given');
} }
$port = $parts['port'] ?? 0; $port = $parts['port'] ?? 0;
if ($parts['host'] === null || $port === 0) { if ($parts['host'] === null || $port === 0) {
throw new SocketException("Invalid URI for socket pool; missing host or port"); throw new SocketException('Invalid URI for socket pool; missing host or port');
} }
$scheme = \strtolower($parts['scheme']); $scheme = \strtolower($parts['scheme']);
$host = \strtolower($parts['host']); $host = \strtolower($parts['host']);
@ -71,17 +75,19 @@ class ProxySocketPool implements SocketPool
)); ));
} }
if ($parts['query'] !== null || $parts['fragment'] !== null) { if ($parts['query'] !== null || $parts['fragment'] !== null) {
throw new SocketException("Invalid URI for socket pool; query or fragment components not allowed"); throw new SocketException('Invalid URI for socket pool; query or fragment components not allowed');
} }
if ($parts['path'] !== '') { if ($parts['path'] !== '') {
throw new SocketException("Invalid URI for socket pool; path component must be empty"); throw new SocketException('Invalid URI for socket pool; path component must be empty');
} }
if ($parts['user'] !== null) { if ($parts['user'] !== null) {
throw new SocketException("Invalid URI for socket pool; user component not allowed"); throw new SocketException('Invalid URI for socket pool; user component not allowed');
} }
return $scheme.'://'.$host.':'.$port; return $scheme.'://'.$host.':'.$port;
} }
/** @inheritdoc */
/** {@inheritdoc} */
public function checkout(string $uri, CancellationToken $token = null): Promise public function checkout(string $uri, CancellationToken $token = null): Promise
{ {
// A request might already be cancelled before we reach the checkout, so do not even attempt to checkout in that // A request might already be cancelled before we reach the checkout, so do not even attempt to checkout in that
@ -109,14 +115,18 @@ class ProxySocketPool implements SocketPool
if ($socket->idleWatcher !== null) { if ($socket->idleWatcher !== null) {
Loop::disable($socket->idleWatcher); Loop::disable($socket->idleWatcher);
} }
return new Success(new ClientSocket($socket->resource)); return new Success(new ClientSocket($socket->resource));
} }
return $this->checkoutNewSocket($uri, $token); return $this->checkoutNewSocket($uri, $token);
} }
private function checkoutNewSocket(string $uri, CancellationToken $token = null): Promise private function checkoutNewSocket(string $uri, CancellationToken $token = null): Promise
{ {
return call(function () use ($uri, $token) { return call(function () use ($uri, $token) {
$this->pendingCount[$uri] = ($this->pendingCount[$uri] ?? 0) + 1; $this->pendingCount[$uri] = ($this->pendingCount[$uri] ?? 0) + 1;
try { try {
/** @var ClientSocket $rawSocket */ /** @var ClientSocket $rawSocket */
$rawSocket = yield $this->call($this->dataCenter->rawConnectAsync($uri, $token, $this->socketContext)); $rawSocket = yield $this->call($this->dataCenter->rawConnectAsync($uri, $token, $this->socketContext));
@ -126,9 +136,7 @@ class ProxySocketPool implements SocketPool
} }
} }
$socketId = (int) $rawSocket->getResource(); $socketId = (int) $rawSocket->getResource();
$socket = new class $socket = new class() {
{
use Struct; use Struct;
public $id; public $id;
public $uri; public $uri;
@ -142,14 +150,17 @@ class ProxySocketPool implements SocketPool
$socket->isAvailable = false; $socket->isAvailable = false;
$this->sockets[$uri][$socketId] = $socket; $this->sockets[$uri][$socketId] = $socket;
$this->socketIdUriMap[$socketId] = $uri; $this->socketIdUriMap[$socketId] = $uri;
return $rawSocket; return $rawSocket;
}); });
} }
/** @inheritdoc */
/** {@inheritdoc} */
public function clear(ClientSocket $socket): void public function clear(ClientSocket $socket): void
{ {
$this->clearFromId((int) $socket->getResource()); $this->clearFromId((int) $socket->getResource());
} }
/** /**
* @param int $socketId * @param int $socketId
*/ */
@ -173,7 +184,8 @@ class ProxySocketPool implements SocketPool
unset($this->sockets[$uri]); unset($this->sockets[$uri]);
} }
} }
/** @inheritdoc */
/** {@inheritdoc} */
public function checkin(ClientSocket $socket): void public function checkin(ClientSocket $socket): void
{ {
$socketId = (int) $socket->getResource(); $socketId = (int) $socket->getResource();
@ -186,6 +198,7 @@ class ProxySocketPool implements SocketPool
$resource = $socket->getResource(); $resource = $socket->getResource();
if (!\is_resource($resource) || \feof($resource)) { if (!\is_resource($resource) || \feof($resource)) {
$this->clearFromId((int) $resource); $this->clearFromId((int) $resource);
return; return;
} }
$socket = $this->sockets[$uri][$socketId]; $socket = $this->sockets[$uri][$socketId];

View File

@ -43,6 +43,7 @@ class RPCErrorException extends \Exception
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); $result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
} }
return $result; return $result;
} }

View File

@ -27,8 +27,6 @@ class Serialization
public static function serialize_all($exception) public static function serialize_all($exception)
{ {
echo $exception.PHP_EOL; echo $exception.PHP_EOL;
return;
} }
public static function realpaths($file) public static function realpaths($file)

View File

@ -18,9 +18,7 @@
namespace danog\MadelineProto\Stream\Async; namespace danog\MadelineProto\Stream\Async;
use Amp\Failure;
use Amp\Promise; use Amp\Promise;
use Amp\Success;
/** /**
* Buffered stream helper trait. * Buffered stream helper trait.

View File

@ -20,7 +20,6 @@ namespace danog\MadelineProto\Stream\Async;
use Amp\Promise; use Amp\Promise;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use function Amp\call;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
/** /**
@ -33,6 +32,7 @@ use danog\MadelineProto\Tools;
trait Stream trait Stream
{ {
use Tools; use Tools;
public function connect(ConnectionContext $ctx, string $header = ''): Promise public function connect(ConnectionContext $ctx, string $header = ''): Promise
{ {
return $this->call($this->connectAsync($ctx, $header)); return $this->call($this->connectAsync($ctx, $header));

View File

@ -23,9 +23,7 @@ use Amp\Success;
use danog\MadelineProto\Exception; use danog\MadelineProto\Exception;
use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\Async\RawStream;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use function Amp\call;
use function Amp\Socket\connect; use function Amp\Socket\connect;
use danog\MadelineProto\NothingInTheSocketException;
/** /**
* Buffered raw stream. * Buffered raw stream.
@ -42,6 +40,7 @@ class BufferedRawStream implements \danog\MadelineProto\Stream\BufferedStreamInt
protected $memory_stream; protected $memory_stream;
private $append = ''; private $append = '';
private $append_after = 0; private $append_after = 0;
/** /**
* Asynchronously connect to a TCP/TLS server. * Asynchronously connect to a TCP/TLS server.
* *
@ -177,6 +176,7 @@ class BufferedRawStream implements \danog\MadelineProto\Stream\BufferedStreamInt
$chunk = yield $this->read(); $chunk = yield $this->read();
if ($chunk === null) { if ($chunk === null) {
$this->disconnect(); $this->disconnect();
throw new \danog\MadelineProto\NothingInTheSocketException(); throw new \danog\MadelineProto\NothingInTheSocketException();
} }
fwrite($this->memory_stream, $chunk); fwrite($this->memory_stream, $chunk);
@ -213,8 +213,8 @@ class BufferedRawStream implements \danog\MadelineProto\Stream\BufferedStreamInt
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -310,9 +310,10 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
return $this->write_buffer->bufferWrite($data); return $this->write_buffer->bufferWrite($data);
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -19,7 +19,6 @@
namespace danog\MadelineProto\Stream; namespace danog\MadelineProto\Stream;
use Amp\CancellationToken; use Amp\CancellationToken;
use Amp\Promise;
use Amp\Socket\ClientConnectContext; use Amp\Socket\ClientConnectContext;
use Amp\Uri\Uri; use Amp\Uri\Uri;
@ -320,7 +319,6 @@ class ConnectionContext
return $this->nextStreams[$this->key][0]; return $this->nextStreams[$this->key][0];
} }
/** /**
* Get a stream from the stream chain. * Get a stream from the stream chain.
* *

View File

@ -98,9 +98,10 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
return $buffer; return $buffer;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -106,9 +106,10 @@ class FullStream implements BufferedStreamInterface, MTProtoBufferInterface
return $buffer; return $buffer;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -24,7 +24,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream;
use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\MTProtoBufferInterface; use danog\MadelineProto\Stream\MTProtoBufferInterface;
use danog\MadelineProto\Tools;
/** /**
* HTTP stream wrapper. * HTTP stream wrapper.
@ -180,9 +179,10 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
{ {
return new Success($this->code); return new Success($this->code);
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -39,9 +39,10 @@ class HttpsStream extends HttpStream implements MTProtoBufferInterface
{ {
return parent::connectAsync($ctx->getCtx()->secure(true), $header); return parent::connectAsync($ctx->getCtx()->secure(true), $header);
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -23,7 +23,6 @@ use danog\MadelineProto\Stream\Async\BufferedStream;
use danog\MadelineProto\Stream\BufferedStreamInterface; use danog\MadelineProto\Stream\BufferedStreamInterface;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\MTProtoBufferInterface; use danog\MadelineProto\Stream\MTProtoBufferInterface;
use danog\MadelineProto\Tools;
/** /**
* TCP Intermediate stream wrapper. * TCP Intermediate stream wrapper.
@ -89,9 +88,10 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
return $buffer; return $buffer;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -87,9 +87,10 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
return $buffer; return $buffer;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -24,7 +24,6 @@ use danog\MadelineProto\Stream\Async\Buffer;
use danog\MadelineProto\Stream\Async\BufferedStream; use danog\MadelineProto\Stream\Async\BufferedStream;
use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Tools;
/** /**
* Obfuscated2 stream wrapper. * Obfuscated2 stream wrapper.
@ -195,9 +194,10 @@ class ObfuscatedStream implements BufferedProxyStreamInterface
} }
$this->extra = $extra; $this->extra = $extra;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -19,11 +19,11 @@
namespace danog\MadelineProto\Stream\Proxy; namespace danog\MadelineProto\Stream\Proxy;
use Amp\Promise; use Amp\Promise;
use Amp\Socket\ClientTlsContext;
use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\Async\RawStream;
use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\RawProxyStreamInterface; use danog\MadelineProto\Stream\RawProxyStreamInterface;
use Amp\Socket\ClientTlsContext;
/** /**
* HTTP proxy stream wrapper. * HTTP proxy stream wrapper.
@ -56,7 +56,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
if (strlen(inet_pton($address)) === 16) { if (strlen(inet_pton($address)) === 16) {
$address = '['.$address.']'; $address = '['.$address.']';
} }
yield $this->stream->write("CONNECT $address:$port HTTP/1.1\r\nHost: $address:$port\r\nAccept: */*\r\n".$this->getProxyAuthHeader()."Connection: keep-Alive\r\n\r\n"); yield $this->stream->write("CONNECT $address:$port HTTP/1.1\r\nHost: $address:$port\r\nAccept: */*\r\n".$this->getProxyAuthHeader()."Connection: keep-Alive\r\n\r\n");
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
@ -124,7 +124,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
\danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http'); \danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http');
if ($secure && method_exists($this->getSocket(), 'enableCrypto')) { if ($secure && method_exists($this->getSocket(), 'enableCrypto')) {
yield $this->getSocket()->enableCrypto((new ClientTlsContext)->withPeerName($uri->getHost())); yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost()));
} }
if (strlen($header)) { if (strlen($header)) {
@ -196,9 +196,10 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
{ {
$this->extra = $extra; $this->extra = $extra;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -19,11 +19,11 @@
namespace danog\MadelineProto\Stream\Proxy; namespace danog\MadelineProto\Stream\Proxy;
use Amp\Promise; use Amp\Promise;
use Amp\Socket\ClientTlsContext;
use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\Async\RawStream;
use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\BufferedProxyStreamInterface;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\RawProxyStreamInterface; use danog\MadelineProto\Stream\RawProxyStreamInterface;
use Amp\Socket\ClientTlsContext;
/** /**
* Socks5 stream wrapper. * Socks5 stream wrapper.
@ -54,7 +54,7 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
$methods .= chr(2); $methods .= chr(2);
} }
$this->stream = yield $ctx->getStream(chr(5).chr(strlen($methods)).$methods); $this->stream = yield $ctx->getStream(chr(5).chr(strlen($methods)).$methods);
$l = 2; $l = 2;
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
@ -139,7 +139,7 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
\danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']); \danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']);
if ($secure && method_exists($this->getSocket(), 'enableCrypto')) { if ($secure && method_exists($this->getSocket(), 'enableCrypto')) {
yield $this->getSocket()->enableCrypto((new ClientTlsContext)->withPeerName($uri->getHost())); yield $this->getSocket()->enableCrypto((new ClientTlsContext())->withPeerName($uri->getHost()));
} }
if (strlen($header)) { if (strlen($header)) {
yield (yield $this->stream->getWriteBuffer(strlen($header)))->bufferWrite($header); yield (yield $this->stream->getWriteBuffer(strlen($header)))->bufferWrite($header);
@ -201,8 +201,9 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
{ {
$this->extra = $extra; $this->extra = $extra;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */

View File

@ -45,8 +45,8 @@ interface StreamInterface
public function disconnect(); public function disconnect();
/** /**
* Get underlying AMPHP socket resource * Get underlying AMPHP socket resource.
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): Socket; public function getSocket(): Socket;

View File

@ -40,6 +40,7 @@ class DefaultStream extends Socket implements RawStreamInterface
public function __construct() public function __construct()
{ {
} }
public function enableCrypto(ClientTlsContext $tlsContext = null): \Amp\Promise public function enableCrypto(ClientTlsContext $tlsContext = null): \Amp\Promise
{ {
return $this->enableCrypto($tlsContext); return $this->enableCrypto($tlsContext);
@ -105,9 +106,10 @@ class DefaultStream extends Socket implements RawStreamInterface
{ {
$this->disconnect(); $this->disconnect();
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */
public function getSocket(): \Amp\Socket\Socket public function getSocket(): \Amp\Socket\Socket

View File

@ -31,7 +31,6 @@ use Amp\Websocket\Rfc7692CompressionFactory;
use danog\MadelineProto\Stream\Async\RawStream; use danog\MadelineProto\Stream\Async\RawStream;
use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\RawStreamInterface; use danog\MadelineProto\Stream\RawStreamInterface;
use danog\MadelineProto\Tools;
use function Amp\Websocket\generateKey; use function Amp\Websocket\generateKey;
use function Amp\Websocket\validateAcceptForKey; use function Amp\Websocket\validateAcceptForKey;
@ -60,7 +59,7 @@ class WsStream implements RawStreamInterface
$stream = yield $ctx->getStream(); $stream = yield $ctx->getStream();
$resource = $stream->getStream()->getResource(); $resource = $stream->getStream()->getResource();
$this->compressionFactory = new Rfc7692CompressionFactory; $this->compressionFactory = new Rfc7692CompressionFactory();
$handshake = new Handshake(str_replace('tcp://', $ctx->isSecure() ? 'ws://' : 'wss://', $ctx->getStringUri())); $handshake = new Handshake(str_replace('tcp://', $ctx->isSecure() ? 'ws://' : 'wss://', $ctx->getStringUri()));
@ -154,8 +153,10 @@ class WsStream implements RawStreamInterface
if (($query = $uri->getQuery()) !== '') { if (($query = $uri->getQuery()) !== '') {
$path .= '?'.$query; $path .= '?'.$query;
} }
return \sprintf("GET %s HTTP/1.1\r\n%s\r\n", $path, Rfc7230::formatHeaders($headers)); return \sprintf("GET %s HTTP/1.1\r\n%s\r\n", $path, Rfc7230::formatHeaders($headers));
} }
private function handleResponse(string $headerBuffer, string $key): array private function handleResponse(string $headerBuffer, string $key): array
{ {
if (\substr($headerBuffer, -4) !== "\r\n\r\n") { if (\substr($headerBuffer, -4) !== "\r\n\r\n") {
@ -190,8 +191,10 @@ class WsStream implements RawStreamInterface
if (!validateAcceptForKey($secWebsocketAccept, $key)) { if (!validateAcceptForKey($secWebsocketAccept, $key)) {
throw new ConnectionException('Invalid "Sec-WebSocket-Accept" header'); throw new ConnectionException('Invalid "Sec-WebSocket-Accept" header');
} }
return $headers; return $headers;
} }
final protected function createCompressionContext(array $headers): ?Websocket\CompressionContext final protected function createCompressionContext(array $headers): ?Websocket\CompressionContext
{ {
$extensions = $headers['sec-websocket-extensions'][0] ?? ''; $extensions = $headers['sec-websocket-extensions'][0] ?? '';
@ -201,10 +204,12 @@ class WsStream implements RawStreamInterface
return $compressionContext; return $compressionContext;
} }
} }
return null; return null;
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @return \Amp\Socket\Socket * @return \Amp\Socket\Socket
*/ */

View File

@ -550,7 +550,6 @@ trait BotAPI
} }
} }
$multiple_args_base = array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']); $multiple_args_base = array_merge($args, ['entities' => [], 'parse_mode' => 'text', 'message' => '']);
$multiple_args = [$multiple_args_base]; $multiple_args = [$multiple_args_base];
$i = 0; $i = 0;
@ -630,12 +629,13 @@ trait BotAPI
} }
} }
if ($c >= 8110) { if ($c >= 8110) {
$this->logger->logger("Entity size limit possibly exceeded, you may get an error indicating that the entities are too long. Reduce the number of entities and/or size of the URLs used.", Logger::FATAL_ERROR); $this->logger->logger('Entity size limit possibly exceeded, you may get an error indicating that the entities are too long. Reduce the number of entities and/or size of the URLs used.', Logger::FATAL_ERROR);
} }
} }
if ($total) { if ($total) {
$this->logger->logger("Too many entities, $total entities will be truncated", Logger::FATAL_ERROR); $this->logger->logger("Too many entities, $total entities will be truncated", Logger::FATAL_ERROR);
} }
return $multiple_args; return $multiple_args;
} }
@ -678,6 +678,7 @@ trait BotAPI
$temp .= substr($text, $match[1] + strlen($match[0])); $temp .= substr($text, $match[1] + strlen($match[0]));
$text = $temp; $text = $temp;
} }
return $text; return $text;
} else { } else {
return htmlentities($text); return htmlentities($text);

View File

@ -29,6 +29,7 @@ class Exception extends \Exception
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); $result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
} }
return $result; return $result;
} }

View File

@ -29,6 +29,7 @@ class Exception extends \Exception
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result); $result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
} }
return $result; return $result;
} }

View File

@ -31,7 +31,9 @@ trait PrettyException
public function prettify_tl($init = '') public function prettify_tl($init = '')
{ {
$eol = PHP_EOL; $eol = PHP_EOL;
if (php_sapi_name() !== 'cli') $eol = '<br>'.PHP_EOL; if (php_sapi_name() !== 'cli') {
$eol = '<br>'.PHP_EOL;
}
$tl = false; $tl = false;
foreach (array_reverse($this->getTrace()) as $k => $frame) { foreach (array_reverse($this->getTrace()) as $k => $frame) {
if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) { if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) {

View File

@ -63,6 +63,7 @@ class Button implements \JsonSerializable, \ArrayAccess
$res = $this->info['API']->$method('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['datacenter' => $this->info['API']->datacenter->curdc]); $res = $this->info['API']->$method('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['datacenter' => $this->info['API']->datacenter->curdc]);
break; break;
} }
return $async ? $res : $this->wait($res); return $async ? $res : $this->wait($res);
} }

View File

@ -195,7 +195,7 @@ trait Tools
}); });
}); });
} catch (\Throwable $throwable) { } catch (\Throwable $throwable) {
throw new \Error("Loop exceptionally stopped without resolving the promise", 0, $throwable); throw new \Error('Loop exceptionally stopped without resolving the promise', 0, $throwable);
} }
} while (!$resolved); } while (!$resolved);
@ -205,38 +205,48 @@ trait Tools
return $value; return $value;
} }
public function all($promises) public function all($promises)
{ {
foreach ($promises as &$promise) { foreach ($promises as &$promise) {
$promise = $this->call($promise); $promise = $this->call($promise);
} }
return all($promises); return all($promises);
} }
public function any($promises) public function any($promises)
{ {
foreach ($promises as &$promise) { foreach ($promises as &$promise) {
$promise = $this->call($promise); $promise = $this->call($promise);
} }
return any($promises); return any($promises);
} }
public function some($promises) public function some($promises)
{ {
foreach ($promises as &$promise) { foreach ($promises as &$promise) {
$promise = $this->call($promise); $promise = $this->call($promise);
} }
return some($promises); return some($promises);
} }
public function first($promises) public function first($promises)
{ {
foreach ($promises as &$promise) { foreach ($promises as &$promise) {
$promise = $this->call($promise); $promise = $this->call($promise);
} }
return first($promises); return first($promises);
} }
public function timeout($promise, $timeout) public function timeout($promise, $timeout)
{ {
return timeout($this->call($promise), $timeout); return timeout($this->call($promise), $timeout);
} }
public function call($promise) public function call($promise)
{ {
if ($promise instanceof \Generator) { if ($promise instanceof \Generator) {
@ -247,6 +257,7 @@ trait Tools
return $promise; return $promise;
} }
public function callFork($promise, $actual = null, $file = '') public function callFork($promise, $actual = null, $file = '')
{ {
if ($actual) { if ($actual) {
@ -271,12 +282,15 @@ trait Tools
} }
}); });
} }
return $promise; return $promise;
} }
public function callForkDefer($promise) public function callForkDefer($promise)
{ {
Loop::defer([$this, 'callFork'], $promise); Loop::defer([$this, 'callFork'], $promise);
} }
public function rethrow($e, $file = '') public function rethrow($e, $file = '')
{ {
$logger = isset($this->logger) ? $this->logger : Logger::$default; $logger = isset($this->logger) ? $this->logger : Logger::$default;
@ -287,6 +301,7 @@ trait Tools
$logger->logger((string) $e); $logger->logger((string) $e);
Promise\rethrow(new Failure($e)); Promise\rethrow(new Failure($e));
} }
public function after($a, $b) public function after($a, $b)
{ {
$a = $this->call($a()); $a = $this->call($a());
@ -311,6 +326,7 @@ trait Tools
{ {
return new \Amp\Delayed($time * 1000); return new \Amp\Delayed($time * 1000);
} }
public function is_array_or_alike($var) public function is_array_or_alike($var)
{ {
return is_array($var) || return is_array($var) ||

View File

@ -28,18 +28,22 @@ namespace danog\MadelineProto\VoIP;
trait AuthKeyHandler trait AuthKeyHandler
{ {
private $calls = []; private $calls = [];
public function request_call($user) public function request_call($user)
{ {
return $this->wait($this->request_call_async($user)); return $this->wait($this->request_call_async($user));
} }
public function accept_call($user) public function accept_call($user)
{ {
return $this->wait($this->accept_call_async($user)); return $this->wait($this->accept_call_async($user));
} }
public function discard_call($call, $reason, $rating = [], $need_debug = true) public function discard_call($call, $reason, $rating = [], $need_debug = true)
{ {
return $this->wait($this->discard_call_async($call, $reason, $rating, $need_debug)); return $this->wait($this->discard_call_async($call, $reason, $rating, $need_debug));
} }
public function request_call_async($user) public function request_call_async($user)
{ {
if (!class_exists('\\danog\\MadelineProto\\VoIP')) { if (!class_exists('\\danog\\MadelineProto\\VoIP')) {

View File

@ -20,27 +20,28 @@ namespace danog\MadelineProto;
if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
/** /**
* Manages storage of VoIP server config * Manages storage of VoIP server config.
*/ */
class VoIPServerConfig extends VoIPServerConfigInternal class VoIPServerConfig extends VoIPServerConfigInternal
{ {
/** /**
* The configuration * The configuration.
* *
* @var array * @var array
*/ */
private static $_config = []; private static $_config = [];
/** /**
* The default configuration * The default configuration.
* *
* @var array * @var array
*/ */
private static $_configDefault = []; private static $_configDefault = [];
/** /**
* Update shared call settings * Update shared call settings.
*
* @param array $config The settings
* *
* @param array $config The settings
* @return void * @return void
*/ */
public static function update(array $config) public static function update(array $config)
@ -48,8 +49,9 @@ if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
self::$_config = $config; self::$_config = $config;
self::updateInternal(self::getFinal()); self::updateInternal(self::getFinal());
} }
/** /**
* Get shared call settings * Get shared call settings.
* *
* @return array The settings * @return array The settings
*/ */
@ -59,9 +61,10 @@ if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
} }
/** /**
* Update default shared call settings * Update default shared call settings.
*
* @param array $configDefault The settings
* *
* @param array $configDefault The settings
* @return void * @return void
*/ */
public static function updateDefault(array $configDefault) public static function updateDefault(array $configDefault)
@ -69,8 +72,9 @@ if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
self::$_configDefault = $configDefault; self::$_configDefault = $configDefault;
self::updateInternal(self::getFinal()); self::updateInternal(self::getFinal());
} }
/** /**
* Get default shared call settings * Get default shared call settings.
* *
* @return array The settings * @return array The settings
*/ */
@ -80,7 +84,7 @@ if (class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
} }
/** /**
* Get final settings * Get final settings.
* *
* @return void * @return void
*/ */

View File

@ -42,6 +42,7 @@ trait ApiStart
$lines[count($lines) - 1] .= array_shift($chunk); $lines[count($lines) - 1] .= array_shift($chunk);
$lines = array_merge($lines, $chunk); $lines = array_merge($lines, $chunk);
} }
return array_shift($lines); return array_shift($lines);
}; };
echo 'You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a) echo 'You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a)
@ -96,7 +97,7 @@ Note that you can also provide the API parameters directly in the code using the
return yield $this->my_telegram_org_wrapper->get_app_async(); return yield $this->my_telegram_org_wrapper->get_app_async();
} }
yield $this->web_api_echo_async(); yield $this->web_api_echo_async();
} else if (isset($_POST['api_id']) && isset($_POST['api_hash'])) { } elseif (isset($_POST['api_id']) && isset($_POST['api_hash'])) {
$app['api_id'] = (int) $_POST['api_id']; $app['api_id'] = (int) $_POST['api_id'];
$app['api_hash'] = $_POST['api_hash']; $app['api_hash'] = $_POST['api_hash'];
$this->getting_api_id = false; $this->getting_api_id = false;

View File

@ -26,16 +26,19 @@ trait DialogHandler
if ($this->authorization['user']['bot']) { if ($this->authorization['user']['bot']) {
$res = []; $res = [];
foreach ($this->chats as $chat) { foreach ($this->chats as $chat) {
$res []= $this->gen_all($chat)['Peer']; $res[] = $this->gen_all($chat)['Peer'];
} }
return $res; return $res;
} }
$res = []; $res = [];
foreach (yield $this->get_full_dialogs_async($force) as $dialog) { foreach (yield $this->get_full_dialogs_async($force) as $dialog) {
$res []= $dialog['peer']; $res[] = $dialog['peer'];
} }
return $res; return $res;
} }
public function get_full_dialogs_async($force = true) public function get_full_dialogs_async($force = true)
{ {
if ($force || !isset($this->dialog_params['offset_date']) || is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || is_null($this->dialog_params['count'])) { if ($force || !isset($this->dialog_params['offset_date']) || is_null($this->dialog_params['offset_date']) || !isset($this->dialog_params['offset_id']) || is_null($this->dialog_params['offset_id']) || !isset($this->dialog_params['offset_peer']) || is_null($this->dialog_params['offset_peer']) || !isset($this->dialog_params['count']) || is_null($this->dialog_params['count'])) {
@ -48,45 +51,45 @@ trait DialogHandler
$datacenter = $this->datacenter->curdc; $datacenter = $this->datacenter->curdc;
$dialogs = []; $dialogs = [];
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getting_dialogs']); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['getting_dialogs']);
while ($this->dialog_params['count'] < $res['count']) { while ($this->dialog_params['count'] < $res['count']) {
$res = yield $this->method_call_async_read('messages.getDialogs', $this->dialog_params, ['datacenter' => $datacenter, 'FloodWaitLimit' => 100]); $res = yield $this->method_call_async_read('messages.getDialogs', $this->dialog_params, ['datacenter' => $datacenter, 'FloodWaitLimit' => 100]);
$last_peer = 0; $last_peer = 0;
$last_date = 0; $last_date = 0;
$last_id = 0; $last_id = 0;
$res['messages'] = array_reverse($res['messages']); $res['messages'] = array_reverse($res['messages']);
foreach (array_reverse($res['dialogs']) as $dialog) { foreach (array_reverse($res['dialogs']) as $dialog) {
$id = $this->get_id($dialog['peer']); $id = $this->get_id($dialog['peer']);
if (!isset($dialogs[$id])) { if (!isset($dialogs[$id])) {
$dialogs[$id] = $dialog; $dialogs[$id] = $dialog;
}
if (!$last_date) {
if (!$last_peer) {
$last_peer = $id;
} }
if (!$last_date) { if (!$last_id) {
if (!$last_peer) { $last_id = $dialog['top_message'];
$last_peer = $id; }
} foreach ($res['messages'] as $message) {
if (!$last_id) { if ($this->get_id($message) === $last_peer && $last_id === $message['id']) {
$last_id = $dialog['top_message']; $last_date = $message['date'];
} break;
foreach ($res['messages'] as $message) {
if ($this->get_id($message) === $last_peer && $last_id === $message['id']) {
$last_date = $message['date'];
break;
}
} }
} }
} }
if ($last_date) {
$this->dialog_params['offset_date'] = $last_date;
$this->dialog_params['offset_peer'] = $last_peer;
$this->dialog_params['offset_id'] = $last_id;
$this->dialog_params['count'] = count($dialogs);
} else {
break;
}
if (!isset($res['count'])) {
break;
}
} }
if ($last_date) {
$this->dialog_params['offset_date'] = $last_date;
$this->dialog_params['offset_peer'] = $last_peer;
$this->dialog_params['offset_id'] = $last_id;
$this->dialog_params['count'] = count($dialogs);
} else {
break;
}
if (!isset($res['count'])) {
break;
}
}
return $dialogs; return $dialogs;
} }

View File

@ -20,8 +20,6 @@
namespace danog\MadelineProto\Wrappers; namespace danog\MadelineProto\Wrappers;
use danog\MadelineProto\MTProtoTools\PasswordCalculator; use danog\MadelineProto\MTProtoTools\PasswordCalculator;
use danog\MadelineProto\VoIPServerConfig;
use function Amp\Promise\wait;
/** /**
* Manages logging in and out. * Manages logging in and out.
@ -103,7 +101,9 @@ trait Login
if ($e->rpc === 'SESSION_PASSWORD_NEEDED') { if ($e->rpc === 'SESSION_PASSWORD_NEEDED') {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_2fa_enabled'], \danog\MadelineProto\Logger::NOTICE); $this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_2fa_enabled'], \danog\MadelineProto\Logger::NOTICE);
$this->authorization = yield $this->method_call_async_read('account.getPassword', [], ['datacenter' => $this->datacenter->curdc]); $this->authorization = yield $this->method_call_async_read('account.getPassword', [], ['datacenter' => $this->datacenter->curdc]);
if (!isset($this->authorization['hint'])) $this->authorization['hint'] = ''; if (!isset($this->authorization['hint'])) {
$this->authorization['hint'] = '';
}
$this->authorized = self::WAITING_PASSWORD; $this->authorized = self::WAITING_PASSWORD;
return $this->authorization; return $this->authorization;
@ -159,6 +159,7 @@ trait Login
$res = yield $this->get_self_async(); $res = yield $this->get_self_async();
$this->startUpdateSystem(); $this->startUpdateSystem();
return $res; return $res;
} }

View File

@ -19,7 +19,6 @@
namespace danog\MadelineProto\Wrappers; namespace danog\MadelineProto\Wrappers;
use Amp\Deferred;
use Amp\Promise; use Amp\Promise;
/** /**
@ -38,14 +37,17 @@ trait Loop
{ {
if (is_callable($max_forks)) { if (is_callable($max_forks)) {
$this->logger->logger('Running async callable'); $this->logger->logger('Running async callable');
return yield $max_forks(); return yield $max_forks();
} }
if ($max_forks instanceof Promise) { if ($max_forks instanceof Promise) {
$this->logger->logger('Resolving async promise'); $this->logger->logger('Resolving async promise');
return yield $max_forks; return yield $max_forks;
} }
if (in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler'])) { if (in_array($this->settings['updates']['callback'], [['danog\\MadelineProto\\API', 'get_updates_update_handler'], 'get_updates_update_handler'])) {
$this->logger->logger('Getupdates event handler is enabled, exiting from loop', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Getupdates event handler is enabled, exiting from loop', \danog\MadelineProto\Logger::FATAL_ERROR);
return false; return false;
} }
if (!is_callable($this->loop_callback) || (is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !method_exists(...$this->loop_callback))) { if (!is_callable($this->loop_callback) || (is_array($this->loop_callback) && $this->loop_callback[1] === 'onLoop' && !method_exists(...$this->loop_callback))) {
@ -53,6 +55,7 @@ trait Loop
} }
if (php_sapi_name() !== 'cli') { if (php_sapi_name() !== 'cli') {
$needs_restart = true; $needs_restart = true;
try { try {
set_time_limit(-1); set_time_limit(-1);
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
@ -61,13 +64,13 @@ trait Loop
$this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart'); $this->logger->logger($needs_restart ? 'Will self-restart' : 'Will not self-restart');
$backtrace = debug_backtrace(0); $backtrace = debug_backtrace(0);
$lockfile = dirname(end($backtrace)['file']) . '/bot.lock'; $lockfile = dirname(end($backtrace)['file']).'/bot.lock';
unset($backtrace); unset($backtrace);
$try_locking = true; $try_locking = true;
if (!file_exists($lockfile)) { if (!file_exists($lockfile)) {
touch($lockfile); touch($lockfile);
$lock = fopen('bot.lock', 'r+'); $lock = fopen('bot.lock', 'r+');
} else if (isset($GLOBALS['lock'])) { } elseif (isset($GLOBALS['lock'])) {
$try_locking = false; $try_locking = false;
$lock = $GLOBALS['lock']; $lock = $GLOBALS['lock'];
} else { } else {
@ -79,7 +82,7 @@ trait Loop
while (!$locked) { while (!$locked) {
$locked = flock($lock, LOCK_EX | LOCK_NB); $locked = flock($lock, LOCK_EX | LOCK_NB);
if (!$locked) { if (!$locked) {
$this->closeConnection("Bot is already running"); $this->closeConnection('Bot is already running');
if ($try++ >= 30) { if ($try++ >= 30) {
exit; exit;
} }
@ -92,13 +95,13 @@ trait Loop
flock($lock, LOCK_UN); flock($lock, LOCK_UN);
fclose($lock); fclose($lock);
if ($needs_restart) { if ($needs_restart) {
$a = fsockopen((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp') . '://' . $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT']); $a = fsockopen((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'tls' : 'tcp').'://'.$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT']);
fwrite($a, $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['SERVER_PROTOCOL'] . "\r\n" . 'Host: ' . $_SERVER['SERVER_NAME'] . "\r\n\r\n"); fwrite($a, $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n".'Host: '.$_SERVER['SERVER_NAME']."\r\n\r\n");
$this->logger->logger("Self-restarted"); $this->logger->logger('Self-restarted');
} }
}); });
$this->closeConnection("Bot was started"); $this->closeConnection('Bot was started');
} }
if (!$this->settings['updates']['handle_updates']) { if (!$this->settings['updates']['handle_updates']) {
$this->settings['updates']['handle_updates'] = true; $this->settings['updates']['handle_updates'] = true;
@ -133,6 +136,7 @@ trait Loop
yield $this->waitUpdate(); yield $this->waitUpdate();
} }
} }
public function closeConnection($message = 'OK!') public function closeConnection($message = 'OK!')
{ {
if (php_sapi_name() === 'cli' || isset($GLOBALS['exited']) || headers_sent()) { if (php_sapi_name() === 'cli' || isset($GLOBALS['exited']) || headers_sent()) {
@ -143,7 +147,7 @@ trait Loop
header('Connection: close'); header('Connection: close');
ignore_user_abort(true); ignore_user_abort(true);
ob_start(); ob_start();
echo '<html><body><h1>' . $message . '</h1></body</html>'; echo '<html><body><h1>'.$message.'</h1></body</html>';
$size = ob_get_length(); $size = ob_get_length();
header("Content-Length: $size"); header("Content-Length: $size");
header('Content-Type: text/html'); header('Content-Type: text/html');

View File

@ -45,6 +45,7 @@ trait Start
$lines[count($lines) - 1] .= array_shift($chunk); $lines[count($lines) - 1] .= array_shift($chunk);
$lines = array_merge($lines, $chunk); $lines = array_merge($lines, $chunk);
} }
return array_shift($lines); return array_shift($lines);
}; };
if (strpos(yield $readline('Do you want to login as user or bot (u/b)? '), 'b') !== false) { if (strpos(yield $readline('Do you want to login as user or bot (u/b)? '), 'b') !== false) {

View File

@ -15,16 +15,16 @@ final class APITest extends TestCase
$MadelineProto = new \danog\MadelineProto\API( $MadelineProto = new \danog\MadelineProto\API(
[ [
'app_info' => [ 'app_info' => [
'api_id' => 25628, 'api_id' => 25628,
'api_hash' => '1fe17cda7d355166cdaa71f04122873c' 'api_hash' => '1fe17cda7d355166cdaa71f04122873c',
], ],
'connection_settings' => [ 'connection_settings' => [
'all' => [ 'all' => [
'ipv6' => $ipv6, 'ipv6' => $ipv6,
'test_mode' => $test_mode, 'test_mode' => $test_mode,
'protocol' => $protocol, 'protocol' => $protocol,
'obfuscated' => $obfuscated, 'obfuscated' => $obfuscated,
'transport' => $transport, 'transport' => $transport,
], ],
], ],
] ]
@ -33,6 +33,7 @@ final class APITest extends TestCase
$this->assertContainsEquals('_', $pong, 'pong'); $this->assertContainsEquals('_', $pong, 'pong');
$this->assertContainsEquals('ping_id', $pong, $ping['ping_id']); $this->assertContainsEquals('ping_id', $pong, $ping['ping_id']);
} }
public function protocolProvider(): \Generator public function protocolProvider(): \Generator
{ {
foreach ([false, true] as $test_mode) { foreach ([false, true] as $test_mode) {
@ -43,7 +44,9 @@ final class APITest extends TestCase
continue; continue;
} }
foreach (['tcp_abridged', 'tcp_intermediate', 'tcp_intermediate_padded', 'tcp_full'] as $protocol) { foreach (['tcp_abridged', 'tcp_intermediate', 'tcp_intermediate_padded', 'tcp_full'] as $protocol) {
if ($protocol === 'tcp_full' && $obfuscated) continue; if ($protocol === 'tcp_full' && $obfuscated) {
continue;
}
yield [$transport, $obfuscated, $protocol, $test_mode, $ipv6]; yield [$transport, $obfuscated, $protocol, $test_mode, $ipv6];
} }
} }

View File

@ -83,7 +83,7 @@ foreach (\danog\MadelineProto\Lang::$current_lang as $key => $value) {
if (!$param_name && strpos($key, 'object_') === 0) { if (!$param_name && strpos($key, 'object_') === 0) {
$value = str_replace('Update ', '', $value).' update'; $value = str_replace('Update ', '', $value).' update';
} }
//} elseif (ctype_lower($value[0])) { //} elseif (ctype_lower($value[0])) {
} else { } else {
\danog\MadelineProto\Lang::$lang[$lang_code][$key] = readline($value.' => '); \danog\MadelineProto\Lang::$lang[$lang_code][$key] = readline($value.' => ');
if (\danog\MadelineProto\Lang::$lang[$lang_code][$key] === '') { if (\danog\MadelineProto\Lang::$lang[$lang_code][$key] === '') {