Multiple async and VoIP improvements

This commit is contained in:
Daniil Gentili 2019-03-29 20:25:42 +01:00
parent e5798a41db
commit 7005cdf10a
12 changed files with 158 additions and 325 deletions

2
docs

@ -1 +1 @@
Subproject commit 3dbba4bc60dc830c08d5343e438bcd003ba9d1c5
Subproject commit f0229af1baa48d7529f90d7c3dcfbf9d5f54187b

View File

@ -9,11 +9,11 @@ MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY
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/>.
*/
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')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php' . PHP_EOL;
if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
@ -26,15 +26,15 @@ if (!file_exists('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) {
$MadelineProto->inputEncryptedFilePhoto = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic
$MadelineProto->inputEncryptedFileGif = $MadelineProto->upload_encrypted('tests/pony.mp4');
$MadelineProto->inputEncryptedFileSticker = $MadelineProto->upload_encrypted('tests/lel.webp');
$MadelineProto->inputEncryptedFileDocument = $MadelineProto->upload_encrypted('tests/60', 'magic'); // This gets an inputFile object with file name magic
$MadelineProto->inputEncryptedFileVideo = $MadelineProto->upload_encrypted('tests/swing.mp4');
$MadelineProto->inputEncryptedFileAudio = $MadelineProto->upload_encrypted('tests/mosconi.mp3');
$MadelineProto->inputEncryptedFilePhoto = $MadelineProto->upload_encrypted('tests/faust.jpg', 'fausticorn.jpg'); // This gets an inputFile object with file name magic
$MadelineProto->inputEncryptedFileGif = $MadelineProto->upload_encrypted('tests/pony.mp4');
$MadelineProto->inputEncryptedFileSticker = $MadelineProto->upload_encrypted('tests/lel.webp');
$MadelineProto->inputEncryptedFileDocument = $MadelineProto->upload_encrypted('tests/60', 'magic'); // This gets an inputFile object with file name magic
$MadelineProto->inputEncryptedFileVideo = $MadelineProto->upload_encrypted('tests/swing.mp4');
$MadelineProto->inputEncryptedFileAudio = $MadelineProto->upload_encrypted('tests/mosconi.mp3');
}*/
class EventHandler extends \danog\MadelineProto\EventHandler
@ -45,15 +45,7 @@ class EventHandler extends \danog\MadelineProto\EventHandler
$call->configuration['enable_NS'] = false;
$call->configuration['enable_AGC'] = false;
$call->configuration['enable_AEC'] = false;
$call->configuration['shared_config'] = [
'audio_init_bitrate' => 100 * 1000,
'audio_max_bitrate' => 100 * 1000,
'audio_min_bitrate' => 10 * 1000,
'audio_congestion_window' => 4 * 1024,
//'audio_bitrate_step_decr' => 0,
//'audio_bitrate_step_incr' => 2000,
];
$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->parseConfig();
$call->playOnHold($songs);
@ -91,7 +83,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
$this->configureCall($call);
if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
$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) {
@ -181,7 +173,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
$this->calls[$update['phone_call']->getOtherID()] = $update['phone_call'];
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) {
}
}
@ -203,7 +195,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
$this->configureCall($call);
if ($call->getCallState() !== \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
$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) {
try {
@ -239,7 +231,7 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
}
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) {
if ($call->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
try {
@ -248,24 +240,24 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
'reply_to_msg_id' => $this->times[$call->getOtherID()][1],
'peer' => $call->getOtherID(), 'message' => 'Call statistics by @magnaluna',
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => "/tmp/stats".$call->getCallID()['id'].".txt",
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => "stats".$call->getCallID()['id'].".txt"]
]
'_' => 'inputMediaUploadedDocument',
'file' => "/tmp/stats".$call->getCallID()['id'].".txt",
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => "stats".$call->getCallID()['id'].".txt"]
]
],
]);*/
$this->messages->sendMedia([
'reply_to_msg_id' => $this->times[$call->getOtherID()][1],
'peer' => $call->getOtherID(), 'message' => 'Debug info by @magnaluna',
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => '/tmp/logs'.$call->getCallID()['id'].'.log',
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'logs'.$call->getCallID()['id'].'.log'],
],
],
]);
'reply_to_msg_id' => $this->times[$call->getOtherID()][1],
'peer' => $call->getOtherID(), 'message' => 'Debug info by @magnaluna',
'media' => [
'_' => 'inputMediaUploadedDocument',
'file' => '/tmp/logs' . $call->getCallID()['id'] . '.log',
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'logs' . $call->getCallID()['id'] . '.log'],
],
],
]);
}
} catch (\danog\MadelineProto\Exception $e) {
echo $e;
@ -274,14 +266,14 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
} catch (\danog\MadelineProto\Exception $e) {
echo $e;
}
@unlink('/tmp/logs'.$call->getCallID()['id'].'.log');
@unlink('/tmp/stats'.$call->getCallID()['id'].'.txt');
@unlink('/tmp/logs' . $call->getCallID()['id'] . '.log');
@unlink('/tmp/stats' . $call->getCallID()['id'] . '.txt');
unset($this->calls[$key]);
} elseif (isset($this->times[$call->getOtherID()]) && $this->times[$call->getOtherID()][0] < time()) {
$this->times[$call->getOtherID()][0] += 30 + count($this->calls);
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) {
echo $e;
}
@ -289,7 +281,16 @@ Propic art by @magnaluna on [deviantart](https://magnaluna.deviantart.com).", 'p
}
}
}
$MadelineProto = new \danog\MadelineProto\API('session.madeline', ['secret_chats' => ['accept_chats' => false], 'logger' => ['logger' => 3, 'logger_param' => getcwd().'/MadelineProto.log']]);
\danog\MadelineProto\VoIPServerConfig::update(
[
'audio_init_bitrate' => 100 * 1000,
'audio_max_bitrate' => 100 * 1000,
'audio_min_bitrate' => 10 * 1000,
'audio_congestion_window' => 4 * 1024,
]
);
$MadelineProto = new \danog\MadelineProto\API('session.madeline', ['secret_chats' => ['accept_chats' => false], 'logger' => ['logger' => 3, 'logger_param' => getcwd() . '/MadelineProto.log']]);
$MadelineProto->start();
if (!isset($MadelineProto->programmed_call)) {

View File

@ -212,12 +212,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
$'.$constructor.$layer.' = '.$params.';
```
[PWRTelegram](https://pwrtelegram.xyz) json-encoded version:
```
'.$pwr_params.'
```
Or, if you\'re into Lua:

View File

@ -230,28 +230,6 @@ $MadelineProto->start();
$'.$type.' = $MadelineProto->'.$php_method.'(['.$params.']);
```
### [PWRTelegram HTTP API](https://pwrtelegram.xyz) example (NOT FOR MadelineProto):
'.($bot ? '### As a bot:
POST/GET to `https://api.pwrtelegram.xyz/botTOKEN/madeline`
Parameters:
* method - '.$data['method'].'
* params - `{'.$json_params.'}`
' : '').'
### As a user:
POST/GET to `https://api.pwrtelegram.xyz/userTOKEN/'.$data['method'].'`
Parameters:
'.$pwr_params.'
Or, if you\'re into Lua:
```lua

File diff suppressed because one or more lines are too long

View File

@ -463,11 +463,15 @@ trait AuthKeyHandler
}
public function get_dh_config()
{
return $this->wait($this->get_dh_config_async());
}
public function get_dh_config_async()
{
$this->updates_state['sync_loading'] = true;
try {
$dh_config = $this->method_call('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]);
$dh_config = yield $this->method_call_async_read('messages.getDhConfig', ['version' => $this->dh_config['version'], 'random_length' => 0], ['datacenter' => $this->datacenter->curdc]);
} finally {
$this->updates_state['sync_loading'] = false;
}

View File

@ -30,191 +30,6 @@ use function Amp\Promise\all;
*/
trait CallHandler
{
/*
public function select()
{
$result = [];
try {
/*
if ($this->is_http($this->settings['connection_settings']['default_dc']) || $this->altervista) {
$this->logger->logger("Initial HTTP short poll");
$waiting = $this->datacenter->select(0.1);
$result = $this->handle_select($waiting, $result);
}/
$tries = 10; // TODO add setting
$this->logger->logger('Long poll');
$t = microtime(true);
$waiting = $this->datacenter->select();
$t = microtime(true) - $t;
$this->logger->logger("Long poll took $t");
$result = $this->handle_select($waiting, $result);
do {
$this->logger->logger('Short poll');
$waiting = $this->datacenter->select($this->is_http($this->settings['connection_settings']['default_dc']) || $this->altervista ? $this->settings['connection_settings']['all']['timeout'] / 10 : true);
$result = $this->handle_select($waiting, $result);
} while ($tries-- && $waiting);
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
$this->logger->logger('Nothing in the socket while selecting', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
foreach ($this->datacenter->sockets as $dc => $socket) {
$this->close_and_reopen($dc);
$this->send_messages($dc);
}
}
return $result;
}
public $did = [];
public function handle_select($waiting, $result)
{
foreach ($waiting as $dc) {
$error = $this->recv_message($dc);
if ($error !== true) {
$this->close_and_reopen($dc);
if ($error === -404) {
if ($this->datacenter->sockets[$dc]->temp_auth_key !== null) {
$this->logger->logger('WARNING: Resetting auth key...', \danog\MadelineProto\Logger::WARNING);
$this->datacenter->sockets[$dc]->temp_auth_key = null;
$this->init_authorization();
return $result;
}
}
throw new \danog\MadelineProto\RPCErrorException($error, $error);
}
$result[$dc] = $this->handle_messages($dc) && (isset($result[$dc]) ? $result[$dc] : true);
if (($this->is_http($dc) || $this->altervista) && $this->datacenter->sockets[$dc]->new_outgoing) {
$this->send_messages($dc);
}
}
return $result;
}
public function iorun($updates)
{
do {
if ($updates && time() - $this->last_getdifference > $this->settings['updates']['getdifference_interval']) {
$this->get_updates_difference();
return;
}
if ($canunset = !$this->updates_state['sync_loading']) {
$this->updates_state['sync_loading'] = true;
}
if ($canunsetpostponeupdates = !$this->postpone_updates) {
$this->postpone_updates = true;
}
if ($canunsetpostponepwrchat = !$this->postpone_pwrchat) {
$this->postpone_pwrchat = true;
}
if (($this->is_http($this->settings['connection_settings']['default_dc']) || $this->altervista) && $updates) {
$this->send_messages($this->settings['connection_settings']['default_dc']);
}
foreach ($this->datacenter->sockets as $id => $datacenter) {
if ($datacenter->pending_outgoing) {
$this->send_messages($id);
}
}
$this->logger->logger('Polling for ' . ($updates ? 'updates' : 'replies') . ': selecting', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$t = microtime(true);
$only_updates = $this->select();
$t = microtime(true) - $t;
$this->logger->logger('Polling for ' . ($updates ? 'updates' : 'replies') . ': selecting took ' . $t, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$response_result = $this->has_pending_calls();
$repeat = 0;
foreach ($this->datacenter->sockets as $id => $datacenter) {
if ($updates) {
if (isset($only_updates[$id])) {
if ($only_updates[$id]) {
$this->logger->logger("Polling for updates: got only updates for DC $id", \danog\MadelineProto\Logger::VERBOSE);
} else {
$this->logger->logger("Polling for updates: got also RPC replies for DC $id", \danog\MadelineProto\Logger::NOTICE);
}
if ($response_result[$id]) {
$this->logger->logger("Polling for updates: still pending requests, resending for DC $id", \danog\MadelineProto\Logger::WARNING);
$this->send_messages($id);
}
} else {
if ($response_result[$id] || $id === $this->settings['connection_settings']['default_dc']) {
$this->logger->logger("Polling for updates: got nothing for DC $id", \danog\MadelineProto\Logger::ERROR);
if ($this->is_http($id) || $this->altervista) {
$this->logger->logger("Polling for updates: closing and reopening DC $id since we're on HTTP, and we polled");
$this->close_and_reopen($id);
$datacenter->last_http_wait = 0;
$repeat |= 1;
$this->logger->logger("Polling for updates: and now repolling for DC $id");
$this->send_messages($id);
}
}
}
} else {
if (isset($only_updates[$id])) {
if ($only_updates[$id]) {
$this->logger->logger("Polling for replies: got only updates for DC $id", \danog\MadelineProto\Logger::WARNING);
if ($response_result[$id]) {
$this->logger->logger("Polling for replies: still pending requests, repolling for DC $id", \danog\MadelineProto\Logger::WARNING);
$this->send_messages($id);
$repeat |= 1;
} else {
$this->logger->logger("Polling for replies: got all RPC replies for DC $id", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
}
} else {
if ($response_result[$id]) {
$this->logger->logger("Polling for replies: still pending requests, repolling for DC $id", \danog\MadelineProto\Logger::WARNING);
$this->send_messages($id);
} else {
$this->logger->logger("Polling for replies: got all RPC replies for DC $id", \danog\MadelineProto\Logger::NOTICE);
}
}
} else {
if ($response_result[$id]) {
$this->logger->logger("Polling for replies: got nothing for DC $id", \danog\MadelineProto\Logger::ERROR);
$this->logger->logger("Polling for replies: closing and reopening DC $id", \danog\MadelineProto\Logger::ERROR);
$this->close_and_reopen($id);
$datacenter->last_http_wait = 0;
$repeat |= 1;
$this->logger->logger("Polling for replies: resending for DC $id", \danog\MadelineProto\Logger::WARNING);
$this->send_messages($id);
} else {
$this->logger->logger("Polling for replies: got all RPC replies for DC $id", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
}
}
}
}
$this->logger->logger('Running guzzle promise queue');
\GuzzleHttp\Promise\queue()->run();
if ($repeat) {
$this->logger->logger('Repeat iowait');
}
} while ($repeat);
if ($canunset) {
$this->updates_state['sync_loading'] = false;
}
if ($canunsetpostponepwrchat) {
$this->postpone_pwrchat = false;
$this->handle_pending_pwrchat();
}
if ($canunsetpostponeupdates) {
$this->postpone_updates = false;
$this->handle_pending_updates();
}
}
*/
public function has_pending_calls()
{
$result = [];

View File

@ -337,9 +337,12 @@ trait ResponseHandler
case 500:
if ($response['error_message'] === 'MSG_WAIT_FAILED') {
$this->datacenter->sockets[$datacenter]->call_queue[$request['queue']] = [];
Loop::defer([$this, 'method_recall'], ['message_id' => $request_id, 'datacenter' => $datacenter]);
return;
}
$this->got_response_for_outgoing_message_id($request_id, $datacenter);
Loop::defer([$this, 'method_recall'], ['message_id' => $request_id, 'datacenter' => $datacenter]);
$this->handle_reject($datacenter, $request, new \danog\MadelineProto\RPCErrorException($response['error_message'], $response['error_code']));
return;
case 303:

View File

@ -55,7 +55,6 @@ trait UpdateHandler
return;
}
$this->updates[$this->updates_key++] = $update;
$this->logger->logger('Stored ');
}
public function get_updates_async($params = [])
@ -543,7 +542,8 @@ trait UpdateHandler
if (isset($this->calls[$update['phone_call']['id']])) {
return;
}
$controller = new \danog\MadelineProto\VoIP(false, $update['phone_call']['admin_id'], ['_' => 'inputPhoneCall', 'id' => $update['phone_call']['id'], 'access_hash' => $update['phone_call']['access_hash']], $this, \danog\MadelineProto\VoIP::CALL_STATE_INCOMING, $update['phone_call']['protocol']);
$controller = new \danog\MadelineProto\VoIP(false, $update['phone_call']['admin_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_INCOMING);
$controller->setCall($update['phone_call']);
$controller->storage = ['g_a_hash' => $update['phone_call']['g_a_hash']];
$update['phone_call'] = $this->calls[$update['phone_call']['id']] = $controller;
break;

View File

@ -51,9 +51,11 @@ trait AuthKeyHandler
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['generating_g_a'], \danog\MadelineProto\Logger::VERBOSE);
$g_a = $dh_config['g']->powMod($a, $dh_config['p']);
$this->check_G($g_a, $dh_config['p']);
$res = $this->method_call('phone.requestCall', ['user_id' => $user, 'g_a_hash' => hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_p2p' => true, 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => 65]], ['datacenter' => $this->datacenter->curdc]);
$this->calls[$res['phone_call']['id']] = $controller = new \danog\MadelineProto\VoIP(true, $user['user_id'], ['_' => 'inputPhoneCall', 'id' => $res['phone_call']['id'], 'access_hash' => $res['phone_call']['access_hash']], $this, \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED, $res['phone_call']['protocol']);
$controller = new \danog\MadelineProto\VoIP(true, $user['user_id'], $this, \danog\MadelineProto\VoIP::CALL_STATE_REQUESTED);
$controller->storage = ['a' => $a, 'g_a' => str_pad($g_a->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
$res = $this->method_call('phone.requestCall', ['user_id' => $user, 'g_a_hash' => hash('sha256', $g_a->toBytes(), true), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_p2p' => true, 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
$controller->setCall($res['phone_call']);
$this->calls[$res['phone_call']['id']] = $controller;
$this->handle_pending_updates();
$this->get_updates_difference();
@ -83,7 +85,7 @@ trait AuthKeyHandler
$this->check_G($g_b, $dh_config['p']);
try {
$res = $this->method_call('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => 65]], ['datacenter' => $this->datacenter->curdc]);
$res = $this->method_call('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
$this->logger->logger(sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id']));
@ -126,7 +128,7 @@ trait AuthKeyHandler
$params['g_b'] = new \phpseclib\Math\BigInteger($params['g_b'], 256);
$this->check_G($params['g_b'], $dh_config['p']);
$key = str_pad($params['g_b']->powMod($this->calls[$params['id']]->storage['a'], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT);
$res = $this->method_call('phone.confirmCall', ['key_fingerprint' => substr(sha1($key, true), -8), 'peer' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'g_a' => $this->calls[$params['id']]->storage['g_a'], 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => 65]], ['datacenter' => $this->datacenter->curdc])['phone_call'];
$res = $this->method_call('phone.confirmCall', ['key_fingerprint' => substr(sha1($key, true), -8), 'peer' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'g_a' => $this->calls[$params['id']]->storage['g_a'], 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]], ['datacenter' => $this->datacenter->curdc])['phone_call'];
$visualization = [];
$length = new \phpseclib\Math\BigInteger(count(\danog\MadelineProto\Magic::$emojis));
foreach (str_split(hash('sha256', $key.str_pad($this->calls[$params['id']]->storage['g_a'], 256, chr(0), \STR_PAD_LEFT), true), 8) as $number) {
@ -134,7 +136,7 @@ trait AuthKeyHandler
$visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
}
$this->calls[$params['id']]->setVisualization($visualization);
$this->calls[$params['id']]->configuration['shared_config'] = array_merge($this->method_call('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]), $this->calls[$params['id']]->configuration['shared_config']);
$this->calls[$params['id']]->configuration['endpoints'] = array_merge([$res['connection']], $res['alternative_connections'], $this->calls[$params['id']]->configuration['endpoints']);
$this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
$this->calls[$params['id']]->parseConfig();
@ -177,7 +179,6 @@ trait AuthKeyHandler
$visualization[] = \danog\MadelineProto\Magic::$emojis[(int) (new \phpseclib\Math\BigInteger($number, 256))->divide($length)[1]->toString()];
}
$this->calls[$params['id']]->setVisualization($visualization);
$this->calls[$params['id']]->configuration['shared_config'] = array_merge($this->method_call('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]), $this->calls[$params['id']]->configuration['shared_config']);
$this->calls[$params['id']]->configuration['endpoints'] = array_merge([$params['connection']], $params['alternative_connections'], $this->calls[$params['id']]->configuration['endpoints']);
$this->calls[$params['id']]->configuration = array_merge(['recv_timeout' => $this->config['call_receive_timeout_ms'] / 1000, 'init_timeout' => $this->config['call_connect_timeout_ms'] / 1000, 'data_saving' => \danog\MadelineProto\VoIP::DATA_SAVING_NEVER, 'enable_NS' => true, 'enable_AEC' => true, 'enable_AGC' => true, 'auth_key' => $key, 'auth_key_id' => substr(sha1($key, true), -8), 'call_id' => substr(hash('sha256', $key, true), -16), 'network_type' => \danog\MadelineProto\VoIP::NET_TYPE_ETHERNET], $this->calls[$params['id']]->configuration);
$this->calls[$params['id']]->parseConfig();

View File

@ -20,6 +20,8 @@
namespace danog\MadelineProto\Wrappers;
use danog\MadelineProto\MTProtoTools\PasswordCalculator;
use danog\MadelineProto\VoIPServerConfig;
use function Amp\Promise\wait;
/**
* Manages logging in and out.
@ -27,6 +29,10 @@ use danog\MadelineProto\MTProtoTools\PasswordCalculator;
trait Login
{
public function logout()
{
return $this->wait($this->logout_async());
}
public function logout_async()
{
foreach ($this->datacenter->sockets as $socket) {
$socket->authorized = false;
@ -40,41 +46,39 @@ trait Login
$this->users = [];
$this->state = [];
$this->tos = ['expires' => 0, 'accepted' => true];
if (!$this->method_call('auth.logOut', [], ['datacenter' => $this->datacenter->curdc])) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['logout_error']);
}
yield $this->method_call_async_read('auth.logOut', [], ['datacenter' => $this->datacenter->curdc]);
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['logout_ok'], \danog\MadelineProto\Logger::NOTICE);
return true;
}
public function bot_login($token)
public function bot_login_async($token)
{
if ($this->authorized === self::LOGGED_IN) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_logged_in'], \danog\MadelineProto\Logger::NOTICE);
$this->logout();
yield $this->logout_async();
}
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_bot'], \danog\MadelineProto\Logger::NOTICE);
$this->authorization = $this->method_call('auth.importBotAuthorization', ['bot_auth_token' => $token, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash']], ['datacenter' => $this->datacenter->curdc]);
$this->authorization = yield $this->method_call_async_read('auth.importBotAuthorization', ['bot_auth_token' => $token, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash']], ['datacenter' => $this->datacenter->curdc]);
$this->authorized = self::LOGGED_IN;
$this->authorized_dc = $this->datacenter->curdc;
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
$this->updates = [];
$this->updates_key = 0;
$this->init_authorization();
yield $this->init_authorization_async();
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE);
return $this->authorization;
}
public function phone_login($number, $sms_type = 5)
public function phone_login_async($number, $sms_type = 5)
{
if ($this->authorized === self::LOGGED_IN) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_logged_in'], \danog\MadelineProto\Logger::NOTICE);
$this->logout();
yield $this->logout_async();
}
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_code_sending'], \danog\MadelineProto\Logger::NOTICE);
$this->authorization = $this->method_call('auth.sendCode', ['settings' => ['_' => 'codeSettings'], 'phone_number' => $number, 'sms_type' => $sms_type, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash'], 'lang_code' => $this->settings['app_info']['lang_code']], ['datacenter' => $this->datacenter->curdc]);
$this->authorization = yield $this->method_call_async_read('auth.sendCode', ['settings' => ['_' => 'codeSettings'], 'phone_number' => $number, 'sms_type' => $sms_type, 'api_id' => $this->settings['app_info']['api_id'], 'api_hash' => $this->settings['app_info']['api_hash'], 'lang_code' => $this->settings['app_info']['lang_code']], ['datacenter' => $this->datacenter->curdc]);
$this->authorized_dc = $this->datacenter->curdc;
$this->authorization['phone_number'] = $number;
//$this->authorization['_'] .= 'MP';
@ -86,7 +90,7 @@ trait Login
return $this->authorization;
}
public function complete_phone_login($code)
public function complete_phone_login_async($code)
{
if ($this->authorized !== self::WAITING_CODE) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['login_code_uncalled']);
@ -95,11 +99,11 @@ trait Login
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_user'], \danog\MadelineProto\Logger::NOTICE);
try {
$authorization = $this->method_call('auth.signIn', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => (string) $code], ['datacenter' => $this->datacenter->curdc]);
$authorization = yield $this->method_call_async_read('auth.signIn', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => (string) $code], ['datacenter' => $this->datacenter->curdc]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
if ($e->rpc === 'SESSION_PASSWORD_NEEDED') {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_2fa_enabled'], \danog\MadelineProto\Logger::NOTICE);
$this->authorization = $this->method_call('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'] = '';
$this->authorized = self::WAITING_PASSWORD;
@ -118,17 +122,19 @@ trait Login
$this->authorized = self::LOGGED_IN;
$this->authorization = $authorization;
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
$this->init_authorization();
yield $this->init_authorization_async();
VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]));
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE);
return $this->authorization;
}
public function import_authorization($authorization)
public function import_authorization_async($authorization)
{
if ($this->authorized === self::LOGGED_IN) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_logged_in'], \danog\MadelineProto\Logger::NOTICE);
$this->logout();
yield $this->logout_async();
}
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_auth_key'], \danog\MadelineProto\Logger::NOTICE);
list($dc_id, $auth_key) = $authorization;
@ -147,39 +153,42 @@ trait Login
$this->datacenter->sockets[$dc_id]->new_incoming = [];
$this->datacenter->sockets[$dc_id]->authorized = true;
$this->authorized = self::LOGGED_IN;
$this->init_authorization();
yield $this->init_authorization_async();
VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]));
return $this->get_self();
return yield $this->get_self_async();
}
public function export_authorization()
public function export_authorization_async()
{
if ($this->authorized !== self::LOGGED_IN) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['not_logged_in']);
}
$this->get_self();
yield $this->get_self_async();
$this->authorized_dc = $this->datacenter->curdc;
return [$this->datacenter->curdc, $this->datacenter->sockets[$this->datacenter->curdc]->auth_key['auth_key']];
}
public function complete_signup($first_name, $last_name)
public function complete_signup_async($first_name, $last_name)
{
if ($this->authorized !== self::WAITING_SIGNUP) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['signup_uncalled']);
}
$this->authorized = self::NOT_LOGGED_IN;
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['signing_up'], \danog\MadelineProto\Logger::NOTICE);
$this->authorization = $this->method_call('auth.signUp', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => $this->authorization['phone_code'], 'first_name' => $first_name, 'last_name' => $last_name], ['datacenter' => $this->datacenter->curdc]);
$this->authorization = yield $this->method_call_async_read('auth.signUp', ['phone_number' => $this->authorization['phone_number'], 'phone_code_hash' => $this->authorization['phone_code_hash'], 'phone_code' => $this->authorization['phone_code'], 'first_name' => $first_name, 'last_name' => $last_name], ['datacenter' => $this->datacenter->curdc]);
$this->authorized = self::LOGGED_IN;
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
$this->init_authorization();
yield $this->init_authorization_async();
VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]));
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['signup_ok'], \danog\MadelineProto\Logger::NOTICE);
return $this->authorization;
}
public function complete_2fa_login($password)
public function complete_2fa_login_async($password)
{
if ($this->authorized !== self::WAITING_PASSWORD) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['2fa_uncalled']);
@ -188,20 +197,21 @@ trait Login
$hasher = new PasswordCalculator($this->logger);
$hasher->addInfo($this->authorization);
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_user'], \danog\MadelineProto\Logger::NOTICE);
$this->authorization = $this->method_call('auth.checkPassword', ['password' => $hasher->getCheckPassword($password)], ['datacenter' => $this->datacenter->curdc]);
$this->authorization = yield $this->method_call_async_read('auth.checkPassword', ['password' => $hasher->getCheckPassword($password)], ['datacenter' => $this->datacenter->curdc]);
$this->authorized = self::LOGGED_IN;
$this->datacenter->sockets[$this->datacenter->curdc]->authorized = true;
$this->init_authorization();
yield $this->init_authorization_async();
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['login_ok'], \danog\MadelineProto\Logger::NOTICE);
VoIPServerConfig::updateDefault(yield $this->method_call_async_read('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]));
return $this->authorization;
}
public function update_2fa(array $params): bool
public function update_2fa_async(array $params)
{
$hasher = new PasswordCalculator($this->logger);
$hasher->addInfo($this->method_call('account.getPassword', [], ['datacenter' => $this->datacenter->curdc]));
$hasher->addInfo(yield $this->method_call_async_read('account.getPassword', [], ['datacenter' => $this->datacenter->curdc]));
return $this->method_call('account.updatePasswordSettings', $hasher->getPassword($params), ['datacenter' => $this->datacenter->curdc]);
return yield $this->method_call_async_read('account.updatePasswordSettings', $hasher->getPassword($params), ['datacenter' => $this->datacenter->curdc]);
}
}

View File

@ -102,7 +102,6 @@ trait Loop
$this->datacenter->sockets[$this->settings['connection_settings']['default_dc']]->updater->start();
$this->logger->logger('Started update loop', \danog\MadelineProto\Logger::NOTICE);
$offset = 0;
while (true) {
foreach ($this->updates as $update) {