1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-11-27 05:54:41 +01:00

Fixed threading, fixed APIFactory, started working on calls

This commit is contained in:
Daniil Gentili 2017-04-01 13:20:57 +02:00
parent 564009cda9
commit cd1040ec19
31 changed files with 337 additions and 154 deletions

7
a.php Normal file
View File

@ -0,0 +1,7 @@
<?php
$payload = base64_decode('NAAAAAAAAAAAAAAAAAAAAAAAAAC06N5YFAAAAHiXRmAwx9DuB28gQszy/RHjhN2RdLkYdQ==');
$socket = fsockopen('tcp://149.154.167.91:443'); // DC 4
$socket = fsockopen('tcp://149.154.167.50:443'); // DC 2
stream_set_timeout($socket, 5);
echo 'Wrote '.fwrite($socket, $payload).' bytes'.PHP_EOL;
if (strlen(fread($socket, 100))) echo 'Read 100 bytes from socket'.PHP_EOL; else echo 'No data could be read from socket'.PHP_EOL;

View File

@ -1,23 +1,8 @@
--- ---
title: DataJSON title: DataJSON
description: constructors and methods of type DataJSON description: Any json-encodable data
--- ---
## Type: DataJSON ## Type: DataJSON
[Back to types index](index.md) [Back to constructor index](index.md)
### Possible values (constructors):
[dataJSON](../constructors/dataJSON.md)
### Methods that return an object of this type (methods):
[$MadelineProto->bots->sendCustomRequest](../methods/bots_sendCustomRequest.md)
[$MadelineProto->phone->getCallConfig](../methods/phone_getCallConfig.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -0,0 +1,8 @@
---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.

View File

@ -35,6 +35,7 @@ class API extends APIFactory
//$this->future_salts = $this->get_future_salts(['num' => 3]); //$this->future_salts = $this->get_future_salts(['num' => 3]);
$this->API->v = $this->API->getV(); $this->API->v = $this->API->getV();
\danog\MadelineProto\Logger::log(['MadelineProto is ready!'], Logger::NOTICE); \danog\MadelineProto\Logger::log(['MadelineProto is ready!'], Logger::NOTICE);
$this->setup_threads();
} }
/* /*
@ -45,11 +46,57 @@ class API extends APIFactory
return ['API']; return ['API'];
} }
*/ */
public function setup_threads()
{
if ($this->API->threads = $this->API->run_workers = class_exists('\Pool') && php_sapi_name() == 'cli' && $this->API->settings['threading']['allow_threading']) {
\danog\MadelineProto\Logger::log(['THREADING IS ENABLED'], \danog\MadelineProto\Logger::NOTICE);
$this->start_threads();
}
}
public function start_threads()
{
if ($this->API->threads) {
$dcs = $this->API->datacenter->get_dcs();
if (!isset($this->reader_pool)) {
$this->reader_pool = new \Pool(count($dcs));
}
if (!isset($this->readers)) {
$this->readers = [];
}
foreach ($dcs as $dc) {
if (!isset($this->readers[$dc])) {
$this->readers[$dc] = new \danog\MadelineProto\Threads\SocketReader($this->API, $dc);
}
if (!$this->readers[$dc]->isRunning()) {
$this->readers[$dc]->garbage = false;
$this->reader_pool->submit($this->readers[$dc]);
Logger::log(['Socket reader on DC '.$dc.': RESTARTED'], Logger::WARNING);
} else {
Logger::log(['Socket reader on DC '.$dc.': WORKING'], Logger::NOTICE);
}
}
}
}
public function __sleep()
{
$t = get_object_vars($this);
if (isset($t['reader_pool'])) {
unset($t['reader_pool']);
}
if (isset($t['readers'])) {
unset($t['readers']);
}
return array_keys($t);
}
public function __wakeup() public function __wakeup()
{ {
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']); set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
//$this->APIFactory(); $this->setup_threads();
if (!isset($this->messages)) $this->APIFactory();
} }
public function __destruct() public function __destruct()

View File

@ -142,7 +142,7 @@ class Connection
throw new Exception("Connection: couldn't connect to socket."); throw new Exception("Connection: couldn't connect to socket.");
} }
if (($wrote = fwrite($this->sock, $what)) !== strlen($what)) { if (($wrote = fwrite($this->sock, $what)) !== strlen($what)) {
throw new \danog\MadelineProto\Exception("WARNING: Wrong length was read (should've written ".strlen($what).', wrote '.$wrote.')!'); throw new \danog\MadelineProto\Exception("WARNING: Wrong length was written (should've written ".strlen($what).', wrote '.$wrote.')!');
} }
return $wrote; return $wrote;

