Major fixes and refactoring of wrapper APIs
This commit is contained in:
parent
46c4e222db
commit
b339a9d849
@ -1,6 +1,6 @@
|
||||
language: php
|
||||
php:
|
||||
- '7.1'
|
||||
- '7.4'
|
||||
before_install:
|
||||
- echo "phar.readonly = 0" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
"vlucas/phpdotenv": "^3",
|
||||
"erusev/parsedown": "^1.6",
|
||||
"rollbar/rollbar": "dev-master",
|
||||
"ext-curl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-json": "*",
|
||||
"ext-xml": "*",
|
||||
@ -28,7 +27,8 @@
|
||||
"amphp/websocket-client": "dev-master",
|
||||
"amphp/artax": "^3.0",
|
||||
"amphp/file": "^0.3.5",
|
||||
"amphp/uri": "^0.1.4"
|
||||
"amphp/uri": "^0.1.4",
|
||||
"amphp/byte-stream": "dev-master#bc191a8 as 1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpdocumentor/reflection-docblock": "^3.1",
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$MadelineProto = new \danog\MadelineProto\API('sessionf.madeline');
|
||||
$MadelineProto = new \danog\MadelineProto\API('session.madeline');
|
||||
$me = $MadelineProto->start();
|
||||
|
||||
$me = $MadelineProto->get_self();
|
||||
|
@ -29,7 +29,7 @@ if (!isset($backtrace[0]["file"]) || !in_array(basename($backtrace[0]["file"]),
|
||||
die("madeline.phar cannot be required manually: use the automatic loader, instead: https://docs.madelineproto.xyz/docs/INSTALLATION.html#simple".PHP_EOL);
|
||||
}
|
||||
if (isset($backtrace[1]["file"])) {
|
||||
chdir(dirname($backtrace[1]["file"]));
|
||||
@chdir(dirname($backtrace[1]["file"]));
|
||||
}
|
||||
if ($contents = file_get_contents("https://phar.madelineproto.xyz/phar.php?v=new")) {
|
||||
file_put_contents($backtrace[0]["file"], $contents);
|
||||
|
@ -92,7 +92,7 @@ class EventHandler extends \danog\MadelineProto\EventHandler
|
||||
|
||||
if (file_exists('.env')) {
|
||||
echo 'Loading .env...'.PHP_EOL;
|
||||
$dotenv = new Dotenv\Dotenv(getcwd());
|
||||
$dotenv = Dotenv\Dotenv::create(getcwd());
|
||||
$dotenv->load();
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
use Amp\Deferred;
|
||||
|
||||
class API extends APIFactory
|
||||
{
|
||||
use \danog\Serializable;
|
||||
@ -29,11 +31,21 @@ class API extends APIFactory
|
||||
public $API;
|
||||
public $getting_api_id = false;
|
||||
public $my_telegram_org_wrapper;
|
||||
public $asyncAPIPromise;
|
||||
|
||||
public function __magic_construct($params = [], $settings = [])
|
||||
{
|
||||
Magic::class_exists();
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
$deferred = new Deferred;
|
||||
$this->asyncAPIPromise = $deferred->promise();
|
||||
$this->asyncAPIPromise->onResolve(function () {
|
||||
$this->asyncAPIPromise = null;
|
||||
});
|
||||
$this->setInitPromise($this->__construct_async($params, $settings, $deferred));
|
||||
}
|
||||
public function __construct_async($params, $settings, $deferred)
|
||||
{
|
||||
if (is_string($params)) {
|
||||
$realpaths = Serialization::realpaths($params);
|
||||
$this->session = $realpaths['file'];
|
||||
@ -62,7 +74,7 @@ class API extends APIFactory
|
||||
class_exists('\\Volatile');
|
||||
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
||||
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||
class_exists('\\danog\\MadelineProto\\' . $class);
|
||||
class_exists('\\danog\\MadelineProto\\'.$class);
|
||||
}
|
||||
$unserialized = \danog\Serialization::unserialize($tounserialize);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
@ -72,11 +84,11 @@ class API extends APIFactory
|
||||
if (defined('MADELINEPROTO_TEST') && MADELINEPROTO_TEST === 'pony') {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
|
||||
class_exists('\\Volatile');
|
||||
$tounserialize = str_replace('O:26:"danog\\MadelineProto\\Button":', 'O:35:"danog\\MadelineProto\\TL\\Types\\Button":', $tounserialize);
|
||||
foreach (['RSA', 'TL\\TLMethod', 'TL\\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection', 'TL\\Types\\Button', 'TL\\Types\\Bytes', 'APIFactory'] as $class) {
|
||||
class_exists('\\danog\\MadelineProto\\' . $class);
|
||||
class_exists('\\danog\\MadelineProto\\'.$class);
|
||||
}
|
||||
Logger::log((string) $e, Logger::ERROR);
|
||||
if (strpos($e->getMessage(), "Erroneous data format for unserializing 'phpseclib\\Math\\BigInteger'") === 0) {
|
||||
@ -96,16 +108,15 @@ class API extends APIFactory
|
||||
|
||||
if (isset($unserialized->API)) {
|
||||
$this->API = $unserialized->API;
|
||||
$this->callFork((function () {
|
||||
yield $this->API->asyncInitPromise;
|
||||
$this->API->asyncInitPromise = null;
|
||||
$this->APIFactory();
|
||||
\danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE);
|
||||
$pong = yield $this->ping(['ping_id' => 3], ['async' => true]);
|
||||
\danog\MadelineProto\Logger::log('Pong: ' . $pong['ping_id'], Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
|
||||
})());
|
||||
$this->APIFactory();
|
||||
$deferred->resolve();
|
||||
yield $this->API->initAsync();
|
||||
$this->APIFactory();
|
||||
\danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE);
|
||||
$this->asyncInitPromise = null;
|
||||
$pong = yield $this->ping(['ping_id' => 3], ['async' => true]);
|
||||
\danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -113,34 +124,31 @@ class API extends APIFactory
|
||||
$params = $settings;
|
||||
}
|
||||
if (!isset($params['app_info']['api_id']) || !$params['app_info']['api_id']) {
|
||||
$app = $this->api_start();
|
||||
$app = yield $this->api_start_async($params);
|
||||
$params['app_info']['api_id'] = $app['api_id'];
|
||||
$params['app_info']['api_hash'] = $app['api_hash'];
|
||||
}
|
||||
$this->API = new MTProto($params);
|
||||
$this->APIFactory();
|
||||
$deferred->resolve();
|
||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['apifactory_start'], Logger::VERBOSE);
|
||||
$this->callFork((function () {
|
||||
yield $this->API->asyncInitPromise;
|
||||
$this->API->asyncInitPromise = null;
|
||||
$this->APIFactory();
|
||||
\danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE);
|
||||
$pong = yield $this->ping(['ping_id' => 3], ['async' => true]);
|
||||
\danog\MadelineProto\Logger::log('Pong: ' . $pong['ping_id'], Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
|
||||
})());
|
||||
$this->APIFactory();
|
||||
yield $this->API->initAsync();
|
||||
$this->APIFactory();
|
||||
$this->asyncInitPromise = null;
|
||||
\danog\MadelineProto\Logger::log('Ping...', Logger::ULTRA_VERBOSE);
|
||||
$pong = yield $this->ping(['ping_id' => 3], ['async' => true]);
|
||||
\danog\MadelineProto\Logger::log('Pong: '.$pong['ping_id'], Logger::ULTRA_VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['madelineproto_ready'], Logger::NOTICE);
|
||||
}
|
||||
|
||||
public function async($async)
|
||||
{
|
||||
$this->async = $async;
|
||||
foreach ($this->API->get_methods_namespaced() as $pair) {
|
||||
$namespace = key($pair);
|
||||
$this->{$namespace}->async = $async;
|
||||
}
|
||||
|
||||
if ($this->API->event_handler && class_exists($this->API->event_handler) && is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
||||
$this->API->setEventHandler($this->API->event_handler);
|
||||
if ($this->API) {
|
||||
if ($this->API->event_handler && class_exists($this->API->event_handler) && is_subclass_of($this->API->event_handler, '\danog\MadelineProto\EventHandler')) {
|
||||
$this->API->setEventHandler($this->API->event_handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +162,10 @@ class API extends APIFactory
|
||||
if (\danog\MadelineProto\Magic::$has_thread && is_object(\Thread::getCurrentThread()) || Magic::is_fork()) {
|
||||
return;
|
||||
}
|
||||
$this->serialize();
|
||||
if ($this->asyncInitPromise) {
|
||||
$this->init();
|
||||
}
|
||||
$this->wait($this->serialize());
|
||||
//restore_error_handler();
|
||||
}
|
||||
|
||||
@ -163,49 +174,6 @@ class API extends APIFactory
|
||||
return ['API', 'web_api_template', 'getting_api_id', 'my_telegram_org_wrapper'];
|
||||
}
|
||||
|
||||
public function &__get($name)
|
||||
{
|
||||
if ($name === 'settings') {
|
||||
$this->API->setdem = true;
|
||||
|
||||
return $this->API->settings;
|
||||
}
|
||||
|
||||
return $this->API->storage[$name];
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if ($name === 'settings') {
|
||||
if ($this->API->phoneConfigWatcherId) {
|
||||
$this->wait($this->API->phoneConfigWatcherId);
|
||||
$this->API->phoneConfigWatcherId = null;
|
||||
}
|
||||
if (Magic::is_fork() && !Magic::$processed_fork) {
|
||||
\danog\MadelineProto\Logger::log('Detected fork');
|
||||
$this->API->reset_session();
|
||||
foreach ($this->API->datacenter->sockets as $id => $datacenter) {
|
||||
$this->API->close_and_reopen($id);
|
||||
}
|
||||
Magic::$processed_fork = true;
|
||||
}
|
||||
|
||||
return $this->API->__construct(array_replace_recursive($this->API->settings, $value));
|
||||
}
|
||||
|
||||
return $this->API->storage[$name] = $value;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
unset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
private function from_camel_case($input)
|
||||
{
|
||||
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
|
||||
@ -221,10 +189,10 @@ class API extends APIFactory
|
||||
{
|
||||
if ($this->API) {
|
||||
foreach ($this->API->get_method_namespaces() as $namespace) {
|
||||
$this->{$namespace} = new APIFactory($namespace, $this->API);
|
||||
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
|
||||
}
|
||||
$methods = get_class_methods($this->API);
|
||||
foreach ($methods as $key => $method) {
|
||||
foreach ($methods as $method) {
|
||||
if ($method == 'method_call_async_read') {
|
||||
unset($methods[array_search('method_call', $methods)]);
|
||||
} elseif (stripos($method, 'async') !== false) {
|
||||
@ -266,6 +234,9 @@ class API extends APIFactory
|
||||
|
||||
public function get_all_methods()
|
||||
{
|
||||
if ($this->asyncInitPromise) {
|
||||
$this->init();
|
||||
}
|
||||
$methods = [];
|
||||
foreach ($this->API->methods->by_id as $method) {
|
||||
$methods[] = $method['method'];
|
||||
@ -274,16 +245,64 @@ class API extends APIFactory
|
||||
return array_merge($methods, get_class_methods($this->API));
|
||||
}
|
||||
|
||||
public function serialize($params = null)
|
||||
public function serialize($filename = null)
|
||||
{
|
||||
if ($params === null) {
|
||||
$params = $this->session;
|
||||
}
|
||||
if (empty($params)) {
|
||||
return;
|
||||
}
|
||||
Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']);
|
||||
return $this->callFork((function () use ($filename) {
|
||||
if ($filename === null) {
|
||||
$filename = $this->session;
|
||||
}
|
||||
if (empty($filename)) {
|
||||
return;
|
||||
}
|
||||
Logger::log(\danog\MadelineProto\Lang::$current_lang['serializing_madelineproto']);
|
||||
|
||||
return Serialization::serialize($params, $this);
|
||||
if ($filename == '') {
|
||||
throw new \danog\MadelineProto\Exception('Empty filename');
|
||||
}
|
||||
if (isset($this->API->setdem) && $this->API->setdem) {
|
||||
$this->API->setdem = false;
|
||||
$this->API->__construct($this->API->settings);
|
||||
}
|
||||
if ($this->API === null && !$this->getting_api_id) {
|
||||
return false;
|
||||
}
|
||||
if ($this->API && $this->API->asyncInitPromise) {
|
||||
yield $this->API->initAsync();
|
||||
}
|
||||
$this->serialized = time();
|
||||
$realpaths = Serialization::realpaths($filename);
|
||||
if (!file_exists($realpaths['lockfile'])) {
|
||||
touch($realpaths['lockfile']);
|
||||
clearstatcache();
|
||||
}
|
||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'w');
|
||||
\danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
||||
flock($realpaths['lockfile'], LOCK_EX);
|
||||
\danog\MadelineProto\Logger::log('Lock acquired, serializing');
|
||||
|
||||
try {
|
||||
if (!$this->getting_api_id) {
|
||||
$update_closure = $this->API->settings['updates']['callback'];
|
||||
if ($this->API->settings['updates']['callback'] instanceof \Closure) {
|
||||
$this->API->settings['updates']['callback'] = [$this->API, 'noop'];
|
||||
}
|
||||
$logger_closure = $this->API->settings['logger']['logger_param'];
|
||||
if ($this->API->settings['logger']['logger_param'] instanceof \Closure) {
|
||||
$this->API->settings['logger']['logger_param'] = [$this->API, 'noop'];
|
||||
}
|
||||
}
|
||||
$wrote = file_put_contents($realpaths['tempfile'], serialize($this));
|
||||
rename($realpaths['tempfile'], $realpaths['file']);
|
||||
} finally {
|
||||
if (!$this->getting_api_id) {
|
||||
$this->API->settings['updates']['callback'] = $update_closure;
|
||||
$this->API->settings['logger']['logger_param'] = $logger_closure;
|
||||
}
|
||||
flock($realpaths['lockfile'], LOCK_UN);
|
||||
fclose($realpaths['lockfile']);
|
||||
}
|
||||
|
||||
return $wrote;
|
||||
})());
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,9 @@
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
use Amp\Promise;
|
||||
use danog\MadelineProto\Async\AsyncConstruct;
|
||||
|
||||
class APIFactory
|
||||
class APIFactory extends AsyncConstruct
|
||||
{
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
@ -119,126 +120,121 @@ class APIFactory
|
||||
public $API;
|
||||
public $lua = false;
|
||||
public $async = false;
|
||||
public $asyncAPIPromise;
|
||||
|
||||
protected $methods = [];
|
||||
|
||||
public function __construct($namespace, $API)
|
||||
public function __construct($namespace, $API, &$async)
|
||||
{
|
||||
$this->namespace = $namespace . '.';
|
||||
$this->namespace = $namespace.'.';
|
||||
$this->API = $API;
|
||||
$this->async = &$async;
|
||||
}
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
$yielded = $this->__call_async($name, $arguments);
|
||||
$async = $this->lua === false && (is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop'));
|
||||
if ($async) {
|
||||
return $yielded;
|
||||
}
|
||||
if (!$this->lua) {
|
||||
return $this->wait($yielded);
|
||||
}
|
||||
|
||||
try {
|
||||
$yielded = $this->wait($yielded);
|
||||
Lua::convert_objects($yielded);
|
||||
|
||||
return $yielded;
|
||||
} catch (\Throwable $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
public function __call_async($name, $arguments)
|
||||
{
|
||||
if ($this->asyncInitPromise) {
|
||||
yield $this->initAsync();
|
||||
}
|
||||
if (Magic::is_fork() && !Magic::$processed_fork) {
|
||||
\danog\MadelineProto\Logger::log('Detected fork');
|
||||
$this->API->reset_session();
|
||||
foreach ($this->API->datacenter->sockets as $id => $datacenter) {
|
||||
$this->API->close_and_reopen($id);
|
||||
foreach ($this->API->datacenter->sockets as $datacenter) {
|
||||
yield $datacenter->reconnect();
|
||||
}
|
||||
Magic::$processed_fork = true;
|
||||
}
|
||||
|
||||
if ($this->API->setdem) {
|
||||
$this->API->setdem = false;
|
||||
$this->API->__construct($this->API->settings);
|
||||
}
|
||||
//$this->API->get_config([], ['datacenter' => $this->API->datacenter->curdc]);
|
||||
|
||||
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...");
|
||||
$this->serialize($this->session);
|
||||
}
|
||||
/*
|
||||
if ($name !== 'accept_tos' && $name !== 'decline_tos') {
|
||||
$this->API->check_tos();
|
||||
}*/
|
||||
if ($this->API->setdem) {
|
||||
$this->API->setdem = false;
|
||||
$this->API->__construct($this->API->settings);
|
||||
yield $this->API->initAsync();
|
||||
}
|
||||
if ($this->API->asyncInitPromise) {
|
||||
yield $this->API->initAsync();
|
||||
}
|
||||
|
||||
$lower_name = strtolower($name);
|
||||
if ($this->namespace !== '' || !isset($this->methods[$lower_name])) {
|
||||
$name = $this->namespace.$name;
|
||||
$aargs = isset($arguments[1]) && is_array($arguments[1]) ? $arguments[1] : [];
|
||||
$aargs['apifactory'] = true;
|
||||
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
||||
$args = isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [];
|
||||
|
||||
if ($this->lua === false) {
|
||||
return $this->namespace !== '' || !isset($this->methods[$lower_name]) ? $this->__mtproto_call($this->namespace . $name, $arguments) : $this->__api_call($lower_name, $arguments);
|
||||
}
|
||||
|
||||
try {
|
||||
$deserialized = $this->namespace !== '' || !isset($this->methods[$lower_name]) ? $this->__mtproto_call($this->namespace . $name, $arguments) : $this->__api_call($lower_name, $arguments);
|
||||
|
||||
Lua::convert_objects($deserialized);
|
||||
|
||||
return $deserialized;
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
} catch (\danog\MadelineProto\TL\Exception $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
} catch (\danog\MadelineProto\PTSException $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
} catch (\danog\MadelineProto\SecurityException $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
} catch (\danog\MadelineProto\TL\Conversion\Exception $e) {
|
||||
return ['error_code' => $e->getCode(), 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
public function __api_call($name, $arguments)
|
||||
{
|
||||
if ($this->API->asyncInitPromise) {
|
||||
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop');
|
||||
if ($async) {
|
||||
return $this->call((function () use ($name, $arguments) {
|
||||
yield $this->API->asyncInitPromise;
|
||||
$this->API->asyncInitPromise = null;
|
||||
return yield $this->methods[$name](...$arguments);
|
||||
})());
|
||||
} else {
|
||||
$this->wait($this->API->asyncInitPromise);
|
||||
$this->API->asyncInitPromise = null;
|
||||
}
|
||||
}
|
||||
$result = $this->methods[$name](...$arguments);
|
||||
if (is_object($result) && ($result instanceof \Generator || $result instanceof Promise)) {
|
||||
$async = is_array(end($arguments)) && isset(end($arguments)['async']) ? end($arguments)['async'] : ($this->async && $name !== 'loop');
|
||||
if ($async) {
|
||||
return $result;
|
||||
} else {
|
||||
return $this->wait($result);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function __mtproto_call($name, $arguments)
|
||||
{
|
||||
$aargs = isset($arguments[1]) && is_array($arguments[1]) ? $arguments[1] : [];
|
||||
$aargs['apifactory'] = true;
|
||||
$args = isset($arguments[0]) && is_array($arguments[0]) ? $arguments[0] : [];
|
||||
|
||||
$async = isset(end($arguments)['async']) ? end($arguments)['async'] : $this->async;
|
||||
|
||||
if ($this->API->asyncInitPromise) {
|
||||
if ($async) {
|
||||
return $this->call((function () use ($name, $args, $aargs) {
|
||||
yield $this->API->asyncInitPromise;
|
||||
$this->API->asyncInitPromise = null;
|
||||
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
||||
return yield $this->API->method_call_async_read($name, $args, $aargs);
|
||||
;
|
||||
})());
|
||||
} else {
|
||||
$this->wait($this->API->asyncInitPromise);
|
||||
$this->API->asyncInitPromise = null;
|
||||
}
|
||||
}
|
||||
$aargs['datacenter'] = $this->API->datacenter->curdc;
|
||||
$res = $this->API->method_call_async_read($name, $args, $aargs);
|
||||
|
||||
if ($async) {
|
||||
return $res;
|
||||
return yield $this->API->method_call_async_read($name, $args, $aargs);
|
||||
} else {
|
||||
return $this->wait($res);
|
||||
return yield $this->methods[$lower_name](...$arguments);
|
||||
}
|
||||
}
|
||||
|
||||
public function &__get($name)
|
||||
{
|
||||
if ($this->asyncAPIPromise) {
|
||||
$this->wait($this->asyncAPIPromise);
|
||||
}
|
||||
if ($name === 'settings') {
|
||||
$this->API->setdem = true;
|
||||
|
||||
return $this->API->settings;
|
||||
}
|
||||
|
||||
return $this->API->storage[$name];
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if ($this->asyncAPIPromise) {
|
||||
$this->wait($this->asyncAPIPromise);
|
||||
}
|
||||
if ($name === 'settings') {
|
||||
if ($this->API->asyncInitPromise) {
|
||||
$this->API->init();
|
||||
}
|
||||
return $this->API->__construct(array_replace_recursive($this->API->settings, $value));
|
||||
}
|
||||
|
||||
return $this->API->storage[$name] = $value;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
if ($this->asyncAPIPromise) {
|
||||
$this->wait($this->asyncAPIPromise);
|
||||
}
|
||||
return isset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
if ($this->asyncAPIPromise) {
|
||||
$this->wait($this->asyncAPIPromise);
|
||||
}
|
||||
unset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
}
|
||||
|
53
src/danog/MadelineProto/Async/AsyncConstruct.php
Normal file
53
src/danog/MadelineProto/Async/AsyncConstruct.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Async constructor abstract class.
|
||||
*
|
||||
* This file is part of MadelineProto.
|
||||
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @copyright 2016-2018 Daniil Gentili <daniil@daniil.it>
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
|
||||
*
|
||||
* @link https://docs.madelineproto.xyz MadelineProto documentation
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto\Async;
|
||||
|
||||
use danog\MadelineProto\Tools;
|
||||
|
||||
/**
|
||||
* Async constructor class.
|
||||
*
|
||||
* Manages asynchronous construction and wakeup of classes
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class AsyncConstruct
|
||||
{
|
||||
use Tools;
|
||||
public $asyncInitPromise;
|
||||
public function init()
|
||||
{
|
||||
if ($this->asyncInitPromise) {
|
||||
$this->wait($this->asyncInitPromise);
|
||||
}
|
||||
}
|
||||
public function initAsync()
|
||||
{
|
||||
if ($this->asyncInitPromise) {
|
||||
yield $this->asyncInitPromise;
|
||||
}
|
||||
}
|
||||
public function setInitPromise($promise)
|
||||
{
|
||||
$this->asyncInitPromise = $this->call($promise);
|
||||
$this->asyncInitPromise->onResolve(function () {
|
||||
$this->asyncInitPromise = null;
|
||||
});
|
||||
}
|
||||
}
|
@ -94,7 +94,6 @@ class Connection
|
||||
return $this->ctx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Connect function.
|
||||
*
|
||||
@ -157,7 +156,6 @@ class Connection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function sendMessage($message, $flush = true)
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
@ -201,6 +199,7 @@ class Connection
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
$this->API->logger->logger("Disconnecting from DC {$this->datacenter}");
|
||||
$this->old = true;
|
||||
foreach (['reader', 'writer', 'checker', 'waiter', 'updater'] as $loop) {
|
||||
if (isset($this->{$loop}) && $this->{$loop}) {
|
||||
@ -210,6 +209,7 @@ class Connection
|
||||
if ($this->stream) {
|
||||
$this->stream->disconnect();
|
||||
}
|
||||
$this->API->logger->logger("Disconnected from DC {$this->datacenter}");
|
||||
}
|
||||
|
||||
public function reconnect(): \Generator
|
||||
@ -226,12 +226,17 @@ class Connection
|
||||
|
||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
||||
$timeout = $API->settings['connection_settings'][$dc_config_number]['timeout'];
|
||||
$pfs = $API->settings['connection_settings'][$dc_config_number]['pfs'];
|
||||
|
||||
foreach ($this->new_outgoing as $message_id) {
|
||||
if (isset($this->outgoing_messages[$message_id]['sent'])
|
||||
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < time()
|
||||
&& ($this->temp_auth_key === null) === $this->outgoing_messages[$message_id]['unencrypted']
|
||||
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
||||
) {
|
||||
if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -239,6 +244,33 @@ class Connection
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getPendingCalls()
|
||||
{
|
||||
$API = $this->API;
|
||||
$datacenter = $this->datacenter;
|
||||
|
||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
||||
$timeout = $API->settings['connection_settings'][$dc_config_number]['timeout'];
|
||||
$pfs = $API->settings['connection_settings'][$dc_config_number]['pfs'];
|
||||
|
||||
$result = [];
|
||||
foreach ($this->new_outgoing as $message_id) {
|
||||
if (isset($this->outgoing_messages[$message_id]['sent'])
|
||||
&& $this->outgoing_messages[$message_id]['sent'] + $timeout < time()
|
||||
&& ($this->temp_auth_key === null) === $this->outgoing_messages[$message_id]['unencrypted']
|
||||
&& $this->outgoing_messages[$message_id]['_'] !== 'msgs_state_req'
|
||||
) {
|
||||
if ($pfs && !isset($this->temp_auth_key['bound']) && $this->outgoing_messages[$message_id]['_'] !== 'auth.bindTempAuthKey') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[] = $message_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return __CLASS__;
|
||||
|
@ -38,6 +38,7 @@ use danog\MadelineProto\Stream\Transport\DefaultStream;
|
||||
use danog\MadelineProto\Stream\Transport\WssStream;
|
||||
use danog\MadelineProto\Stream\Transport\WsStream;
|
||||
use danog\MadelineProto\TL\Conversion\Exception;
|
||||
use Amp\Artax\Cookie\ArrayCookieJar;
|
||||
|
||||
/**
|
||||
* Manages datacenters.
|
||||
@ -67,12 +68,13 @@ class DataCenter
|
||||
if ($socket instanceof Connection && !strpos($key, '_bk')) {
|
||||
$this->API->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['dc_con_stop'], $key), \danog\MadelineProto\Logger::VERBOSE);
|
||||
$socket->old = true;
|
||||
$socket->setExtra($this->API);
|
||||
$socket->disconnect();
|
||||
} else {
|
||||
unset($this->sockets[$key]);
|
||||
}
|
||||
}
|
||||
$this->HTTPClient = new DefaultClient(null, 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
|
||||
{
|
||||
@ -170,10 +172,10 @@ class DataCenter
|
||||
default:
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_invalid']);
|
||||
}
|
||||
if ($this->settings[$dc_config_number]['obfuscated'] && !in_array($default[1][0], [HttpsStream::getName(), HttpStream::getName()])) {
|
||||
if ($this->settings[$dc_config_number]['obfuscated'] && !in_array($default[2][0], [HttpsStream::getName(), HttpStream::getName()])) {
|
||||
$default = [[DefaultStream::getName(), []], [BufferedRawStream::getName(), []], [ObfuscatedStream::getName(), []], end($default)];
|
||||
}
|
||||
if ($this->settings[$dc_config_number]['transport'] && !in_array($default[1][0], [HttpsStream::getName(), HttpStream::getName()])) {
|
||||
if ($this->settings[$dc_config_number]['transport'] && !in_array($default[2][0], [HttpsStream::getName(), HttpStream::getName()])) {
|
||||
switch ($this->settings[$dc_config_number]['transport']) {
|
||||
case 'tcp':
|
||||
if ($this->settings[$dc_config_number]['obfuscated']) {
|
||||
|
@ -24,54 +24,10 @@ class EventHandler extends APIFactory
|
||||
public function __construct($MadelineProto)
|
||||
{
|
||||
$this->API = $MadelineProto->API;
|
||||
$this->async = $MadelineProto->async;
|
||||
$this->methods = $MadelineProto->methods;
|
||||
$this->async = &$MadelineProto->async;
|
||||
$this->methods = &$MadelineProto->methods;
|
||||
foreach ($this->API->get_method_namespaces() as $namespace) {
|
||||
$this->{$namespace} = new APIFactory($namespace, $this->API);
|
||||
$this->{$namespace}->async = $MadelineProto->async;
|
||||
$this->{$namespace} = new APIFactory($namespace, $this->API, $this->async);
|
||||
}
|
||||
}
|
||||
|
||||
public function &__get($name)
|
||||
{
|
||||
if ($name === 'settings') {
|
||||
$this->API->setdem = true;
|
||||
|
||||
return $this->API->settings;
|
||||
}
|
||||
|
||||
return $this->API->storage[$name];
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if ($name === 'settings') {
|
||||
if ($this->API->phoneConfigWatcherId) {
|
||||
$this->wait($this->API->phoneConfigWatcherId);
|
||||
$this->API->phoneConfigWatcherId = null;
|
||||
}
|
||||
if (Magic::is_fork() && !Magic::$processed_fork) {
|
||||
\danog\MadelineProto\Logger::log('Detected fork');
|
||||
$this->API->reset_session();
|
||||
foreach ($this->API->datacenter->sockets as $id => $datacenter) {
|
||||
$this->API->close_and_reopen($id);
|
||||
}
|
||||
Magic::$processed_fork = true;
|
||||
}
|
||||
|
||||
return $this->API->__construct(array_replace_recursive($this->API->settings, $value));
|
||||
}
|
||||
|
||||
return $this->API->storage[$name] = $value;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->API->storage[$name]);
|
||||
}
|
||||
|
||||
public function __unset($name)
|
||||
{
|
||||
unset($this->API->storage[$name]);
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,7 @@ class Exception extends \Exception
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$result = $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.$this->getTLTrace();
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
$result = str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
|
||||
}
|
||||
return $result;
|
||||
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.$this->getTLTrace();
|
||||
}
|
||||
|
||||
public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null)
|
||||
|
@ -38,7 +38,9 @@ class CheckLoop extends ResumableSignalLoop
|
||||
$this->startedLoop();
|
||||
$API->logger->logger("Entered check loop in DC {$datacenter}", Logger::ULTRA_VERBOSE);
|
||||
|
||||
$timeout = $API->settings['connection_settings'][isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all']['timeout'];
|
||||
$dc_config_number = isset($API->settings['connection_settings'][$datacenter]) ? $datacenter : 'all';
|
||||
|
||||
$timeout = $API->settings['connection_settings'][$dc_config_number]['timeout'];
|
||||
while (true) {
|
||||
while (empty($connection->new_outgoing)) {
|
||||
if (yield $this->waitSignal($this->pause())) {
|
||||
@ -52,7 +54,7 @@ class CheckLoop extends ResumableSignalLoop
|
||||
if ($connection->hasPendingCalls()) {
|
||||
$last_recv = $connection->get_max_id(true);
|
||||
if ($connection->temp_auth_key !== null) {
|
||||
$message_ids = array_values($connection->new_outgoing);
|
||||
$message_ids = $connection->getPendingCalls();//array_values($connection->new_outgoing);
|
||||
$deferred = new Deferred();
|
||||
$deferred->promise()->onResolve(
|
||||
function ($e, $result) use ($message_ids, $API, $connection, $datacenter) {
|
||||
@ -109,6 +111,7 @@ class CheckLoop extends ResumableSignalLoop
|
||||
}
|
||||
);
|
||||
$list = '';
|
||||
// Don't edit this here pls
|
||||
foreach ($message_ids as $message_id) {
|
||||
$list .= $connection->outgoing_messages[$message_id]['_'].', ';
|
||||
}
|
||||
@ -126,7 +129,6 @@ class CheckLoop extends ResumableSignalLoop
|
||||
}
|
||||
$connection->writer->resume();
|
||||
}
|
||||
//$t = time();
|
||||
if (yield $this->waitSignal($this->pause($timeout))) {
|
||||
$API->logger->logger("Exiting check loop in DC $datacenter");
|
||||
$this->exitedLoop();
|
||||
|
@ -107,7 +107,7 @@ class ReadLoop extends SignalLoop
|
||||
}
|
||||
$this->startedLoop();
|
||||
if ($this->API->is_http($datacenter)) {
|
||||
$this->API->datacenter->sockets[$datacenter]->waiter->resume();
|
||||
Loop::defer([$connection->waiter, 'resume']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,6 +118,7 @@ class ReadLoop extends SignalLoop
|
||||
$datacenter = $this->datacenter;
|
||||
$connection = $this->connection;
|
||||
if (isset($this->connection->old)) {
|
||||
$API->logger->logger("Not reading because connection is old");
|
||||
throw new NothingInTheSocketException();
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@ class UpdateLoop extends ResumableSignalLoop
|
||||
{
|
||||
$API = $this->API;
|
||||
$datacenter = $this->datacenter;
|
||||
$connection = $this->connection;
|
||||
|
||||
if (!$this->API->settings['updates']['handle_updates']) {
|
||||
yield new Success(0);
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
namespace danog\MadelineProto\Loop\Connection;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Success;
|
||||
use danog\MadelineProto\Connection;
|
||||
use danog\MadelineProto\Logger;
|
||||
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
|
||||
use danog\MadelineProto\MTProtoTools\Crypt;
|
||||
use danog\MadelineProto\Tools;
|
||||
use danog\MadelineProto\Magic;
|
||||
|
||||
/**
|
||||
* Socket write loop.
|
||||
@ -44,7 +44,7 @@ class WriteLoop extends ResumableSignalLoop
|
||||
|
||||
$this->startedLoop();
|
||||
$API->logger->logger("Entered write loop in DC {$datacenter}", Logger::ULTRA_VERBOSE);
|
||||
|
||||
|
||||
$please_wait = false;
|
||||
while (true) {
|
||||
if (empty($connection->pending_outgoing) || $please_wait) {
|
||||
@ -101,7 +101,7 @@ class WriteLoop extends ResumableSignalLoop
|
||||
|
||||
$pad_length = -$length & 15;
|
||||
$pad_length += 16 * $this->random_int($modulus = 16);
|
||||
|
||||
|
||||
$pad = $this->random($pad_length);
|
||||
$buffer = yield $connection->stream->getWriteBuffer(8 + 8 + 4 + $pad_length + $length);
|
||||
|
||||
@ -157,18 +157,16 @@ class WriteLoop extends ResumableSignalLoop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($API->is_http($datacenter) && !$has_http_wait) {
|
||||
//$connection->pending_outgoing[$connection->pending_outgoing_key++] = ['_' => 'http_wait', 'serialized_body' => $this->API->serialize_object(['type' => ''], ['_' => 'http_wait', 'max_wait' => $API->settings['connection_settings'][$dc_config_number]['timeout'] * 1000 - 100, 'wait_after' => 0, 'max_delay' => 0], 'http_wait'), 'content_related' => true, 'unencrypted' => false, 'method' => true];
|
||||
$connection->pending_outgoing[$connection->pending_outgoing_key++] = ['_' => 'http_wait', 'serialized_body' => yield $this->API->serialize_object_async(['type' => ''], ['_' => 'http_wait', 'max_wait' => 30000, 'wait_after' => 0, 'max_delay' => 1], 'http_wait'), 'content_related' => true, 'unencrypted' => false, 'method' => true];
|
||||
$connection->pending_outgoing_key %= Connection::PENDING_MAX;
|
||||
|
||||
$has_http_wait = true;
|
||||
}
|
||||
|
||||
$total_length = 0;
|
||||
$count = 0;
|
||||
ksort($connection->pending_outgoing);
|
||||
$skipped = false;
|
||||
foreach ($connection->pending_outgoing as $k => $message) {
|
||||
if ($message['unencrypted']) {
|
||||
continue;
|
||||
@ -177,8 +175,9 @@ class WriteLoop extends ResumableSignalLoop
|
||||
unset($connection->pending_outgoing[$k]);
|
||||
continue;
|
||||
}
|
||||
if ($API->settings['connection_settings'][$dc_config_number]['pfs'] && !isset($connection->temp_auth_key['bound']) && !strpos($datacenter, 'cdn') && $message['_'] !== 'auth.bindTempAuthKey') {
|
||||
if ($API->settings['connection_settings'][$dc_config_number]['pfs'] && !isset($connection->temp_auth_key['bound']) && !strpos($datacenter, 'cdn') && !in_array($message['_'], ['http_wait', 'auth.bindTempAuthKey']) && $message['method']) {
|
||||
$API->logger->logger("Skipping {$message['_']} due to unbound keys in DC {$datacenter}");
|
||||
$skipped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -191,7 +190,6 @@ class WriteLoop extends ResumableSignalLoop
|
||||
$MTmessage = ['_' => 'MTmessage', 'msg_id' => $message_id, 'body' => $body, 'seqno' => $connection->generate_out_seq_no($message['content_related'])];
|
||||
|
||||
if (isset($message['method']) && $message['method'] && $message['_'] !== 'http_wait') {
|
||||
|
||||
if ((!isset($connection->temp_auth_key['connection_inited']) || $connection->temp_auth_key['connection_inited'] === false) && $message['_'] !== 'auth.bindTempAuthKey') {
|
||||
$API->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['write_client_info'], $message['_']), \danog\MadelineProto\Logger::NOTICE);
|
||||
$MTmessage['body'] = yield $API->serialize_method_async(
|
||||
@ -201,15 +199,15 @@ class WriteLoop extends ResumableSignalLoop
|
||||
'query' => yield $API->serialize_method_async(
|
||||
'initConnection',
|
||||
[
|
||||
'api_id' => $API->settings['app_info']['api_id'],
|
||||
'api_hash' => $API->settings['app_info']['api_hash'],
|
||||
'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',
|
||||
'app_version' => $API->settings['app_info']['app_version'],
|
||||
'api_id' => $API->settings['app_info']['api_id'],
|
||||
'api_hash' => $API->settings['app_info']['api_hash'],
|
||||
'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',
|
||||
'app_version' => $API->settings['app_info']['app_version'],
|
||||
'system_lang_code' => $API->settings['app_info']['lang_code'],
|
||||
'lang_code' => $API->settings['app_info']['lang_code'],
|
||||
'lang_pack' => $API->settings['app_info']['lang_pack'],
|
||||
'query' => $MTmessage['body'],
|
||||
'lang_code' => $API->settings['app_info']['lang_code'],
|
||||
'lang_pack' => $API->settings['app_info']['lang_pack'],
|
||||
'query' => $MTmessage['body'],
|
||||
]
|
||||
),
|
||||
]
|
||||
@ -230,12 +228,12 @@ class WriteLoop extends ResumableSignalLoop
|
||||
}
|
||||
|
||||
/* if ($API->settings['requests']['gzip_encode_if_gt'] !== -1 && ($l = strlen($MTmessage['body'])) > $API->settings['requests']['gzip_encode_if_gt']) {
|
||||
if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) {
|
||||
$MTmessage['body'] = yield $API->serialize_object_async(['type' => 'gzip_packed'], ['packed_data' => $gzipped], 'gzipped data');
|
||||
$API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
}
|
||||
unset($gzipped);
|
||||
}*/
|
||||
if (($g = strlen($gzipped = gzencode($MTmessage['body']))) < $l) {
|
||||
$MTmessage['body'] = yield $API->serialize_object_async(['type' => 'gzip_packed'], ['packed_data' => $gzipped], 'gzipped data');
|
||||
$API->logger->logger('Using GZIP compression for ' . $message['_'] . ', saved ' . ($l - $g) . ' bytes of data, reduced call size by ' . $g * 100 / $l . '%', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
}
|
||||
unset($gzipped);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
$body_length = strlen($MTmessage['body']);
|
||||
@ -311,7 +309,7 @@ class WriteLoop extends ResumableSignalLoop
|
||||
|
||||
if ($has_http_wait) {
|
||||
$connection->last_http_wait = $sent;
|
||||
} elseif ($API->isAltervista()) {
|
||||
} elseif (Magic::$altervista) {
|
||||
$connection->last_http_wait = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
@ -332,8 +330,9 @@ class WriteLoop extends ResumableSignalLoop
|
||||
}
|
||||
|
||||
//if (!empty($connection->pending_outgoing)) $connection->select();
|
||||
} while (!empty($connection->pending_outgoing));
|
||||
} while (!empty($connection->pending_outgoing) && !$skipped);
|
||||
|
||||
$connection->pending_outgoing_key = 0;
|
||||
return $skipped;
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,12 @@ use danog\MadelineProto\Stream\MTProtoTransport\HttpsStream;
|
||||
use danog\MadelineProto\Stream\MTProtoTransport\HttpStream;
|
||||
use danog\MadelineProto\TL\TLCallback;
|
||||
use danog\MadelineProto\MTProtoTools\CombinedUpdatesState;
|
||||
use danog\MadelineProto\Async\AsyncConstruct;
|
||||
|
||||
/**
|
||||
* Manages all of the mtproto stuff.
|
||||
*/
|
||||
class MTProto implements TLCallback
|
||||
class MTProto extends AsyncConstruct implements TLCallback
|
||||
{
|
||||
use \danog\Serializable;
|
||||
use \danog\MadelineProto\MTProtoTools\AckHandler;
|
||||
@ -142,20 +143,18 @@ class MTProto implements TLCallback
|
||||
public $setdem = false;
|
||||
public $storage = [];
|
||||
private $postpone_updates = false;
|
||||
private $altervista = false;
|
||||
private $supportUser = 0;
|
||||
public $referenceDatabase;
|
||||
public $update_deferred;
|
||||
public $phoneConfigWatcherId;
|
||||
|
||||
public $asyncInitPromise;
|
||||
|
||||
public function __magic_construct($settings = [])
|
||||
{
|
||||
$this->asyncInitPromise = $this->call($this->__async_construct($settings));
|
||||
$this->setInitPromise($this->__construct_async($settings));
|
||||
}
|
||||
|
||||
public function __async_construct($settings = [])
|
||||
public function __construct_async($settings = [])
|
||||
{
|
||||
\danog\MadelineProto\Magic::class_exists();
|
||||
// Parse settings
|
||||
@ -215,7 +214,6 @@ class MTProto implements TLCallback
|
||||
}
|
||||
yield $this->get_config_async([], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->v = self::V;
|
||||
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
@ -225,7 +223,7 @@ class MTProto implements TLCallback
|
||||
|
||||
public function isAltervista()
|
||||
{
|
||||
return $this->altervista;
|
||||
return Magic::$altervista;
|
||||
}
|
||||
|
||||
public function isInitingAuthorization()
|
||||
@ -236,9 +234,9 @@ class MTProto implements TLCallback
|
||||
public function __wakeup()
|
||||
{
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3);
|
||||
$this->asyncInitPromise = $this->call($this->__async_wakeup($backtrace));
|
||||
$this->setInitPromise($this->__wakeup_async($backtrace));
|
||||
}
|
||||
public function __async_wakeup($backtrace)
|
||||
public function __wakeup_async($backtrace)
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']);
|
||||
@ -267,7 +265,6 @@ class MTProto implements TLCallback
|
||||
$this->referenceDatabase = new ReferenceDatabase($this);
|
||||
}
|
||||
$this->update_callbacks([$this, $this->referenceDatabase]);
|
||||
$this->altervista = isset($_SERVER['SERVER_ADMIN']) && strpos($_SERVER['SERVER_ADMIN'], 'altervista.org');
|
||||
|
||||
$this->settings['connection_settings']['all']['ipv6'] = \danog\MadelineProto\Magic::$ipv6;
|
||||
/*if (isset($this->settings['pwr']['update_handler']) && $this->settings['pwr']['update_handler'] === $this->settings['updates']['callback']) {
|
||||
@ -374,7 +371,7 @@ class MTProto implements TLCallback
|
||||
$this->reset_session(true, true);
|
||||
$this->config = ['expires' => -1];
|
||||
$this->dh_config = ['version' => 0];
|
||||
yield $this->__async_construct($settings);
|
||||
yield $this->__construct_async($settings);
|
||||
$force = true;
|
||||
foreach ($this->secret_chats as $chat => $data) {
|
||||
try {
|
||||
@ -548,7 +545,6 @@ class MTProto implements TLCallback
|
||||
$app_version = '4.9.1 (13613)';
|
||||
}
|
||||
|
||||
$this->altervista = isset($_SERVER['SERVER_ADMIN']) && strpos($_SERVER['SERVER_ADMIN'], 'altervista.org');
|
||||
// Set default settings
|
||||
$default_settings = ['authorization' => [
|
||||
// Authorization settings
|
||||
@ -615,7 +611,7 @@ class MTProto implements TLCallback
|
||||
// connection settings
|
||||
'all' => [
|
||||
// These settings will be applied on every datacenter that hasn't a custom settings subarray...
|
||||
'protocol' => $this->altervista ? 'http' : 'tcp_abridged',
|
||||
'protocol' => Magic::$altervista ? 'http' : 'tcp_abridged',
|
||||
// can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported)
|
||||
'test_mode' => false,
|
||||
// decides whether to connect to the main telegram servers or to the testing servers (deep telegram)
|
||||
@ -623,9 +619,9 @@ class MTProto implements TLCallback
|
||||
// decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean
|
||||
'timeout' => 2,
|
||||
// timeout for sockets
|
||||
'proxy' => $this->altervista ? '\\HttpProxy' : '\\Socket',
|
||||
'proxy' => Magic::$altervista ? '\\HttpProxy' : '\\Socket',
|
||||
// The proxy class to use
|
||||
'proxy_extra' => $this->altervista ? ['address' => 'localhost', 'port' => 80] : [],
|
||||
'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [],
|
||||
// Extra parameters to pass to the proxy class using setExtra
|
||||
'obfuscated' => false,
|
||||
'transport' => 'tcp',
|
||||
|
@ -790,15 +790,6 @@ trait PeerHandler
|
||||
{
|
||||
$settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all'];
|
||||
if (!isset($this->settings['pwr']) || $this->settings['pwr']['pwr'] === false || $settings['test_mode']) {
|
||||
/*
|
||||
try {
|
||||
if (isset($res['username'])) {
|
||||
shell_exec('curl '.escapeshellarg('https://api.pwrtelegram.xyz/getchat?chat_id=@'.$res['username']).' -s -o /dev/null >/dev/null 2>/dev/null & ');
|
||||
}
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->logger->logger([$e->getMessage());
|
||||
}
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (!empty($res)) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -18,6 +18,8 @@
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
use Amp\Artax\Request;
|
||||
|
||||
/**
|
||||
* Wrapper for my.telegram.org.
|
||||
*/
|
||||
@ -25,119 +27,98 @@ class MyTelegramOrgWrapper
|
||||
{
|
||||
private $logged = false;
|
||||
private $hash = '';
|
||||
private $token;
|
||||
private $number;
|
||||
private $creation_hash;
|
||||
private $settings;
|
||||
const MY_TELEGRAM_URL = 'https://my.telegram.org';
|
||||
|
||||
public function __construct($number)
|
||||
public function __sleep()
|
||||
{
|
||||
if (!extension_loaded('curl')) {
|
||||
throw new Exception(['extension', 'curl']);
|
||||
return ['logged', 'hash', 'token', 'number', 'creation_hash', 'settings'];
|
||||
}
|
||||
public function __construct($settings)
|
||||
{
|
||||
if (!isset($settings['all'])) {
|
||||
$settings['connection_settings'] = ['all' => [
|
||||
// These settings will be applied on every datacenter that hasn't a custom settings subarray...
|
||||
'protocol' => Magic::$altervista ? 'http' : 'tcp_abridged',
|
||||
// can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported)
|
||||
'test_mode' => false,
|
||||
// decides whether to connect to the main telegram servers or to the testing servers (deep telegram)
|
||||
'ipv6' => \danog\MadelineProto\Magic::$ipv6,
|
||||
// decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean
|
||||
'timeout' => 2,
|
||||
// timeout for sockets
|
||||
'proxy' => Magic::$altervista ? '\\HttpProxy' : '\\Socket',
|
||||
// The proxy class to use
|
||||
'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [],
|
||||
// Extra parameters to pass to the proxy class using setExtra
|
||||
'obfuscated' => false,
|
||||
'transport' => 'tcp',
|
||||
'pfs' => extension_loaded('gmp'),
|
||||
],
|
||||
];
|
||||
}
|
||||
$this->settings = $settings;
|
||||
$this->__wakeup();
|
||||
}
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->datacenter = new DataCenter(
|
||||
new class($this->settings)
|
||||
{
|
||||
public function __construct($settings)
|
||||
{
|
||||
$this->logger = new Logger(
|
||||
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_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE,
|
||||
isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
}
|
||||
},
|
||||
[],
|
||||
$this->settings['connection_settings']
|
||||
);
|
||||
}
|
||||
public function login_async($number)
|
||||
{
|
||||
$this->number = $number;
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, self::MY_TELEGRAM_URL.'/auth/send_password');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['phone' => $number]));
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
|
||||
$headers = $this->get_headers('origin', []);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('Curl error: '.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
$request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST');
|
||||
$request = $request->withBody(http_build_query(['phone' => $number]));
|
||||
$request = $request->withHeaders($this->getHeaders('origin'));
|
||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||
$result = yield $response->getBody();
|
||||
$resulta = json_decode($result, true);
|
||||
|
||||
if (!isset($resulta['random_hash'])) {
|
||||
throw new Exception($result);
|
||||
}
|
||||
$this->hash = $resulta['random_hash'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for generating curl request headers.
|
||||
*/
|
||||
private function get_headers($httpType, $cookies)
|
||||
{
|
||||
// Common header flags.
|
||||
$headers = [];
|
||||
$headers[] = 'Dnt: 1';
|
||||
$headers[] = 'Connection: keep-alive';
|
||||
$headers[] = 'Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4';
|
||||
$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36';
|
||||
|
||||
// Add additional headers based on the type of request.
|
||||
switch ($httpType) {
|
||||
case 'origin':
|
||||
$headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
|
||||
$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
||||
$headers[] = 'Accept: application/json, text/javascript, */*; q=0.01';
|
||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/auth';
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
break;
|
||||
case 'refer':
|
||||
$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br';
|
||||
$headers[] = 'Upgrade-Insecure-Requests: 1';
|
||||
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
|
||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL;
|
||||
$headers[] = 'Cache-Control: max-age=0';
|
||||
break;
|
||||
case 'app':
|
||||
$headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
|
||||
$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
||||
$headers[] = 'Accept: */*';
|
||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/apps';
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
break;
|
||||
}
|
||||
|
||||
// Add every cookie to the header.
|
||||
foreach ($cookies as $cookie) {
|
||||
$headers[] = 'Cookie: '.$cookie;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function complete_login($password)
|
||||
public function complete_login_async($password)
|
||||
{
|
||||
if ($this->logged) {
|
||||
throw new Exception('Already logged in!');
|
||||
}
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, self::MY_TELEGRAM_URL.'/auth/login');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
$request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST');
|
||||
$request = $request->withBody(http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
|
||||
$request = $request->withHeaders($this->getHeaders('origin'));
|
||||
$request = $request->withHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
|
||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||
$result = yield $response->getBody();
|
||||
|
||||
$headers = $this->get_headers('origin', []);
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||
$result = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('Curl error: '.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
list($response_headers, $response_content) = preg_split('/(\r\n){2}/', $result, 2);
|
||||
switch ($response_content) {
|
||||
switch ($result) {
|
||||
case 'true':
|
||||
//Logger::log(['Login OK'], Logger::VERBOSE);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($response_content);
|
||||
throw new Exception($result);
|
||||
}
|
||||
$this->token = explode(';', explode('stel_token=', $response_headers)[1])[0];
|
||||
|
||||
$this->token = explode(';', explode('stel_token=', $response->getHeader('Set-Cookie'))[1])[0];
|
||||
|
||||
return $this->logged = true;
|
||||
}
|
||||
@ -147,27 +128,17 @@ class MyTelegramOrgWrapper
|
||||
return $this->logged;
|
||||
}
|
||||
|
||||
public function has_app()
|
||||
public function has_app_async()
|
||||
{
|
||||
if (!$this->logged) {
|
||||
throw new Exception('Not logged in!');
|
||||
}
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, self::MY_TELEGRAM_URL.'/apps');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
||||
$request = $request->withHeaders($this->getHeaders('refer'));
|
||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||
$result = yield $response->getBody();
|
||||
|
||||
$cookies = [];
|
||||
array_push($cookies, 'stel_token='.$this->token);
|
||||
$headers = $this->get_headers('refer', $cookies);
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
$result = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('Curl error: '.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
$title = explode('</title>', explode('<title>', $result)[1])[0];
|
||||
switch ($title) {
|
||||
case 'App configuration':return true;
|
||||
@ -180,27 +151,16 @@ class MyTelegramOrgWrapper
|
||||
throw new Exception($title);
|
||||
}
|
||||
|
||||
public function get_app()
|
||||
public function get_app_async()
|
||||
{
|
||||
if (!$this->logged) {
|
||||
throw new Exception('Not logged in!');
|
||||
}
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, self::MY_TELEGRAM_URL.'/apps');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
|
||||
$cookies = [];
|
||||
array_push($cookies, 'stel_token='.$this->token);
|
||||
$headers = $this->get_headers('refer', $cookies);
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
$result = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('Curl error: '.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
||||
$request = $request->withHeaders($this->getHeaders('refer'));
|
||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||
$result = yield $response->getBody();
|
||||
|
||||
$cose = explode('<label for="app_id" class="col-md-4 text-right control-label">App api_id:</label>
|
||||
<div class="col-md-7">
|
||||
@ -216,58 +176,29 @@ class MyTelegramOrgWrapper
|
||||
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
||||
}
|
||||
|
||||
public function create_app($settings)
|
||||
public function create_app_async($settings)
|
||||
{
|
||||
if (!$this->logged) {
|
||||
throw new Exception('Not logged in!');
|
||||
}
|
||||
if ($this->has_app()) {
|
||||
if (yield $this->has_app_async()) {
|
||||
throw new Exception('The app was already created!');
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, self::MY_TELEGRAM_URL.'/apps/create');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
|
||||
$cookies = [];
|
||||
array_push($cookies, 'stel_token='.$this->token);
|
||||
$headers = $this->get_headers('app', $cookies);
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('Curl error:'.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST');
|
||||
$request = $request->withHeaders($this->getHeaders('app'));
|
||||
$request = $request->withBody(http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
|
||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||
$result = yield $response->getBody();
|
||||
|
||||
if ($result) {
|
||||
throw new Exception($result);
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, self::MY_TELEGRAM_URL.'/apps');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
|
||||
$cookies = [];
|
||||
array_push($cookies, 'stel_token='.$this->token);
|
||||
$headers = $this->get_headers('refer', $cookies);
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('Curl error:'.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
$request = new Request(self::MY_TELEGRAM_URL.'/apps');
|
||||
$request = $request->withHeaders($this->getHeaders('refer'));
|
||||
$response = yield $this->datacenter->getHTTPClient()->request($request);
|
||||
$result = yield $response->getBody();
|
||||
|
||||
$title = explode('</title>', explode('<title>', $result)[1])[0];
|
||||
if ($title === 'Create new application') {
|
||||
@ -289,4 +220,53 @@ class MyTelegramOrgWrapper
|
||||
|
||||
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for generating curl request headers.
|
||||
*/
|
||||
private function getHeaders($httpType)
|
||||
{
|
||||
// Common header flags.
|
||||
$headers = [];
|
||||
$headers[] = 'Dnt: 1';
|
||||
$headers[] = 'Connection: keep-alive';
|
||||
$headers[] = 'Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4';
|
||||
$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36';
|
||||
|
||||
// Add additional headers based on the type of request.
|
||||
switch ($httpType) {
|
||||
case 'origin':
|
||||
$headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
|
||||
//$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
||||
$headers[] = 'Accept: application/json, text/javascript, */*; q=0.01';
|
||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/auth';
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
break;
|
||||
case 'refer':
|
||||
//$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br';
|
||||
$headers[] = 'Upgrade-Insecure-Requests: 1';
|
||||
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
|
||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL;
|
||||
$headers[] = 'Cache-Control: max-age=0';
|
||||
break;
|
||||
case 'app':
|
||||
$headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
|
||||
//$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
|
||||
$headers[] = 'Accept: */*';
|
||||
$headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/apps';
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
break;
|
||||
}
|
||||
|
||||
$final_headers = [];
|
||||
foreach ($headers as $header) {
|
||||
list($key, $value) = explode(':', $header, 2);
|
||||
$final_headers[trim($key)] = trim($value);
|
||||
}
|
||||
|
||||
return $final_headers;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,11 +29,6 @@ class Serialization
|
||||
echo $exception.PHP_EOL;
|
||||
|
||||
return;
|
||||
foreach (self::$instances as $instance) {
|
||||
if (isset($instance->session)) {
|
||||
$instance->serialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function realpaths($file)
|
||||
@ -42,68 +37,4 @@ class Serialization
|
||||
|
||||
return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize API class.
|
||||
*
|
||||
* @param string $filename the dump file
|
||||
* @param API $instance
|
||||
* @param bool $force
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
public static function serialize($filename, $instance, $force = false)
|
||||
{
|
||||
if ($filename == '') {
|
||||
throw new \danog\MadelineProto\Exception('Empty filename');
|
||||
}
|
||||
if (isset($instance->API->setdem) && $instance->API->setdem) {
|
||||
$instance->API->setdem = false;
|
||||
$instance->API->__construct($instance->API->settings);
|
||||
}
|
||||
if ($instance->API === null && !$instance->getting_api_id) {
|
||||
return false;
|
||||
}
|
||||
if ($instance->API && $instance->API->asyncInitPromise) {
|
||||
return $instance->call((static function () use ($filename, $instance, $force) {
|
||||
yield $instance->API->asyncInitPromise;
|
||||
$instance->API->asyncInitPromise = null;
|
||||
return self::serialize($filename, $instance, $force);
|
||||
})());
|
||||
}
|
||||
$instance->serialized = time();
|
||||
$realpaths = self::realpaths($filename);
|
||||
if (!file_exists($realpaths['lockfile'])) {
|
||||
touch($realpaths['lockfile']);
|
||||
clearstatcache();
|
||||
}
|
||||
$realpaths['lockfile'] = fopen($realpaths['lockfile'], 'w');
|
||||
\danog\MadelineProto\Logger::log('Waiting for exclusive lock of serialization lockfile...');
|
||||
flock($realpaths['lockfile'], LOCK_EX);
|
||||
\danog\MadelineProto\Logger::log('Lock acquired, serializing');
|
||||
|
||||
try {
|
||||
if (!$instance->getting_api_id) {
|
||||
$update_closure = $instance->API->settings['updates']['callback'];
|
||||
if ($instance->API->settings['updates']['callback'] instanceof \Closure) {
|
||||
$instance->API->settings['updates']['callback'] = [$instance->API, 'noop'];
|
||||
}
|
||||
$logger_closure = $instance->API->settings['logger']['logger_param'];
|
||||
if ($instance->API->settings['logger']['logger_param'] instanceof \Closure) {
|
||||
$instance->API->settings['logger']['logger_param'] = [$instance->API, 'noop'];
|
||||
}
|
||||
}
|
||||
$wrote = file_put_contents($realpaths['tempfile'], serialize($instance));
|
||||
rename($realpaths['tempfile'], $realpaths['file']);
|
||||
} finally {
|
||||
if (!$instance->getting_api_id) {
|
||||
$instance->API->settings['updates']['callback'] = $update_closure;
|
||||
$instance->API->settings['logger']['logger_param'] = $logger_closure;
|
||||
}
|
||||
flock($realpaths['lockfile'], LOCK_UN);
|
||||
fclose($realpaths['lockfile']);
|
||||
}
|
||||
|
||||
return $wrote;
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ class BufferedRawStream implements \danog\MadelineProto\Stream\BufferedStreamInt
|
||||
protected $memory_stream;
|
||||
private $append = '';
|
||||
private $append_after = 0;
|
||||
|
||||
/**
|
||||
* Asynchronously connect to a TCP/TLS server.
|
||||
*
|
||||
@ -178,7 +177,6 @@ class BufferedRawStream implements \danog\MadelineProto\Stream\BufferedStreamInt
|
||||
$chunk = yield $this->read();
|
||||
if ($chunk === null) {
|
||||
$this->disconnect();
|
||||
|
||||
throw new \danog\MadelineProto\NothingInTheSocketException();
|
||||
}
|
||||
fwrite($this->memory_stream, $chunk);
|
||||
|
@ -252,6 +252,7 @@ trait Tools
|
||||
}
|
||||
});
|
||||
}
|
||||
return $promise;
|
||||
}
|
||||
public function rethrow($e)
|
||||
{
|
||||
|
@ -19,30 +19,34 @@
|
||||
|
||||
namespace danog\MadelineProto\Wrappers;
|
||||
|
||||
use function Amp\ByteStream\getStdin;
|
||||
use function Amp\ByteStream\getStdout;
|
||||
|
||||
/**
|
||||
* Manages simple logging in and out.
|
||||
*/
|
||||
trait ApiStart
|
||||
{
|
||||
public function api_start()
|
||||
public function api_start_async($settings)
|
||||
{
|
||||
if (php_sapi_name() === 'cli') {
|
||||
if (!function_exists('readline')) {
|
||||
$readline = function ($prompt = null) {
|
||||
if ($prompt) {
|
||||
echo $prompt;
|
||||
}
|
||||
$fp = fopen('php://stdin', 'r');
|
||||
$line = rtrim(fgets($fp, 1024));
|
||||
|
||||
return $line;
|
||||
};
|
||||
} else {
|
||||
$readline = 'readline';
|
||||
}
|
||||
$stdin = getStdin();
|
||||
$stdout = getStdout();
|
||||
$readline = function ($prompt = null) use ($stdout, $stdin) {
|
||||
if ($prompt) {
|
||||
yield $stdout->write($prompt);
|
||||
}
|
||||
static $lines = [''];
|
||||
while (count($lines) < 2 && ($chunk = yield $stdin->read()) !== null) {
|
||||
$chunk = explode("\n", str_replace(["\r", "\n\n"], "\n", $chunk));
|
||||
$lines[count($lines) - 1] .= array_shift($chunk);
|
||||
$lines = array_merge($lines, $chunk);
|
||||
}
|
||||
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)
|
||||
Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id'.PHP_EOL;
|
||||
if (strpos($res = $readline('Your choice (m/a): '), 'm') !== false) {
|
||||
if (strpos(yield $readline('Your choice (m/a): '), 'm') !== false) {
|
||||
echo '1) Login to my.telegram.org
|
||||
2) Go to API development tools
|
||||
3) App title: your app\'s name, can be anything
|
||||
@ -51,21 +55,22 @@ Note that you can also provide the API parameters directly in the code using the
|
||||
Platform: anything
|
||||
Description: Describe your app here
|
||||
4) Click on create application'.PHP_EOL;
|
||||
$app['api_id'] = $readline('5) Enter your API ID: ');
|
||||
$app['api_hash'] = $readline('6) Enter your API hash: ');
|
||||
$app['api_id'] = yield $readline('5) Enter your API ID: ');
|
||||
$app['api_hash'] = yield $readline('6) Enter your API hash: ');
|
||||
|
||||
return $app;
|
||||
} else {
|
||||
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($readline('Enter a phone number that is already registered on Telegram: '));
|
||||
$this->my_telegram_org_wrapper->complete_login($readline('Enter the verification code you received in telegram: '));
|
||||
if (!$this->my_telegram_org_wrapper->has_app()) {
|
||||
$app_title = $readline('Enter the app\'s name, can be anything: ');
|
||||
$short_name = $readline('Enter the app\'s short name, can be anything: ');
|
||||
$url = $readline('Enter the app/website\'s URL, or t.me/yourusername: ');
|
||||
$description = $readline('Describe your app: ');
|
||||
$app = $this->my_telegram_org_wrapper->create_app(['app_title' => $app_title, 'app_shortname' => $short_name, 'app_url' => $short_name, 'app_platform' => 'web', 'app_desc' => $description]);
|
||||
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings);
|
||||
yield $this->my_telegram_org_wrapper->login_async(yield $readline('Enter a phone number that is already registered on Telegram: '));
|
||||
yield $this->my_telegram_org_wrapper->complete_login_async(yield $readline('Enter the verification code you received in telegram: '));
|
||||
if (!yield $this->my_telegram_org_wrapper->has_app_async()) {
|
||||
$app_title = yield $readline('Enter the app\'s name, can be anything: ');
|
||||
$short_name = yield $readline('Enter the app\'s short name, can be anything: ');
|
||||
$url = yield $readline('Enter the app/website\'s URL, or t.me/yourusername: ');
|
||||
$description = yield $readline('Describe your app: ');
|
||||
$app = yield $this->my_telegram_org_wrapper->create_app_async(['app_title' => $app_title, 'app_shortname' => $short_name, 'app_url' => $url, 'app_platform' => 'web', 'app_desc' => $description]);
|
||||
} else {
|
||||
$app = $this->my_telegram_org_wrapper->get_app();
|
||||
$app = yield $this->my_telegram_org_wrapper->get_app_async();
|
||||
}
|
||||
|
||||
return $app;
|
||||
@ -80,69 +85,78 @@ Note that you can also provide the API parameters directly in the code using the
|
||||
|
||||
return $app;
|
||||
} elseif (isset($_POST['phone_number'])) {
|
||||
$this->web_api_phone_login();
|
||||
yield $this->web_api_phone_login_async($settings);
|
||||
} else {
|
||||
$this->web_api_echo();
|
||||
yield $this->web_api_echo_async();
|
||||
}
|
||||
} elseif (!$this->my_telegram_org_wrapper->logged_in()) {
|
||||
if (isset($_POST['code'])) {
|
||||
$this->web_api_complete_login();
|
||||
if ($this->my_telegram_org_wrapper->has_app()) {
|
||||
return $this->my_telegram_org_wrapper->get_app();
|
||||
yield $this->web_api_complete_login_async();
|
||||
if (yield $this->my_telegram_org_wrapper->has_app_async()) {
|
||||
return yield $this->my_telegram_org_wrapper->get_app_async();
|
||||
}
|
||||
$this->web_api_echo();
|
||||
yield $this->web_api_echo_async();
|
||||
} else if (isset($_POST['api_id']) && isset($_POST['api_hash'])) {
|
||||
$app['api_id'] = (int) $_POST['api_id'];
|
||||
$app['api_hash'] = $_POST['api_hash'];
|
||||
$this->getting_api_id = false;
|
||||
|
||||
return $app;
|
||||
} elseif (isset($_POST['phone_number'])) {
|
||||
yield $this->web_api_phone_login_async($settings);
|
||||
} else {
|
||||
$this->web_api_echo("You didn't provide a phone code!");
|
||||
$this->my_telegram_org_wrapper = null;
|
||||
yield $this->web_api_echo_async();
|
||||
}
|
||||
} else {
|
||||
if (isset($_POST['app_title'], $_POST['app_shortname'], $_POST['app_url'], $_POST['app_platform'], $_POST['app_desc'])) {
|
||||
$app = $this->web_api_create_app();
|
||||
$app = yield $this->web_api_create_app_async();
|
||||
$this->getting_api_id = false;
|
||||
|
||||
return $app;
|
||||
} else {
|
||||
$this->web_api_echo("You didn't provide all of the required parameters!");
|
||||
yield $this->web_api_echo_async("You didn't provide all of the required parameters!");
|
||||
}
|
||||
}
|
||||
$this->asyncInitPromise = null;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function web_api_phone_login()
|
||||
public function web_api_phone_login_async($settings)
|
||||
{
|
||||
try {
|
||||
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($_POST['phone_number']);
|
||||
$this->web_api_echo();
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_api_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_api_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings);
|
||||
yield $this->my_telegram_org_wrapper->login_async($_POST['phone_number']);
|
||||
yield $this->web_api_echo_async();
|
||||
} catch (\Throwable $e) {
|
||||
yield $this->web_api_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
|
||||
public function web_api_complete_login()
|
||||
public function web_api_complete_login_async()
|
||||
{
|
||||
try {
|
||||
$this->my_telegram_org_wrapper->complete_login($_POST['code']);
|
||||
yield $this->my_telegram_org_wrapper->complete_login_async($_POST['code']);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_api_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_api_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_api_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_api_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
|
||||
public function web_api_create_app()
|
||||
public function web_api_create_app_async()
|
||||
{
|
||||
try {
|
||||
$params = $_POST;
|
||||
unset($params['creating_app']);
|
||||
$app = $this->my_telegram_org_wrapper->create_app($params);
|
||||
$app = yield $this->my_telegram_org_wrapper->create_app_async($params);
|
||||
|
||||
return $app;
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_api_echo('ERROR: '.$e->getMessage().' Try again.');
|
||||
yield $this->web_api_echo_async('ERROR: '.$e->getMessage().' Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_api_echo('ERROR: '.$e->getMessage().' Try again.');
|
||||
yield $this->web_api_echo_async('ERROR: '.$e->getMessage().' Try again.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
namespace danog\MadelineProto\Wrappers;
|
||||
|
||||
use function Amp\ByteStream\getOutput;
|
||||
|
||||
trait ApiTemplates
|
||||
{
|
||||
private $web_api_template = '<!DOCTYPE html>
|
||||
@ -51,12 +53,13 @@ trait ApiTemplates
|
||||
$this->web_template = $template;
|
||||
}
|
||||
|
||||
public function web_api_echo($message = '')
|
||||
public function web_api_echo_async($message = '')
|
||||
{
|
||||
$stdout = getOutput();
|
||||
if (!isset($this->my_telegram_org_wrapper)) {
|
||||
if (isset($_POST['type'])) {
|
||||
if ($_POST['type'] === 'manual') {
|
||||
echo $this->web_api_echo_template('Enter your API ID and API hash<br><b>'.$message.'</b><ol>
|
||||
yield $stdout->write($this->web_api_echo_template('Enter your API ID and API hash<br><b>'.$message.'</b><ol>
|
||||
<li>Login to my.telegram.org</li>
|
||||
<li>Go to API development tools</li>
|
||||
<li>
|
||||
@ -68,18 +71,21 @@ trait ApiTemplates
|
||||
</ul>
|
||||
</li>
|
||||
<li>Click on create application</li>
|
||||
</ol>', '<input type="string" name="api_id" placeholder="API ID" required/><input type="string" name="api_hash" placeholder="API hash" required/>');
|
||||
</ol>', '<input type="string" name="api_id" placeholder="API ID" required/><input type="string" name="api_hash" placeholder="API hash" required/>'));
|
||||
} else {
|
||||
echo $this->web_api_echo_template('Enter your phone number<br><b>'.$message.'</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>');
|
||||
yield $stdout->write($this->web_api_echo_template('Enter your phone number<br><b>'.$message.'</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>'));
|
||||
}
|
||||
} else {
|
||||
echo $this->web_api_echo_template('Do you want to enter the API id and the API hash manually or automatically?<br>Note that you can also provide it directly in the code using the <a href="https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id">settings</a>.<b>'.$message.'</b>', '<select name="type"><option value="automatic">Automatically</option><option value="manual">Manually</option></select>');
|
||||
if ($message) {
|
||||
$message = '<br><br>'.$message;
|
||||
}
|
||||
yield $stdout->write($this->web_api_echo_template('Do you want to enter the API id and the API hash manually or automatically?<br>Note that you can also provide it directly in the code using the <a href="https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id">settings</a>.<b>'.$message.'</b>', '<select name="type"><option value="automatic">Automatically</option><option value="manual">Manually</option></select>'));
|
||||
}
|
||||
} else {
|
||||
if (!$this->my_telegram_org_wrapper->logged_in()) {
|
||||
echo $this->web_api_echo_template('Enter your code<br><b>'.$message.'</b>', '<input type="text" name="code" placeholder="Code" required/>');
|
||||
yield $stdout->write($this->web_api_echo_template('Enter your code<br><b>'.$message.'</b>', '<input type="text" name="code" placeholder="Code" required/>'));
|
||||
} else {
|
||||
echo $this->web_api_echo_template(
|
||||
yield $stdout->write($this->web_api_echo_template(
|
||||
'Enter the API info<br><b>'.$message.'</b>',
|
||||
'<input type="hidden" name="creating_app" value="yes" required/>
|
||||
Enter the app name, can be anything: <br><input type="text" name="app_title" required/><br>
|
||||
@ -111,7 +117,7 @@ trait ApiTemplates
|
||||
<input type="radio" name="app_platform" value="other"> Other (specify in description)
|
||||
</label>
|
||||
<br><br>Enter the app description, can be anything: <br><textarea name="app_desc" required></textarea><br><br>
|
||||
');
|
||||
'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@
|
||||
|
||||
namespace danog\MadelineProto\Wrappers;
|
||||
|
||||
use function Amp\ByteStream\getStdin;
|
||||
use function Amp\ByteStream\getStdout;
|
||||
|
||||
/**
|
||||
* Manages simple logging in and out.
|
||||
*/
|
||||
@ -30,29 +33,30 @@ trait Start
|
||||
return yield $this->get_self_async();
|
||||
}
|
||||
if (php_sapi_name() === 'cli') {
|
||||
if (!function_exists('readline')) {
|
||||
$readline = function ($prompt = null) {
|
||||
if ($prompt) {
|
||||
echo $prompt;
|
||||
}
|
||||
$fp = fopen('php://stdin', 'r');
|
||||
$line = rtrim(fgets($fp, 1024));
|
||||
|
||||
return $line;
|
||||
};
|
||||
$stdin = getStdin();
|
||||
$stdout = getStdout();
|
||||
$readline = function ($prompt = null) use ($stdout, $stdin) {
|
||||
if ($prompt) {
|
||||
yield $stdout->write($prompt);
|
||||
}
|
||||
static $lines = [''];
|
||||
while (count($lines) < 2 && ($chunk = yield $stdin->read()) !== null) {
|
||||
$chunk = explode("\n", str_replace(["\r", "\n\n"], "\n", $chunk));
|
||||
$lines[count($lines) - 1] .= array_shift($chunk);
|
||||
$lines = array_merge($lines, $chunk);
|
||||
}
|
||||
return array_shift($lines);
|
||||
};
|
||||
if (strpos(yield $readline('Do you want to login as user or bot (u/b)? '), 'b') !== false) {
|
||||
yield $this->bot_login_async(yield $readline('Enter your bot token: '));
|
||||
} else {
|
||||
$readline = 'readline';
|
||||
}
|
||||
if (strpos($readline('Do you want to login as user or bot (u/b)? '), 'b') !== false) {
|
||||
yield $this->bot_login_async($readline('Enter your bot token: '));
|
||||
} else {
|
||||
yield $this->phone_login_async($readline('Enter your phone number: '));
|
||||
$authorization = yield $this->complete_phone_login_async($readline('Enter the phone code: '));
|
||||
yield $this->phone_login_async(yield $readline('Enter your phone number: '));
|
||||
$authorization = yield $this->complete_phone_login_async(yield $readline('Enter the phone code: '));
|
||||
if ($authorization['_'] === 'account.password') {
|
||||
$authorization = yield $this->complete_2fa_login_async($readline('Please enter your password (hint '.$authorization['hint'].'): '));
|
||||
$authorization = yield $this->complete_2fa_login_async(yield $readline('Please enter your password (hint '.$authorization['hint'].'): '));
|
||||
}
|
||||
if ($authorization['_'] === 'account.needSignup') {
|
||||
$authorization = yield $this->complete_signup_async($readline('Please enter your first name: '), $readline('Please enter your last name (can be empty): '));
|
||||
$authorization = yield $this->complete_signup_async(yield $readline('Please enter your first name: '), yield $readline('Please enter your last name (can be empty): '));
|
||||
}
|
||||
}
|
||||
$this->serialize();
|
||||
@ -65,25 +69,25 @@ trait Start
|
||||
} elseif (isset($_POST['token'])) {
|
||||
yield $this->web_bot_login_async();
|
||||
} else {
|
||||
$this->web_echo();
|
||||
yield $this->web_echo_async();
|
||||
}
|
||||
} elseif ($this->authorized === self::WAITING_CODE) {
|
||||
if (isset($_POST['phone_code'])) {
|
||||
yield $this->web_complete_phone_login_async();
|
||||
} else {
|
||||
$this->web_echo("You didn't provide a phone code!");
|
||||
yield $this->web_echo_async("You didn't provide a phone code!");
|
||||
}
|
||||
} elseif ($this->authorized === self::WAITING_PASSWORD) {
|
||||
if (isset($_POST['password'])) {
|
||||
yield $this->web_complete_2fa_login_async();
|
||||
} else {
|
||||
$this->web_echo("You didn't provide the password!");
|
||||
yield $this->web_echo_async("You didn't provide the password!");
|
||||
}
|
||||
} elseif ($this->authorized === self::WAITING_SIGNUP) {
|
||||
if (isset($_POST['first_name'])) {
|
||||
yield $this->web_complete_signup_async();
|
||||
} else {
|
||||
$this->web_echo("You didn't provide the first name!");
|
||||
yield $this->web_echo_async("You didn't provide the first name!");
|
||||
}
|
||||
}
|
||||
if ($this->authorized === self::LOGGED_IN) {
|
||||
@ -99,11 +103,11 @@ trait Start
|
||||
{
|
||||
try {
|
||||
yield $this->phone_login_async($_POST['phone_number']);
|
||||
$this->web_echo();
|
||||
yield $this->web_echo_async();
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,11 +115,11 @@ trait Start
|
||||
{
|
||||
try {
|
||||
yield $this->complete_phone_login_async($_POST['phone_code']);
|
||||
$this->web_echo();
|
||||
yield $this->web_echo_async();
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,11 +127,11 @@ trait Start
|
||||
{
|
||||
try {
|
||||
yield $this->complete_2fa_login_async($_POST['password']);
|
||||
$this->web_echo();
|
||||
yield $this->web_echo_async();
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,11 +139,11 @@ trait Start
|
||||
{
|
||||
try {
|
||||
yield $this->complete_signup_async($_POST['first_name'], isset($_POST['last_name']) ? $_POST['last_name'] : '');
|
||||
$this->web_echo();
|
||||
yield $this->web_echo_async();
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,11 +151,11 @@ trait Start
|
||||
{
|
||||
try {
|
||||
yield $this->bot_login_async($_POST['token']);
|
||||
$this->web_echo();
|
||||
yield $this->web_echo_async();
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->web_echo('ERROR: '.$e->getMessage().'. Try again.');
|
||||
yield $this->web_echo_async('ERROR: '.$e->getMessage().'. Try again.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,33 +19,36 @@
|
||||
|
||||
namespace danog\MadelineProto\Wrappers;
|
||||
|
||||
use function Amp\ByteStream\getOutput;
|
||||
|
||||
trait Templates
|
||||
{
|
||||
public function web_echo($message = '')
|
||||
public function web_echo_async($message = '')
|
||||
{
|
||||
$stdout = getOutput();
|
||||
switch ($this->authorized) {
|
||||
case self::NOT_LOGGED_IN:
|
||||
if (isset($_POST['type'])) {
|
||||
if ($_POST['type'] === 'phone') {
|
||||
echo $this->web_echo_template('Enter your phone number<br><b>'.$message.'</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>');
|
||||
yield $stdout->write($this->web_echo_template('Enter your phone number<br><b>'.$message.'</b>', '<input type="text" name="phone_number" placeholder="Phone number" required/>'));
|
||||
} else {
|
||||
echo $this->web_echo_template('Enter your bot token<br><b>'.$message.'</b>', '<input type="text" name="token" placeholder="Bot token" required/>');
|
||||
yield $stdout->write($this->web_echo_template('Enter your bot token<br><b>'.$message.'</b>', '<input type="text" name="token" placeholder="Bot token" required/>'));
|
||||
}
|
||||
} else {
|
||||
echo $this->web_echo_template('Do you want to login as user or bot?<br><b>'.$message.'</b>', '<select name="type"><option value="phone">User</option><option value="bot">Bot</option></select>');
|
||||
yield $stdout->write($this->web_echo_template('Do you want to login as user or bot?<br><b>'.$message.'</b>', '<select name="type"><option value="phone">User</option><option value="bot">Bot</option></select>'));
|
||||
}
|
||||
break;
|
||||
|
||||
case self::WAITING_CODE:
|
||||
echo $this->web_echo_template('Enter your code<br><b>'.$message.'</b>', '<input type="text" name="phone_code" placeholder="Phone code" required/>');
|
||||
yield $stdout->write($this->web_echo_template('Enter your code<br><b>'.$message.'</b>', '<input type="text" name="phone_code" placeholder="Phone code" required/>'));
|
||||
break;
|
||||
|
||||
case self::WAITING_PASSWORD:
|
||||
echo $this->web_echo_template('Enter your password<br><b>'.$message.'</b>', '<input type="password" name="password" placeholder="Hint: '.$this->authorization['hint'].'" required/>');
|
||||
yield $stdout->write($this->web_echo_template('Enter your password<br><b>'.$message.'</b>', '<input type="password" name="password" placeholder="Hint: '.$this->authorization['hint'].'" required/>'));
|
||||
break;
|
||||
|
||||
case self::WAITING_SIGNUP:
|
||||
echo $this->web_echo_template('Sign up please<br><b>'.$message.'</b>', '<input type="text" name="first_name" placeholder="First name" required/><input type="text" name="last_name" placeholder="Last name"/>');
|
||||
yield $stdout->write($this->web_echo_template('Sign up please<br><b>'.$message.'</b>', '<input type="text" name="first_name" placeholder="First name" required/><input type="text" name="last_name" placeholder="Last name"/>'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ $settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: [];
|
||||
*/
|
||||
echo 'Loading MadelineProto...'.PHP_EOL;
|
||||
$MadelineProto = new \danog\MadelineProto\API(getcwd().'/testing.madeline', $settings);
|
||||
var_dump($MadelineProto->get_dialogs_full());
|
||||
|
||||
try {
|
||||
$MadelineProto->get_self();
|
||||
|
Loading…
Reference in New Issue
Block a user