View File

@ -694,6 +694,16 @@ description: Represents a boolean.
Represents a boolean.'); Represents a boolean.');
file_put_contents('types/DataJSON.md', '---
title: DataJSON
description: Any json-encodable data
---
## Type: DataJSON
[Back to constructor index](index.md)
Any json-encodable data.');
\danog\MadelineProto\Logger::log(['Done!'], \danog\MadelineProto\Logger::NOTICE); \danog\MadelineProto\Logger::log(['Done!'], \danog\MadelineProto\Logger::NOTICE);
} }
} }

View File

@ -39,6 +39,7 @@ class MTProto
use \danog\MadelineProto\TL\Conversion\Extension; use \danog\MadelineProto\TL\Conversion\Extension;
use \danog\MadelineProto\TL\Conversion\TD; use \danog\MadelineProto\TL\Conversion\TD;
use \danog\MadelineProto\Tools; use \danog\MadelineProto\Tools;
use \danog\MadelineProto\VoIP\AuthKeyHandler;
public $settings = []; public $settings = [];
public $config = ['expires' => -1]; public $config = ['expires' => -1];
@ -102,51 +103,6 @@ class MTProto
$this->should_serialize = true; $this->should_serialize = true;
} }
public function setup_threads()
{
if ($this->threads = $this->run_workers = class_exists('\Pool') && php_sapi_name() == 'cli' && $this->settings['threading']['allow_threading']) {
\danog\MadelineProto\Logger::log(['THREADING IS ENABLED'], \danog\MadelineProto\Logger::NOTICE);
$this->start_threads();
}
}
public function start_threads()
{
if ($this->threads) {
$dcs = $this->datacenter->get_dcs();
if (!isset($this->reader_pool)) {
$this->reader_pool = new \Pool(count($dcs));
}
if (!isset($this->readers)) {
$this->readers = [];
}
foreach ($dcs as $dc) {
if (!isset($this->readers[$dc])) {
$this->readers[$dc] = new \danog\MadelineProto\Threads\SocketReader($this, $dc);
}
if (!$this->readers[$dc]->isRunning()) {
$this->readers[$dc]->garbage = false;
$this->reader_pool->submit($this->readers[$dc]);
Logger::log(['Socket reader on DC '.$dc.': RESTARTED'], Logger::WARNING);
} else {
Logger::log(['Socket reader on DC '.$dc.': WORKING'], Logger::NOTICE);
}
}
}
}
public function __sleep()
{
$t = get_object_vars($this);
if (isset($t['reader_pool'])) {
unset($t['reader_pool']);
}
if (isset($t['readers'])) {
unset($t['readers']);
}
return array_keys($t);
}
public function __wakeup() public function __wakeup()
{ {
@ -160,7 +116,6 @@ class MTProto
\danog\MadelineProto\Logger::log(['Serialization is out of date, reconstructing object!'], Logger::WARNING); \danog\MadelineProto\Logger::log(['Serialization is out of date, reconstructing object!'], Logger::WARNING);
$this->__construct($this->settings); $this->__construct($this->settings);
} }
$this->setup_threads();
$this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']); $this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']);
if ($this->authorized && $this->settings['updates']['handle_updates']) { if ($this->authorized && $this->settings['updates']['handle_updates']) {
\danog\MadelineProto\Logger::log(['Getting updates after deserialization...'], Logger::NOTICE); \danog\MadelineProto\Logger::log(['Getting updates after deserialization...'], Logger::NOTICE);
@ -329,7 +284,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
'accept_calls' => true, // Should I accept calls? Can be true, false or on array of user ids from which to accept calls 'accept_calls' => true, // Should I accept calls? Can be true, false or on array of user ids from which to accept calls
], ],
'threading' => [ 'threading' => [
'allow_threading' => false, // Should I use threading, if it is enabled? 'allow_threading' => true, // Should I use threading, if it is enabled?
'handler_workers' => 10, // How many workers should every message handler pool of each socket reader have 'handler_workers' => 10, // How many workers should every message handler pool of each socket reader have
], ],
'pwr' => ['pwr' => false, 'db_token' => false, 'strict' => false], 'pwr' => ['pwr' => false, 'db_token' => false, 'strict' => false],
@ -389,7 +344,6 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
$this->datacenter->dc_connect($new_dc); $this->datacenter->dc_connect($new_dc);
} }
} }
$this->setup_threads();
$this->init_authorization(); $this->init_authorization();
if ($old !== $this->datacenter->get_dcs()) { if ($old !== $this->datacenter->get_dcs()) {
$this->connect_to_all_dcs(); $this->connect_to_all_dcs();

View File

@ -508,85 +508,6 @@ trait AuthKeyHandler
return $this->dh_config = $dh_config; return $this->dh_config = $dh_config;
} }
private $temp_requested_calls = [];
private $calls = [];
public function accept_call($params)
{
$dh_config = $this->get_dh_config();
\danog\MadelineProto\Logger::log(['Generating b...'], \danog\MadelineProto\Logger::VERBOSE);
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
$params['g_a'] = new \phpseclib\Math\BigInteger($params['g_a'], 256);
$this->check_G($params['g_a'], $dh_config['p']);
$key = ['auth_key' => str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => 65, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'protocol' => $params['protocol'], 'connection' => $params['connection'], 'alternative_connections' => $params['alternative_connections']];
//$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'layer' => 8, 'ttl' => PHP_INT_MAX, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0]];
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
$this->check_G($g_b, $dh_config['p']);
$this->handle_pending_updates();
}
public function request_call($user)
{
$user = $this->get_info($user)['InputUser'];
\danog\MadelineProto\Logger::log(['Calling '.$user['user_id'].'...'], \danog\MadelineProto\Logger::VERBOSE);
$dh_config = $this->get_dh_config();
\danog\MadelineProto\Logger::log(['Generating a...'], \danog\MadelineProto\Logger::VERBOSE);
$a = new \phpseclib\Math\BigInteger($this->random(256), 256);
\danog\MadelineProto\Logger::log(['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' => $g_a->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'min_layer' => $this->settings['tl_schema']['layer'], 'max_layer' => $this->settings['tl_schema']['layer']]], ['datacenter' => $this->datacenter->curdc]);
$res = $this->method_call('phone.requestCall', ['user_id' => $user, 'g_a' => $g_a->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'min_layer' => 65, 'max_layer' => 65, 'udp_reflector' => true]], ['datacenter' => $this->datacenter->curdc]);
$this->temp_requested_calls[$res['phone_call']['id']] = $a;
$this->handle_pending_updates();
$this->get_updates_difference();
return $res['phone_call']['id'];
}
public function complete_call($params)
{
if ($this->call_status($params['id']) !== 1) {
\danog\MadelineProto\Logger::log(['Could not find and complete secret chat '.$params['id']]);
return false;
}
$dh_config = $this->get_dh_config();
$params['g_a_or_b'] = new \phpseclib\Math\BigInteger($params['g_a_or_b'], 256);
$this->check_G($params['g_a_or_b'], $dh_config['p']);
$key = ['auth_key' => str_pad($params['g_a_or_b']->powMod($this->temp_requested_secret_chats[$params['id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
unset($this->temp_requested_calls[$params['id']]);
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
if ($key['fingerprint'] !== $params['key_fingerprint']) {
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
}
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => 65, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'protocol' => $params['protocol'], 'connection' => $params['connection'], 'alternative_connections' => $params['alternative_connections']];
$this->handle_pending_updates();
}
public function call_status($id)
{
if (isset($this->calls[$id])) {
return 2;
}
if (isset($this->temp_requested_calls[$id])) {
return 1;
}
return 0;
}
public function get_secret_chat($chat)
{
return $this->secret_chats[$chat];
}
public function bind_temp_auth_key($expires_in, $datacenter) public function bind_temp_auth_key($expires_in, $datacenter)
{ {
for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) { for ($retry_id_total = 1; $retry_id_total <= $this->settings['max_tries']['authorization']; $retry_id_total++) {

View File

@ -52,7 +52,7 @@ trait CallHandler
while ($server_answer === null && $res_count++ < $this->settings['max_tries']['response'] + 1) { // Loop until we get a response, loop for a max of $this->settings['max_tries']['response'] times while ($server_answer === null && $res_count++ < $this->settings['max_tries']['response'] + 1) { // Loop until we get a response, loop for a max of $this->settings['max_tries']['response'] times
try { try {
\danog\MadelineProto\Logger::log(['Getting response (try number '.$res_count.' for '.$method.')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(['Getting response (try number '.$res_count.' for '.$method.')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$this->start_threads(); //$this->start_threads();
if (!isset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']) || !isset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']]['content'])) { // Checks if I have received the response to the called method, if not continue looping if (!isset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']) || !isset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']]['content'])) { // Checks if I have received the response to the called method, if not continue looping
if ($only_updates) { if ($only_updates) {
if ($update_count > 50) { if ($update_count > 50) {
@ -86,7 +86,7 @@ trait CallHandler
throw new \danog\MadelineProto\Exception("Couldn't get response"); throw new \danog\MadelineProto\Exception("Couldn't get response");
} }
if (!isset($server_answer['_'])) { if (!isset($server_answer['_'])) {
\danog\MadelineProto\Logger::log(['Response does not have a type!', $server_answer], \danog\MadelineProto\Logger::FATAL_ERROR); return $server_answer;
} }
switch ($server_answer['_']) { switch ($server_answer['_']) {
case 'rpc_error': case 'rpc_error':

View File

@ -340,6 +340,9 @@ trait TL
if ($constructorData['predicate'] === 'messageEntityMentionName') { if ($constructorData['predicate'] === 'messageEntityMentionName') {
$constructorData = $this->constructors->find_by_predicate('inputMessageEntityMentionName'); $constructorData = $this->constructors->find_by_predicate('inputMessageEntityMentionName');
} }
if ($constructorData['predicate'] === 'dataJSON') {
$object['data'] = json_encode($object['data']);
}
if (!$bare) { if (!$bare) {
$concat .= \danog\PHP\Struct::pack('<i', $constructorData['id']); $concat .= \danog\PHP\Struct::pack('<i', $constructorData['id']);
} }
@ -444,7 +447,7 @@ trait TL
} elseif (!is_object($bytes_io)) { } elseif (!is_object($bytes_io)) {
throw new Exception('An invalid bytes_io handle was provided.'); throw new Exception('An invalid bytes_io handle was provided.');
} }
//\danog\MadelineProto\Logger::log(['Deserializing '.$type['type'].' at byte '.$bytes_io->pos); //\danog\MadelineProto\Logger::log(['Deserializing '.$type['type'].' at byte '.$bytes_io->pos]);
switch ($type['type']) { switch ($type['type']) {
case 'Bool': case 'Bool':
return $this->deserialize_bool($bytes_io->read(4)); return $this->deserialize_bool($bytes_io->read(4));
@ -570,7 +573,9 @@ trait TL
if (isset($x['flags'])) { // I don't think we need this anymore if (isset($x['flags'])) { // I don't think we need this anymore
unset($x['flags']); unset($x['flags']);
} }
if ($x['_'] === 'dataJSON') {
return json_decode($x['data'], true);
}
return $x; return $x;
} }
} }

View File

@ -51,7 +51,7 @@ class SocketReader extends \Threaded implements \Collectable
try { try {
$this->API->recv_message($this->current); $this->API->recv_message($this->current);
$handler_pool->submit(new SocketHandler($this->API, $this->current)); $handler_pool->submit(new SocketHandler($this->API, $this->current));
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\NothingInTheSocketException $e) {
} }
} }
while ($handler_pool->collect()); while ($handler_pool->collect());

View File

@ -0,0 +1,102 @@
<?php
/*
Copyright 2016-2017 Daniil Gentili
(https://daniil.it)
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/>.
*/
namespace danog\MadelineProto\VoIP;
/**
* Manages the creation of the authorization key.
*
* https://core.telegram.org/mtproto/auth_key
* https://core.telegram.org/mtproto/samples-auth_key
*/
trait AuthKeyHandler
{
private $temp_requested_calls = [];
private $calls = [];
public function accept_call($params)
{
$dh_config = $this->get_dh_config();
$phone_config = $this->method_call('phone.getCallConfig');
$b = new \phpseclib\Math\BigInteger($this->random(256), 256);
$params['g_a'] = new \phpseclib\Math\BigInteger($params['g_a'], 256);
$this->check_G($params['g_a'], $dh_config['p']);
$key = ['auth_key' => str_pad($params['g_a']->powMod($b, $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
$this->calls[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => 65, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'protocol' => $params['protocol'], 'connection' => $params['connection'], 'alternative_connections' => $params['alternative_connections']];
//$this->calls[$params['id']] = ['key' => $key, 'admin' => false, 'user_id' => $params['admin_id'], 'InputEncryptedChat' => ['_' => 'inputEncryptedChat', 'chat_id' => $params['id'], 'access_hash' => $params['access_hash']], 'in_seq_no_x' => 1, 'out_seq_no_x' => 0, 'layer' => 8, 'ttl' => PHP_INT_MAX, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0]];
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
$this->check_G($g_b, $dh_config['p']);
$this->handle_pending_updates();
}
public function request_call($user)
{
$user = $this->get_info($user)['InputUser'];
\danog\MadelineProto\Logger::log(['Calling '.$user['user_id'].'...'], \danog\MadelineProto\Logger::VERBOSE);
$dh_config = $this->get_dh_config();
$phone_config = $this->method_call('phone.getCallConfig', [], ['datacenter' => $this->datacenter->curdc]);
\danog\MadelineProto\Logger::log(['Generating a...'], \danog\MadelineProto\Logger::VERBOSE);
$a = new \phpseclib\Math\BigInteger($this->random(256), 256);
\danog\MadelineProto\Logger::log(['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_reflector' => true, 'min_layer' => $this->settings['tl_schema']['layer'], 'max_layer' => $this->settings['tl_schema']['layer']]], ['datacenter' => $this->datacenter->curdc]);
$this->temp_requested_calls[$res['phone_call']['id']] = $a;
$this->handle_pending_updates();
$this->get_updates_difference();
return $res['phone_call']['id'];
}
public function complete_call($params)
{
if ($this->call_status($params['id']) !== 1) {
\danog\MadelineProto\Logger::log(['Could not find and complete secret chat '.$params['id']]);
return false;
}
$dh_config = $this->get_dh_config();
$params['g_a_or_b'] = new \phpseclib\Math\BigInteger($params['g_a_or_b'], 256);
$this->check_G($params['g_a_or_b'], $dh_config['p']);
$key = ['auth_key' => str_pad($params['g_a_or_b']->powMod($this->temp_requested_calls[$params['id']], $dh_config['p'])->toBytes(), 256, chr(0), \STR_PAD_LEFT)];
unset($this->temp_requested_calls[$params['id']]);
$key['fingerprint'] = substr(sha1($key['auth_key'], true), -8);
if ($key['fingerprint'] !== $params['key_fingerprint']) {
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
}
$key['visualization_orig'] = substr(sha1($key['auth_key'], true), 16);
$key['visualization_46'] = substr(hash('sha256', $key['auth_key'], true), 20);
$this->calls[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputPhoneCall' => ['id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputPhoneCall'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'layer' => 65, 'ttr' => 100, 'updated' => time(), 'incoming' => [], 'outgoing' => [], 'created' => time(), 'rekeying' => [0], 'protocol' => $params['protocol'], 'connection' => $params['connection'], 'alternative_connections' => $params['alternative_connections']];
$this->handle_pending_updates();
}
public function call_status($id)
{
if (isset($this->calls[$id])) {
return 2;
}
if (isset($this->temp_requested_calls[$id])) {
return 1;
}
return 0;
}
public function get_secret_chat($chat)
{
return $this->calls[$chat];
}
}

View File

@ -66,7 +66,7 @@ if ($MadelineProto === false) {
} }
$message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd)' : ('Travis ci tests in progress: commit '.getenv('TRAVIS_COMMIT').', job '.getenv('TRAVIS_JOB_NUMBER').', PHP version: '.getenv('TRAVIS_PHP_VERSION')); $message = (getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd)' : ('Travis ci tests in progress: commit '.getenv('TRAVIS_COMMIT').', job '.getenv('TRAVIS_JOB_NUMBER').', PHP version: '.getenv('TRAVIS_PHP_VERSION'));
//$MadelineProto->API->request_secret_chat('@Harold_Saxon'); //$MadelineProto->API->request_call('@danogentili');
echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL; echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL;
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $MadelineProto).' bytes'.PHP_EOL; echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $MadelineProto).' bytes'.PHP_EOL;
echo 'Size of MadelineProto instance is '.strlen(serialize($MadelineProto)).' bytes'.PHP_EOL; echo 'Size of MadelineProto instance is '.strlen(serialize($MadelineProto)).' bytes'.PHP_EOL;