Killed fread with fire, improved peer handling, written basic update handling features, written static class for serializing and deserializing MadelineProto easily, fixed lots of bugs, more stuff kek
This commit is contained in:
parent
7515530b37
commit
84abb27f18
|
@ -71,3 +71,4 @@ session.mad
|
|||
*.madeline
|
||||
enc.tar.xz
|
||||
a
|
||||
web_data.php
|
||||
|
|
11
README.md
11
README.md
|
@ -215,14 +215,15 @@ var_dump($authorization);
|
|||
|
||||
var_dump($MadelineProto->resolve_username('@Palmas2012')); // Always use this method to resolve usernames, but you won't need to call this to get info about peers, as get_peer and get_input_peer will call it for you if needed
|
||||
|
||||
$mention = $MadelineProto->get_peer('@veetaw'); // Returns an object of type User or Chat
|
||||
$mention = $MadelineProto->constructor2inputpeer($mention); // Converts an object of type User or Chat to an object of type inputPeer
|
||||
|
||||
$message = "I've installed MadelineProto!";
|
||||
|
||||
$mention = $MadelineProto->get_info('@@NonSonoGioTech'); // Returns the following array: ['constructor' => $constructor, 'inputPeer' => $inputPeer, 'inputType' => $inputType, 'Peer' => $Peer, 'id' => $id, 'botApiId' => $bot_api_id]
|
||||
$mention = $mention['inputType']; // Selects only the inputType object
|
||||
|
||||
foreach (['@pwrtelegramgroup', '@pwrtelegramgroupita'] as $peer) {
|
||||
$peer = $MadelineProto->get_input_peer($peer);
|
||||
$peer = $MadelineProto->get_info($peer)['inputPeer']; // Select the inputPeerType (alias inputPeer) object
|
||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => strlen($message), 'user_id' => $mention]]]);
|
||||
var_dump($sentMessage);
|
||||
\danog\MadelineProto\Logger::log($sentMessage);
|
||||
}
|
||||
|
||||
// The above works with bots too
|
||||
|
|
|
@ -219,14 +219,15 @@ var_dump($authorization);
|
|||
|
||||
var_dump($MadelineProto->resolve_username('@Palmas2012')); // Always use this method to resolve usernames, but you won't need to call this to get info about peers, as get_peer and get_input_peer will call it for you if needed
|
||||
|
||||
$mention = $MadelineProto->get_peer('@veetaw'); // Returns an object of type User or Chat
|
||||
$mention = $MadelineProto->constructor2inputpeer($mention); // Converts an object of type User or Chat to an object of type inputPeer
|
||||
|
||||
$message = "I've installed MadelineProto!";
|
||||
|
||||
$mention = $MadelineProto->get_info('@@NonSonoGioTech'); // Returns the following array: ['constructor' => $constructor, 'inputPeer' => $inputPeer, 'inputType' => $inputType, 'Peer' => $Peer, 'id' => $id, 'botApiId' => $bot_api_id]
|
||||
$mention = $mention['inputType']; // Selects only the inputType object
|
||||
|
||||
foreach (['@pwrtelegramgroup', '@pwrtelegramgroupita'] as $peer) {
|
||||
$peer = $MadelineProto->get_input_peer($peer);
|
||||
$peer = $MadelineProto->get_info($peer)['inputPeer']; // Select the inputPeerType (alias inputPeer) object
|
||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => strlen($message), 'user_id' => $mention]]]);
|
||||
var_dump($sentMessage);
|
||||
\danog\MadelineProto\Logger::log($sentMessage);
|
||||
}
|
||||
|
||||
// The above works with bots too
|
||||
|
|
BIN
enc.tar.xz.enc
BIN
enc.tar.xz.enc
Binary file not shown.
|
@ -16,6 +16,7 @@ class API extends APIFactory
|
|||
{
|
||||
use \danog\MadelineProto\Wrappers\Login;
|
||||
use \danog\MadelineProto\Wrappers\PeerHandler;
|
||||
use \danog\MadelineProto\Wrappers\SettingsManager;
|
||||
|
||||
public $API;
|
||||
public $settings;
|
||||
|
@ -23,6 +24,11 @@ class API extends APIFactory
|
|||
|
||||
public function __construct($params = [])
|
||||
{
|
||||
// Detect 64 bit
|
||||
if (PHP_INT_SIZE < 8) {
|
||||
throw new Exception('MadelineProto supports only 64 bit systems ATM');
|
||||
}
|
||||
|
||||
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
||||
$this->API = new MTProto($params);
|
||||
|
||||
|
@ -45,6 +51,7 @@ class API extends APIFactory
|
|||
|
||||
public function __wakeup()
|
||||
{
|
||||
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
||||
$this->APIFactory();
|
||||
}
|
||||
|
||||
|
|
|
@ -162,8 +162,12 @@ class Connection extends Tools
|
|||
if (!(get_resource_type($this->sock) == 'file' || get_resource_type($this->sock) == 'stream')) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
$packet = stream_get_contents($this->sock, $length);
|
||||
if (strlen($packet) != $length) {
|
||||
throw new \danog\MadelineProto\Exception("WARNING: Wrong length was read (should've read ".($length).", read ".strlen($packet).")!");
|
||||
}
|
||||
|
||||
return fread($this->sock, $length);
|
||||
return $packet;
|
||||
break;
|
||||
case 'http':
|
||||
case 'https':
|
||||
|
@ -193,19 +197,20 @@ class Connection extends Tools
|
|||
if ($in_seq_no != $this->in_seq_no) {
|
||||
throw new Exception('Incoming seq_no mismatch');
|
||||
}
|
||||
|
||||
$payload = $this->fopen_and_write('php://memory', 'rw+b', substr($packet, 4, $packet_length - 12));
|
||||
break;
|
||||
case 'tcp_intermediate':
|
||||
$packet_length_data = $this->sock->read(4);
|
||||
$packet_length_data = $this->read(4);
|
||||
if (strlen($packet_length_data) < 4) {
|
||||
throw new Exception('Nothing in the socket!');
|
||||
}
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data)[0];
|
||||
$packet = $this->sock->read($packet_length);
|
||||
$packet = $this->read($packet_length);
|
||||
$payload = $this->fopen_and_write('php://memory', 'rw+b', $packet);
|
||||
break;
|
||||
case 'tcp_abridged':
|
||||
$packet_length_data = $this->sock->read(1);
|
||||
$packet_length_data = $this->read(1);
|
||||
if (strlen($packet_length_data) < 1) {
|
||||
throw new Exception('Nothing in the socket!');
|
||||
}
|
||||
|
@ -213,10 +218,10 @@ class Connection extends Tools
|
|||
if ($packet_length < 127) {
|
||||
$packet_length <<= 2;
|
||||
} else {
|
||||
$packet_length_data = $this->sock->read(3);
|
||||
$packet_length_data = $this->read(3);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data.pack('x'))[0] << 2;
|
||||
}
|
||||
$packet = $this->sock->read($packet_length);
|
||||
$packet = $this->read($packet_length);
|
||||
$payload = $this->fopen_and_write('php://memory', 'rw+b', $packet);
|
||||
break;
|
||||
case 'http':
|
||||
|
|
|
@ -32,14 +32,42 @@ class MTProto extends PrimeModule
|
|||
public $settings = [];
|
||||
public $config = ['expires' => -1];
|
||||
public $ipv6 = false;
|
||||
|
||||
public $should_serialize = true;
|
||||
|
||||
public function __construct($settings = [])
|
||||
{
|
||||
// Detect 64 bit
|
||||
if (PHP_INT_SIZE < 8) {
|
||||
throw new Exception('MadelineProto supports only 64 bit systems ATM');
|
||||
}
|
||||
// Parse settings
|
||||
$this->parse_settings($settings);
|
||||
|
||||
// Setup logger
|
||||
$this->setup_logger();
|
||||
|
||||
// Connect to servers
|
||||
\danog\MadelineProto\Logger::log('Istantiating DataCenter...');
|
||||
$this->datacenter = new DataCenter($this->settings['connection'], $this->settings['connection_settings']);
|
||||
|
||||
// Load rsa key
|
||||
\danog\MadelineProto\Logger::log('Loading RSA key...');
|
||||
$this->key = new RSA($settings['authorization']['rsa_key']);
|
||||
|
||||
// Istantiate TL class
|
||||
\danog\MadelineProto\Logger::log('Translating tl schemas...');
|
||||
$this->tl = new TL\TL($this->settings['tl_schema']['src']);
|
||||
|
||||
$this->switch_dc(2, true);
|
||||
$this->get_config();
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->setup_logger();
|
||||
$this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']);
|
||||
$this->reset_session();
|
||||
if ($this->datacenter->authorized) {
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
}
|
||||
public function parse_settings($settings) {
|
||||
// Detect ipv6
|
||||
$google = '';
|
||||
try {
|
||||
|
@ -161,9 +189,13 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
|||
'response' => 5, // How many times should I try to get a response of a query before throwing an exception
|
||||
],
|
||||
'msg_array_limit' => [ // How big should be the arrays containing the incoming and outgoing messages?
|
||||
'incoming' => 30,
|
||||
'outgoing' => 30,
|
||||
'incoming' => 100,
|
||||
'outgoing' => 100,
|
||||
],
|
||||
'updates' => [
|
||||
'updates_array_limit' => 1000, // How big should be the array containing the updates processed with the default example_update_handler callback
|
||||
'callback' => [$this, 'get_updates_update_handler'] // A callable function that will be called every time an update is received, must accept an array (for the update) as the only parameter
|
||||
]
|
||||
];
|
||||
foreach ($default_settings as $key => $param) {
|
||||
if (!isset($settings[$key])) {
|
||||
|
@ -184,36 +216,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
|||
unset($settings['connection_settings']['all']);
|
||||
}
|
||||
$this->settings = $settings;
|
||||
|
||||
// Setup logger
|
||||
$this->setup_logger();
|
||||
|
||||
// Connect to servers
|
||||
\danog\MadelineProto\Logger::log('Istantiating DataCenter...');
|
||||
$this->datacenter = new DataCenter($this->settings['connection'], $this->settings['connection_settings']);
|
||||
|
||||
// Load rsa key
|
||||
\danog\MadelineProto\Logger::log('Loading RSA key...');
|
||||
$this->key = new RSA($settings['authorization']['rsa_key']);
|
||||
|
||||
// Istantiate TL class
|
||||
\danog\MadelineProto\Logger::log('Translating tl schemas...');
|
||||
$this->tl = new TL\TL($this->settings['tl_schema']['src']);
|
||||
|
||||
$this->switch_dc(2, true);
|
||||
$this->get_config();
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->setup_logger();
|
||||
$this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']);
|
||||
$this->reset_session();
|
||||
if ($this->datacenter->authorized) {
|
||||
$this->get_updates_state();
|
||||
}
|
||||
}
|
||||
|
||||
public function setup_logger()
|
||||
{
|
||||
if (!\danog\MadelineProto\Logger::$constructed) {
|
||||
|
@ -243,15 +246,14 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
|||
if (!isset($this->datacenter->sockets[$new_dc])) {
|
||||
$this->datacenter->dc_connect($new_dc);
|
||||
$this->init_authorization();
|
||||
$this->config = $this->write_client_info('help.getConfig');
|
||||
$this->parse_config();
|
||||
|
||||
$this->get_config($this->write_client_info('help.getConfig'));
|
||||
$this->get_nearest_dc($allow_nearest_dc_switch);
|
||||
}
|
||||
if (
|
||||
(isset($this->datacenter->sockets[$old_dc]->authorized) && $this->datacenter->sockets[$old_dc]->authorized) &&
|
||||
!(isset($this->datacenter->sockets[$new_dc]->authorized) && $this->datacenter->sockets[$new_dc]->authorized && $this->datacenter->sockets[$new_dc]->authorization['user']['id'] === $this->datacenter->sockets[$old_dc]->authorization['user']['id'])
|
||||
) {
|
||||
$this->should_serialize = true;
|
||||
$this->datacenter->curdc = $old_dc;
|
||||
$exported_authorization = $this->method_call('auth.exportAuthorization', ['dc_id' => $new_dc]);
|
||||
$this->datacenter->curdc = $new_dc;
|
||||
|
@ -273,6 +275,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
|||
if ($this->datacenter->auth_key == null) {
|
||||
\danog\MadelineProto\Logger::log('Generating permanent authorization key...');
|
||||
$this->datacenter->auth_key = $this->create_auth_key(-1);
|
||||
$this->should_serialize = true;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log('Generating temporary authorization key...');
|
||||
$this->datacenter->temp_auth_key = $this->create_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in']);
|
||||
|
@ -306,21 +309,22 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
|||
if ($nearest_dc['nearest_dc'] != $nearest_dc['this_dc'] && $allow_switch) {
|
||||
$this->switch_dc($nearest_dc['nearest_dc']);
|
||||
$this->settings['connection_settings']['default_dc'] = $nearest_dc['nearest_dc'];
|
||||
$this->should_serialize = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_config()
|
||||
public function get_config($config = [])
|
||||
{
|
||||
if ($this->config['expires'] > time()) {
|
||||
return;
|
||||
}
|
||||
$this->config = $this->method_call('help.getConfig');
|
||||
$this->config = empty($config) ? $this->method_call('help.getConfig') : $config;
|
||||
$this->should_serialize = true;
|
||||
$this->parse_config();
|
||||
}
|
||||
|
||||
public function parse_config()
|
||||
{
|
||||
\danog\MadelineProto\Logger::log('Received config!', $this->config);
|
||||
foreach ($this->config['dc_options'] as $dc) {
|
||||
$test = $this->config['test_mode'] ? 'test' : 'main';
|
||||
$ipv6 = ($dc['ipv6'] ? 'ipv6' : 'ipv4');
|
||||
|
@ -329,5 +333,6 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
|||
$this->settings['connection'][$test][$ipv6][$id] = $dc;
|
||||
}
|
||||
unset($this->config['dc_options']);
|
||||
\danog\MadelineProto\Logger::log('Updated config!', $this->config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ trait CallHandler
|
|||
foreach (range(1, $this->settings['max_tries']['query']) as $count) {
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log('Calling method (try number '.$count.' for '.$method.')...');
|
||||
|
||||
$args = $this->tl->get_named_method_args($method, $args);
|
||||
$int_message_id = $this->send_message($this->tl->serialize_method($method, $args), $this->tl->content_related($method), $message_id);
|
||||
$this->datacenter->outgoing_messages[$int_message_id]['content'] = ['method' => $method, 'args' => $args];
|
||||
|
@ -35,7 +36,7 @@ trait CallHandler
|
|||
\danog\MadelineProto\Logger::log('Getting response (try number '.$res_count.' for '.$method.')...');
|
||||
$this->recv_message();
|
||||
$this->handle_messages();
|
||||
if (!isset($this->datacenter->incoming_messages[$this->datacenter->outgoing_messages[$int_message_id]['response']]['content'])) {
|
||||
if (!isset($this->datacenter->outgoing_messages[$int_message_id]['response']) || !isset($this->datacenter->incoming_messages[$this->datacenter->outgoing_messages[$int_message_id]['response']]['content'])) {
|
||||
continue;
|
||||
}
|
||||
$server_answer = $this->datacenter->incoming_messages[$this->datacenter->outgoing_messages[$int_message_id]['response']]['content'];
|
||||
|
@ -94,6 +95,7 @@ trait CallHandler
|
|||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
\danog\MadelineProto\Logger::log('An error occurred while calling method '.$method.': '.$e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine().'. Recreating connection and retrying to call method...');
|
||||
$this->datacenter->close_and_reopen();
|
||||
sleep(1); // To avoid flooding
|
||||
continue;
|
||||
}
|
||||
if ($server_answer == null) {
|
||||
|
@ -113,7 +115,7 @@ trait CallHandler
|
|||
|
||||
foreach (range(1, $this->settings['max_tries']['query']) as $count) {
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log('Sending object (try number '.$count.' for '.$object.')...');
|
||||
\danog\MadelineProto\Logger::log($object == 'msgs_ack' ? 'ack '.$args['msg_ids'][0] : 'Sending object (try number '.$count.' for '.$object.')...');
|
||||
$int_message_id = $this->send_message($this->tl->serialize_object(['type' => $object], $args), $this->tl->content_related($object));
|
||||
$this->datacenter->outgoing_messages[$int_message_id]['content'] = ['method' => $object, 'args' => $args];
|
||||
} catch (Exception $e) {
|
||||
|
|
|
@ -55,7 +55,7 @@ trait MessageHandler
|
|||
{
|
||||
$payload = $this->datacenter->read_message();
|
||||
if (fstat($payload)['size'] == 4) {
|
||||
$error = \danog\PHP\Struct::unpack('<i', fread($payload, 4))[0];
|
||||
$error = \danog\PHP\Struct::unpack('<i', stream_get_contents($payload, 4))[0];
|
||||
if ($error == -404) {
|
||||
if ($this->datacenter->temp_auth_key != null) {
|
||||
\danog\MadelineProto\Logger::log('WARNING: Resetting auth key...');
|
||||
|
@ -68,13 +68,13 @@ trait MessageHandler
|
|||
}
|
||||
throw new \danog\MadelineProto\RPCErrorException($error, $error);
|
||||
}
|
||||
$auth_key_id = fread($payload, 8);
|
||||
$auth_key_id = stream_get_contents($payload, 8);
|
||||
if ($auth_key_id == $this->string2bin('\x00\x00\x00\x00\x00\x00\x00\x00')) {
|
||||
list($message_id, $message_length) = \danog\PHP\Struct::unpack('<QI', fread($payload, 12));
|
||||
list($message_id, $message_length) = \danog\PHP\Struct::unpack('<QI', stream_get_contents($payload, 12));
|
||||
$this->check_message_id($message_id, false);
|
||||
$message_data = fread($payload, $message_length);
|
||||
$message_data = stream_get_contents($payload, $message_length);
|
||||
} elseif ($auth_key_id == $this->datacenter->temp_auth_key['id']) {
|
||||
$message_key = fread($payload, 16);
|
||||
$message_key = stream_get_contents($payload, 16);
|
||||
$encrypted_data = stream_get_contents($payload);
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->temp_auth_key['auth_key'], 'from server');
|
||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||
|
|
|
@ -24,7 +24,10 @@ trait PeerHandler
|
|||
foreach ($users as $key => $user) {
|
||||
switch ($user['_']) {
|
||||
case 'user':
|
||||
$this->chats[$user['id']] = $user;
|
||||
if (!isset($this->chats[$user['id']])) {
|
||||
$this->chats[$user['id']] = $user;
|
||||
$this->should_serialize = true;
|
||||
}
|
||||
case 'userEmpty':
|
||||
break;
|
||||
default:
|
||||
|
@ -40,17 +43,134 @@ trait PeerHandler
|
|||
switch ($chat['_']) {
|
||||
case 'chat':
|
||||
case 'chatEmpty':
|
||||
$this->chats[-$chat['id']] = $chat;
|
||||
if (!isset($this->chats[-$chat['id']])) {
|
||||
$this->should_serialize = true;
|
||||
$this->chats[-$chat['id']] = $chat;
|
||||
}
|
||||
|
||||
case 'chatForbidden':
|
||||
case 'channelEmpty':
|
||||
break;
|
||||
case 'channel':
|
||||
$this->chats[(int) ('-100'.$chat['id'])] = $chat;
|
||||
if (!isset($this->chats[(int) ('-100'.$chat['id'])])) {
|
||||
$this->should_serialize = true;
|
||||
$this->chats[(int) ('-100'.$chat['id'])] = $chat;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid chat provided at key '.$key.': '.var_export($chat, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->should_serialize = true;
|
||||
}
|
||||
|
||||
|
||||
public function get_info($id, $recursive = true)
|
||||
{
|
||||
if (is_array($id)) {
|
||||
switch ($id['_']) {
|
||||
case 'inputPeerSelf':
|
||||
case 'inputPeerSelf':
|
||||
$id = $this->datacenter->authorization['user']['id'];
|
||||
break;
|
||||
case 'user':
|
||||
$id = $id['id'];
|
||||
break;
|
||||
case 'inputPeerUser':
|
||||
case 'inputUser':
|
||||
case 'peerUser':
|
||||
$id = $id['user_id'];
|
||||
break;
|
||||
|
||||
case 'chat':
|
||||
$id = -$id['id'];
|
||||
break;
|
||||
case 'inputPeerChat':
|
||||
case 'peerChat':
|
||||
$id = -$id['chat_id'];
|
||||
break;
|
||||
|
||||
case 'channel':
|
||||
$id = '-100'.$id['id'];
|
||||
break;
|
||||
case 'inputPeerChannel':
|
||||
case 'inputChannel':
|
||||
case 'peerChannel':
|
||||
$id = '-100'.$id['channel_id'];
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given ' . var_export($id, true));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (preg_match('/^channel#/', $id)) $id = str_replace('channel#', '-100', $id);
|
||||
if (preg_match('/^chat#/', $id)) $id = str_replace('chat#', '-', $id);
|
||||
if (preg_match('/^user#/', $id)) $id = str_replace('user#', '', $id);
|
||||
|
||||
if (is_numeric($id)) {
|
||||
$id = (int)$id;
|
||||
if (isset($this->chats[$id])) {
|
||||
return $this->gen_all($this->chats[$id]);
|
||||
}
|
||||
debug_print_backtrace();
|
||||
// if ($recursive) {
|
||||
// }
|
||||
throw new \danog\MadelineProto\Exception("Couldn't find peer by provided chat id ".$id);
|
||||
}
|
||||
$id = str_replace('@', '', $id);
|
||||
foreach ($this->chats as $chat) {
|
||||
if (isset($chat['username']) && $chat['username'] == $id) {
|
||||
return $this->gen_all($chat);
|
||||
}
|
||||
}
|
||||
if ($recursive) {
|
||||
$this->resolve_username($id);
|
||||
|
||||
return $this->get_info($id, false);
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception("Couldn't find peer by provided username ".$id);
|
||||
}
|
||||
|
||||
public function gen_all($constructor) {
|
||||
switch ($constructor['_']) {
|
||||
case 'user':
|
||||
$inputPeer = $constructor['self'] ? ['_' => 'inputPeerSelf'] : ['_' => 'inputPeerUser', 'user_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']];
|
||||
$inputType = $constructor['self'] ? ['_' => 'inputUserSelf'] : ['_' => 'inputUser', 'user_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']];
|
||||
$Peer = ['_' => 'peerUser', 'user_id' => $constructor['id']];
|
||||
$id = $constructor['id'];
|
||||
$bot_api_id = $constructor['id'];
|
||||
break;
|
||||
case 'chat':
|
||||
$inputPeer = ['_' => 'inputPeerChat', 'chat_id' => $constructor['id']];
|
||||
$inputType = [];
|
||||
$Peer = ['_' => 'peerChat', 'chat_id' => $constructor['id']];
|
||||
$id = $constructor['id'];
|
||||
$bot_api_id = -$constructor['id'];
|
||||
break;
|
||||
case 'channel':
|
||||
$inputPeer = ['_' => 'inputPeerChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']];
|
||||
$inputType = ['_' => 'inputChannel', 'channel_id' => $constructor['id'], 'access_hash' => $constructor['access_hash']];
|
||||
$Peer = ['_' => 'peerChannel', 'channel_id' => $constructor['id']];
|
||||
$id = $constructor['id'];
|
||||
$bot_api_id = (int)('-100'.$constructor['id']);
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given ' . var_export($constructor, true));
|
||||
break;
|
||||
}
|
||||
|
||||
return ['constructor' => $constructor, 'inputPeer' => $inputPeer, 'inputType' => $inputType, 'Peer' => $Peer, 'id' => $id, 'botApiId' => $bot_api_id];
|
||||
}
|
||||
|
||||
public function resolve_username($username)
|
||||
{
|
||||
$res = $this->method_call('contacts.resolveUsername', ['username' => str_replace('@', '', $username)]);
|
||||
if ($res['_'] == 'contacts.resolvedPeer') {
|
||||
return $res;
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception('resolve_username returned an unexpected constructor: '.var_export($username, true));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,15 +125,9 @@ trait ResponseHandler
|
|||
$this->datacenter->temp_auth_key['server_salt'] = $response['server_salt'];
|
||||
$this->ack_incoming_message_id($current_msg_id); // Acknowledge that I received the server's response
|
||||
\danog\MadelineProto\Logger::log('new session created');
|
||||
\danog\MadelineProto\Logger::log($response);
|
||||
unset($this->datacenter->new_incoming[$current_msg_id]);
|
||||
if ($this->datacenter->authorized) {
|
||||
$this->get_updates_state();
|
||||
}
|
||||
break;
|
||||
case 'msg_container':
|
||||
|
||||
\danog\MadelineProto\Logger::log($response['messages']);
|
||||
unset($this->datacenter->new_incoming[$current_msg_id]);
|
||||
foreach ($response['messages'] as $message) {
|
||||
$this->check_message_id($message['msg_id'], false, true);
|
||||
|
@ -191,8 +185,6 @@ trait ResponseHandler
|
|||
|
||||
if (isset($this->datacenter->incoming_messages[$response['answer_msg_id']])) {
|
||||
$this->ack_incoming_message_id($response['answer_msg_id']);
|
||||
} else {
|
||||
$this->object_call('msg_resend_req', ['msg_ids' => [$response['answer_msg_id']]]);
|
||||
}
|
||||
break;
|
||||
case 'msg_resend_req':
|
||||
|
|
|
@ -18,19 +18,82 @@ namespace danog\MadelineProto\MTProtoTools;
|
|||
trait UpdateHandler
|
||||
{
|
||||
public $updates_state = [];
|
||||
public $channels_state = [];
|
||||
|
||||
public function update_state($data, $chat_id = 0)
|
||||
{
|
||||
if (!isset($this->updates_state[$chat_id])) {
|
||||
$this->updates_state[$chat_id] = ['date' => 0, 'pts' => 0, 'seq' => 0];
|
||||
public $updates = [];
|
||||
|
||||
public function get_updates_update_handler($update) {
|
||||
if (count($this->updates) > $this->settings['updates']['updates_array_limit']) {
|
||||
array_shift($this->updates);
|
||||
}
|
||||
|
||||
$this->updates_state[$chat_id]['pts'] = (!isset($data['pts']) || $data['pts'] == 0) ? $this->updates_state[$chat_id]['pts'] : $data['pts'];
|
||||
$this->updates_state[$chat_id]['seq'] = (!isset($data['seq']) || $data['seq'] == 0) ? $this->updates_state[$chat_id]['seq'] : $data['seq'];
|
||||
$this->updates_state[$chat_id]['date'] = (!isset($data['date']) || $data['date'] < $this->updates_state[$chat_id]['date']) ? $this->updates_state[$chat_id]['date'] : $data['date'];
|
||||
$this->updates[] = $update;
|
||||
\danog\MadelineProto\Logger::log('Stored ', $update);
|
||||
}
|
||||
|
||||
public function get_updates_state()
|
||||
public function get_updates($offset, $limit = null, $timeout = 0) {
|
||||
sleep($timeout);
|
||||
$this->get_updates_difference();
|
||||
$result = array_slice($this->updates, $offset, $limit, true);
|
||||
$updates = [];
|
||||
foreach ($result as $key => $value) {
|
||||
$updates[] = ['update_id' => $key, 'update' => $value];
|
||||
unset($this->updates[$key]);
|
||||
}
|
||||
return $updates;
|
||||
}
|
||||
|
||||
public function &get_channel_state($channel, $pts = 0) {
|
||||
if (!isset($this->channels_state[$channel])) {
|
||||
$this->channels_state[$channel] = ['pts' => $pts, 'pop_pts' => [], 'pending_seq_updates' =>[]];
|
||||
}
|
||||
return $this->channels_state[$channel];
|
||||
}
|
||||
public function update_channel_state($channel, $data)
|
||||
{
|
||||
$this->get_channel_state($channel);
|
||||
|
||||
$this->channels_state[$channel]['pts'] = (!isset($data['pts']) || $data['pts'] == 0) ? $this->get_channel_state($channel)['pts'] : $data['pts'];
|
||||
}
|
||||
|
||||
public function get_channel_difference($channel)
|
||||
{
|
||||
$this->get_channel_state($channel);
|
||||
|
||||
$difference = $this->method_call('updates.getChannelDifference', ['channel' => $this->get_info('channel#'.$channel)['inputType'], 'filter' => ['_' => 'channelMessagesFilterEmpty'],'pts' => $this->get_channel_state($channel)['pts'], 'limit' => 30]);
|
||||
switch ($difference['_']) {
|
||||
case 'updates.channelDifferenceEmpty':
|
||||
$this->update_channel_state($difference);
|
||||
break;
|
||||
case 'updates.difference':
|
||||
$this->handle_update_messages($difference['new_messages'], $channel);
|
||||
$this->handle_multiple_update($difference['other_updates']);
|
||||
$this->update_channel_state($difference);
|
||||
if (!$difference['final']) {
|
||||
$this->get_channel_difference($channel);
|
||||
}
|
||||
break;
|
||||
case 'updates.differenceTooLong':
|
||||
unset($this->channels_state[$channel]);
|
||||
\danog\MadelineProto\Logger::log('Got updates.differenceTooLong: ', $difference);
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference));
|
||||
break;
|
||||
}
|
||||
}
|
||||
public function update_state($data)
|
||||
{
|
||||
if (empty($this->updates_state)) {
|
||||
$this->updates_state = ['date' => 0, 'pts' => 0, 'seq' => 0, 'pending_seq_updates' => []];
|
||||
}
|
||||
|
||||
$this->updates_state['pts'] = (!isset($data['pts']) || $data['pts'] == 0) ? $this->updates_state['pts'] : $data['pts'];
|
||||
$this->updates_state['seq'] = (!isset($data['seq']) || $data['seq'] == 0) ? $this->updates_state['seq'] : $data['seq'];
|
||||
$this->updates_state['date'] = (!isset($data['date']) || $data['date'] < $this->updates_state['date']) ? $this->updates_state['date'] : $data['date'];
|
||||
}
|
||||
|
||||
|
||||
public function get_updates_difference()
|
||||
{
|
||||
if (empty($this->updates_state)) {
|
||||
return $this->update_state($this->method_call('updates.getState'));
|
||||
|
@ -41,19 +104,15 @@ trait UpdateHandler
|
|||
$this->update_state($difference);
|
||||
break;
|
||||
case 'updates.difference':
|
||||
$this->add_users($difference['users']);
|
||||
$this->add_chats($difference['chats']);
|
||||
$this->handle_update_messages($difference['new_messages']);
|
||||
$this->handle_multiple_update($difference['other_updates']);
|
||||
$this->update_state($difference['state']);
|
||||
break;
|
||||
case 'updates.differenceSlice':
|
||||
$this->add_users($difference['users']);
|
||||
$this->add_chats($difference['chats']);
|
||||
$this->handle_update_messages($difference['new_messages']);
|
||||
$this->handle_multiple_update($difference['other_updates']);
|
||||
$this->update_state($difference['intermediate_state']);
|
||||
$this->get_updates_state();
|
||||
$this->get_updates_difference();
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.var_export($difference));
|
||||
|
@ -65,13 +124,22 @@ trait UpdateHandler
|
|||
{
|
||||
switch ($updates['_']) {
|
||||
case 'updatesTooLong':
|
||||
$this->get_updates_state();
|
||||
$this->get_updates_difference();
|
||||
break;
|
||||
case 'updateShortMessage':
|
||||
case 'updateShortChatMessage':
|
||||
case 'updateShortSentMessage':
|
||||
$update = ['_' => 'updateNewMessage'];
|
||||
$this->handle_update_messages($update, ['date' => $updates['date']]);
|
||||
// case 'updateShortSentMessage':
|
||||
$fromID = isset($updates['from_id']) ? $updates['from_id'] : ($updates['out'] ? $this->datacenter->authorization['user']['id'] : $updates['user_id']);
|
||||
$toID = isset($updates['chat_id'])
|
||||
? $updates['chat_id']
|
||||
: ($updates['out'] ? $updates['user_id'] : $this->datacenter->authorization['user']['id']);
|
||||
|
||||
$message = $updates;
|
||||
$message['_'] = 'message';
|
||||
$message['to_id'] = $toID;
|
||||
$message['from_id'] = $this->get_info($fromID)['Peer'];
|
||||
$update = ['_' => 'updateNewMessage', 'message' => $message, 'pts' => $updates['pts'], 'pts_count' => $updates['pts_count']];
|
||||
$this->handle_update($update, ['date' => $updates['date']]);
|
||||
break;
|
||||
case 'updateShort':
|
||||
$this->handle_update($updates['update'], ['date' => $updates['date']]);
|
||||
|
@ -79,12 +147,13 @@ trait UpdateHandler
|
|||
case 'updatesCombined':
|
||||
$this->add_users($updates['users']);
|
||||
$this->add_chats($updates['chats']);
|
||||
$this->handle_multiple_update($updates['updates']);
|
||||
$this->handle_multiple_update($updates['updates'], ['date' => $updates['date'], 'seq' => $updates['seq'], 'seq_start' => $updates['seq_start']]);
|
||||
break;
|
||||
|
||||
case 'updates':
|
||||
$this->add_users($updates['users']);
|
||||
$this->add_chats($updates['chats']);
|
||||
$this->handle_multiple_update($updates['updates']);
|
||||
$this->handle_multiple_update($updates['updates'], ['date' => $updates['date'], 'seq' => $updates['seq']]);
|
||||
break;
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Unrecognized update received: '.var_export($updates));
|
||||
|
@ -92,22 +161,135 @@ trait UpdateHandler
|
|||
}
|
||||
}
|
||||
|
||||
public function handle_update($update)
|
||||
public function handle_update($update, $options = [])
|
||||
{
|
||||
var_dump($update);
|
||||
$channel_id = false;
|
||||
switch ($update['_']) {
|
||||
case 'updateNewChannelMessage':
|
||||
case 'updateEditChannelMessage':
|
||||
$channel_id = $update['message']['to_id']['channel_id'];
|
||||
break;
|
||||
case 'updateDeleteChannelMessages':
|
||||
$channel_id = $update['channel_id'];
|
||||
break;
|
||||
case 'updateChannelTooLong':
|
||||
$channel_id = $update['channel_id'];
|
||||
if (!isset($this->channels_state[$channel_id])) {
|
||||
return false;
|
||||
}
|
||||
return $this->get_channel_difference($channel_id);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->save_update($update);
|
||||
/*
|
||||
switch ($update['_']) {
|
||||
case 'updateNewMessage':
|
||||
case 'updateEditMessage':
|
||||
case 'updateNewChannelMessage':
|
||||
case 'updateEditChannelMessage':
|
||||
$message = $update['message'];
|
||||
if (isset($message['from_id']) && !isset($this->chats[$message['from_id']]) ||
|
||||
isset($message['fwd_from']['from_id']) && !isset($this->chats[$message['fwd_from']['from_id']]) ||
|
||||
isset($message['fwd_from']['channel_id']) && !isset($this->chats[(int)('-100'.$message['fwd_from']['channel_id'])]) ||
|
||||
!isset($this->get_info($message['to_id'])['bot_api_info'])) {
|
||||
|
||||
\danog\MadelineProto\Logger::log('Not enough data for message update');
|
||||
|
||||
if ($channel_id !== false && isset($this->chats[$channel_id])) {
|
||||
$this->get_channel_difference($channel_id);
|
||||
} else {
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ($channel_id !== false && isset($this->chats[$channel_id])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$pop_pts = false;
|
||||
if ($update['pts']) {
|
||||
$new_pts = $cur_state['pts'] + (isset($update['pts_count']) ? $update['pts_count'] : 0);
|
||||
if ($new_pts < $update['pts']) {
|
||||
\danog\MadelineProto\Logger::log('Pts hole', $cur_state, $update, $this->get_info($channel_id));
|
||||
|
||||
$this->cur_state['pop_pts'][] = $update;
|
||||
|
||||
if ($channel_id && isset($this->chats[$channel_id])) {
|
||||
$this->get_channel_difference($channel_id);
|
||||
} else {
|
||||
$this->get_updates_difference();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($new_pts > $update['pts']) {
|
||||
$cur_state['pts'] = $update['pts'];
|
||||
$pop_pts = true;
|
||||
} else if ($update['pts_count']) {
|
||||
return false;
|
||||
}
|
||||
} else if (!$channel_id && isset($options['seq']) && $options['seq'] > 0) {
|
||||
$seq = $options['seq'];
|
||||
$seq_start = isset($options['seq_start']) ? $options['seq_start'] : $options['seq'];
|
||||
|
||||
|
||||
if ($seq_start != $cur_state['seq'] + 1) {
|
||||
if ($seq_start > $cur_state['seq']) {
|
||||
\danog\MadelineProto\Logger::('Seq hole', $cur_state);
|
||||
|
||||
if (!isset($cur_state['pending_seq_updates'][$seq_start])) {
|
||||
$cur_state['pending_seq_updates'][$seq_start] = ['seq' => $seq, 'date': $options['date'], 'updates' => []];
|
||||
}
|
||||
$cur_state['pending_seq_updates'][$seq_start][] = $update;
|
||||
|
||||
if (!$cur_state.syncPending.seqAwaiting ||
|
||||
$cur_state.syncPending.seqAwaiting < $seq_start) {
|
||||
$cur_state.syncPending.seqAwaiting = $seq_start
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (curState.seq != seq) {
|
||||
curState.seq = seq
|
||||
if (options.date && curState.date < options.date) {
|
||||
curState.date = options.date
|
||||
}
|
||||
popSeq = true
|
||||
}
|
||||
}
|
||||
|
||||
saveUpdate(update)
|
||||
|
||||
if (popPts) {
|
||||
popPendingPtsUpdate(channelID)
|
||||
}
|
||||
else if (popSeq) {
|
||||
popPendingSeqUpdate()
|
||||
}*/
|
||||
}
|
||||
|
||||
public function handle_multiple_update($updates)
|
||||
public function handle_multiple_update($updates, $options = [])
|
||||
{
|
||||
foreach ($updates as $update) {
|
||||
$this->handle_update($update);
|
||||
$this->handle_update($update, $options);
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_update_messages($messages)
|
||||
public function handle_update_messages($messages, $channel = false)
|
||||
{
|
||||
foreach ($messages as $message) {
|
||||
$this->handle_update(['_' => 'updateNewMessage', 'message' => $message, 'pts' => $this->updates_state[0]['pts'], 'pts_count' => 0]);
|
||||
$this->save_update(['_' => $channel == false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => $channel == false ? $this->updates_state['pts'] : $this->get_channel_state($channel)['pts'], 'pts_count' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
public function save_update($update) {
|
||||
$this->settings['updates']['callback']($update);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/*
|
||||
Copyright 2016 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;
|
||||
|
||||
/**
|
||||
* Manages serialization of the MadelineProto instance
|
||||
*/
|
||||
class Serialization {
|
||||
|
||||
public static function serialize($filename, $instance, $force = false) {
|
||||
if ($instance->API->should_serialize || !(file_exists($filename) && !empty(file_get_contents($filename))) || $force) {
|
||||
$instance->API->should_serialize = false;
|
||||
return file_put_contents($filename, serialize($instance));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function deserialize($filename) {
|
||||
return file_exists($filename) ? unserialize(file_get_contents($filename)) : false;
|
||||
}
|
||||
}
|
|
@ -87,7 +87,6 @@ class TL extends \danog\MadelineProto\Tools
|
|||
return \danog\PHP\Struct::pack('<I', $object);
|
||||
case 'long':
|
||||
if (!is_numeric($object)) {
|
||||
var_dump($object);
|
||||
throw new Exception("given value isn't numeric");
|
||||
}
|
||||
|
||||
|
@ -252,42 +251,42 @@ class TL extends \danog\MadelineProto\Tools
|
|||
throw new Exception('An invalid bytes_io handle was provided.');
|
||||
}
|
||||
}
|
||||
//\danog\MadelineProto\Logger::log('Deserializing '.$type['type'].'/'.$subtype.' at byte '.ftell($bytes_io));
|
||||
//\danog\MadelineProto\Logger::log('Deserializing '.$type['type'].' at byte '.ftell($bytes_io));
|
||||
switch ($type['type']) {
|
||||
case 'Bool':
|
||||
return $this->deserialize_bool(fread($bytes_io, 4));
|
||||
return $this->deserialize_bool(stream_get_contents($bytes_io, 4));
|
||||
case 'int':
|
||||
return \danog\PHP\Struct::unpack('<i', fread($bytes_io, 4))[0];
|
||||
return \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
case '#':
|
||||
return \danog\PHP\Struct::unpack('<I', fread($bytes_io, 4))[0];
|
||||
return \danog\PHP\Struct::unpack('<I', stream_get_contents($bytes_io, 4))[0];
|
||||
case 'long':
|
||||
return \danog\PHP\Struct::unpack('<q', fread($bytes_io, 8))[0];
|
||||
return \danog\PHP\Struct::unpack('<q', stream_get_contents($bytes_io, 8))[0];
|
||||
case 'double':
|
||||
return \danog\PHP\Struct::unpack('<d', fread($bytes_io, 8))[0];
|
||||
return \danog\PHP\Struct::unpack('<d', stream_get_contents($bytes_io, 8))[0];
|
||||
case 'int128':
|
||||
return fread($bytes_io, 16);
|
||||
return stream_get_contents($bytes_io, 16);
|
||||
case 'int256':
|
||||
return fread($bytes_io, 32);
|
||||
return stream_get_contents($bytes_io, 32);
|
||||
case 'int512':
|
||||
return fread($bytes_io, 32);
|
||||
return stream_get_contents($bytes_io, 32);
|
||||
case 'string':
|
||||
case 'bytes':
|
||||
$l = \danog\PHP\Struct::unpack('<B', fread($bytes_io, 1))[0];
|
||||
$l = \danog\PHP\Struct::unpack('<B', stream_get_contents($bytes_io, 1))[0];
|
||||
if ($l > 254) {
|
||||
throw new Exception('Length is too big');
|
||||
}
|
||||
if ($l == 254) {
|
||||
$long_len = \danog\PHP\Struct::unpack('<I', fread($bytes_io, 3).$this->string2bin('\x00'))[0];
|
||||
$x = fread($bytes_io, $long_len);
|
||||
$long_len = \danog\PHP\Struct::unpack('<I', stream_get_contents($bytes_io, 3).$this->string2bin('\x00'))[0];
|
||||
$x = stream_get_contents($bytes_io, $long_len);
|
||||
$resto = $this->posmod(-$long_len, 4);
|
||||
if ($resto > 0) {
|
||||
fread($bytes_io, $resto);
|
||||
stream_get_contents($bytes_io, $resto);
|
||||
}
|
||||
} else {
|
||||
$x = fread($bytes_io, $l);
|
||||
$x = stream_get_contents($bytes_io, $l);
|
||||
$resto = $this->posmod(-($l + 1), 4);
|
||||
if ($resto > 0) {
|
||||
fread($bytes_io, $resto);
|
||||
stream_get_contents($bytes_io, $resto);
|
||||
}
|
||||
}
|
||||
if (!is_string($x)) {
|
||||
|
@ -298,14 +297,14 @@ class TL extends \danog\MadelineProto\Tools
|
|||
case 'true':
|
||||
return true;
|
||||
case 'Vector t':
|
||||
$id = \danog\PHP\Struct::unpack('<i', fread($bytes_io, 4))[0];
|
||||
$id = \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
$constructorData = $this->constructors->find_by_id($id);
|
||||
if ($constructorData === false) {
|
||||
throw new Exception('Could not extract type: '.$type['type'].' with id '.$id);
|
||||
}
|
||||
switch ($constructorData['predicate']) {
|
||||
case 'gzip_packed':
|
||||
return $this->deserialize(gzdecode($this->deserialize($bytes_io, ['type' => 'string'])));
|
||||
return $this->deserialize($this->fopen_and_write('php://memory', 'rw+b', gzdecode($this->deserialize($bytes_io, ['type' => 'string']))));
|
||||
case 'Vector t':
|
||||
case 'vector':
|
||||
break;
|
||||
|
@ -313,7 +312,7 @@ class TL extends \danog\MadelineProto\Tools
|
|||
throw new Exception('Invalid vector constructor: '.$constructorData['predicate']);
|
||||
}
|
||||
case 'vector':
|
||||
$count = \danog\PHP\Struct::unpack('<i', fread($bytes_io, 4))[0];
|
||||
$count = \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
$result = [];
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$result[] = $this->deserialize($bytes_io, ['type' => $type['subtype']]);
|
||||
|
@ -330,7 +329,7 @@ class TL extends \danog\MadelineProto\Tools
|
|||
} else {
|
||||
$constructorData = $this->constructors->find_by_predicate($type['type']);
|
||||
if ($constructorData === false) {
|
||||
$id = \danog\PHP\Struct::unpack('<i', fread($bytes_io, 4))[0];
|
||||
$id = \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
$constructorData = $this->constructors->find_by_id($id);
|
||||
if ($constructorData === false) {
|
||||
throw new Exception('Could not extract type: '.$type['type'].' with id '.$id);
|
||||
|
@ -338,7 +337,7 @@ class TL extends \danog\MadelineProto\Tools
|
|||
}
|
||||
}
|
||||
if ($constructorData['predicate'] == 'gzip_packed') {
|
||||
return $this->deserialize(gzdecode($this->deserialize($bytes_io, ['type' => 'string'])));
|
||||
return $this->deserialize($this->fopen_and_write('php://memory', 'rw+b', gzdecode($this->deserialize($bytes_io, ['type' => 'string']))));
|
||||
}
|
||||
$x = ['_' => $constructorData['predicate']];
|
||||
foreach ($constructorData['params'] as $arg) {
|
||||
|
@ -365,7 +364,6 @@ class TL extends \danog\MadelineProto\Tools
|
|||
if (isset($x['flags'])) { // I don't think we need this anymore
|
||||
unset($x['flags']);
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class Tools
|
|||
{
|
||||
$pos = ftell($handle);
|
||||
fseek($handle, 0);
|
||||
$content = fread($handle, fstat($handle)['size']);
|
||||
$content = stream_get_contents($handle, fstat($handle)['size']);
|
||||
fseek($handle, $pos);
|
||||
|
||||
return $content;
|
||||
|
|
|
@ -24,8 +24,11 @@ trait Login
|
|||
}
|
||||
$this->API->datacenter->authorized = false;
|
||||
$this->API->datacenter->authorization = null;
|
||||
$this->API->updates = [];
|
||||
\danog\MadelineProto\Logger::log('Logged out successfully!');
|
||||
|
||||
$this->API->should_serialize = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -45,7 +48,12 @@ trait Login
|
|||
]
|
||||
);
|
||||
$this->API->datacenter->authorized = true;
|
||||
$this->API->get_updates_state();
|
||||
$this->API->get_updates_difference();
|
||||
|
||||
|
||||
$this->API->should_serialize = true;
|
||||
|
||||
$this->API->updates = [];
|
||||
\danog\MadelineProto\Logger::log('Logged in successfully!');
|
||||
|
||||
return $this->API->datacenter->authorization;
|
||||
|
@ -70,6 +78,9 @@ trait Login
|
|||
);
|
||||
$this->API->datacenter->authorization['phone_number'] = $number;
|
||||
$this->API->datacenter->waiting_code = true;
|
||||
$this->API->should_serialize = true;
|
||||
$this->API->updates = [];
|
||||
|
||||
\danog\MadelineProto\Logger::log('Code sent successfully! Once you receive the code you should use the complete_phone_login function.');
|
||||
|
||||
return $this->API->datacenter->authorization;
|
||||
|
@ -91,7 +102,9 @@ trait Login
|
|||
);
|
||||
$this->API->datacenter->waiting_code = false;
|
||||
$this->API->datacenter->authorized = true;
|
||||
$this->API->get_updates_state();
|
||||
$this->API->get_updates_difference();
|
||||
$this->API->should_serialize = true;
|
||||
|
||||
\danog\MadelineProto\Logger::log('Logged in successfully!');
|
||||
|
||||
return $this->API->datacenter->authorization;
|
||||
|
|
|
@ -17,56 +17,15 @@ namespace danog\MadelineProto\Wrappers;
|
|||
*/
|
||||
trait PeerHandler
|
||||
{
|
||||
public function get_peer($id, $recursive = true)
|
||||
{
|
||||
if (is_numeric($id)) {
|
||||
if (isset($this->API->chats[$id])) {
|
||||
return $this->API->chats[$id];
|
||||
}
|
||||
// if ($recursive) {
|
||||
// }
|
||||
throw new \danog\MadelineProto\Exception("Couldn't find peer by provided chat id ".$id);
|
||||
}
|
||||
$id = str_replace('@', '', $id);
|
||||
foreach ($this->API->chats as $chat) {
|
||||
if (isset($chat['username']) && $chat['username'] == $id) {
|
||||
return $chat;
|
||||
}
|
||||
}
|
||||
if ($recursive) {
|
||||
$this->resolve_username($id);
|
||||
|
||||
return $this->get_peer($id, false);
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception("Couldn't find peer by provided username ".$id);
|
||||
public function get_info($id, $recursive = true) {
|
||||
return $this->API->get_info($id, $recursive);
|
||||
}
|
||||
|
||||
public function get_input_peer($id)
|
||||
{
|
||||
return $this->constructor2inputpeer($this->get_peer($id));
|
||||
public function gen_all($constructor) {
|
||||
return $this->API->gen_all($constructor);
|
||||
}
|
||||
|
||||
public function constructor2inputpeer($peer)
|
||||
{
|
||||
switch ($peer['_']) {
|
||||
case 'user':
|
||||
return $peer['self'] ? ['_' => 'inputPeerSelf'] : ['_' => 'inputPeerUser', 'user_id' => $peer['id'], 'access_hash' => $peer['access_hash']];
|
||||
case 'chat':
|
||||
case 'chatEmpty':
|
||||
return ['_' => 'inputPeerChat', 'chat_id' => $peer['id']];
|
||||
case 'channel':
|
||||
return ['_' => 'inputPeerChannel', 'channel_id' => $peer['id'], 'access_hash' => $peer['access_hash']];
|
||||
default:
|
||||
throw new \danog\MadelineProto\Exception('Invalid constructor given');
|
||||
}
|
||||
}
|
||||
|
||||
public function resolve_username($username)
|
||||
{
|
||||
$res = $this->API->method_call('contacts.resolveUsername', ['username' => str_replace('@', '', $username)]);
|
||||
if ($res['_'] == 'contacts.resolvedPeer') {
|
||||
return $res;
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception('resolve_username returned an unexpected constructor: '.var_export($username, true));
|
||||
public function resolve_username($username) {
|
||||
return $this->API->resolve_username($username);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/*
|
||||
Copyright 2016 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\Wrappers;
|
||||
|
||||
/**
|
||||
* Manages changing API instance settings.
|
||||
*/
|
||||
trait SettingsManager {
|
||||
public function get_settings() {
|
||||
return $this->API->settings;
|
||||
}
|
||||
public function update_settings($settings) {
|
||||
$this->API->parse_settings($settings);
|
||||
}
|
||||
}
|
35
testing.php
35
testing.php
|
@ -12,10 +12,16 @@ If not, see <http://www.gnu.org/licenses/>.
|
|||
*/
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
$settings = [];
|
||||
if (file_exists('web_data.php')) {
|
||||
require_once('web_data.php');
|
||||
}
|
||||
|
||||
if (file_exists('number.php') && !file_exists('session.madeline')) {
|
||||
$MadelineProto = \danog\MadelineProto\Serialization::deserialize('session.madeline');
|
||||
|
||||
if (file_exists('number.php') && $MadelineProto === false) {
|
||||
include_once 'number.php';
|
||||
$MadelineProto = new \danog\MadelineProto\API();
|
||||
$MadelineProto = new \danog\MadelineProto\API($settings);
|
||||
|
||||
$checkedPhone = $MadelineProto->auth->checkPhone(// auth.checkPhone becomes auth->checkPhone
|
||||
[
|
||||
|
@ -33,35 +39,36 @@ if (file_exists('number.php') && !file_exists('session.madeline')) {
|
|||
$authorization = $MadelineProto->complete_phone_login($code);
|
||||
\danog\MadelineProto\Logger::log($authorization);
|
||||
echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL;
|
||||
echo 'Wrote '.file_put_contents('session.madeline', serialize($MadelineProto)).' bytes'.PHP_EOL;
|
||||
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $MadelineProto).' bytes'.PHP_EOL;
|
||||
}
|
||||
echo 'Deserializing MadelineProto from session.madeline...'.PHP_EOL;
|
||||
$MadelineProto = unserialize(file_get_contents('session.madeline'));
|
||||
$MadelineProto = \danog\MadelineProto\Serialization::deserialize('session.madeline');
|
||||
|
||||
$message = (getenv('TRAVIS_COMMIT') == '') ? 'Message entities can be sent too (yay)' : ('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)' : ('Travis ci tests in progress: commit '.getenv('TRAVIS_COMMIT').', job '.getenv('TRAVIS_JOB_NUMBER').', PHP version: '.getenv('TRAVIS_PHP_VERSION'));
|
||||
|
||||
$flutter = 'https://storage.pwrtelegram.xyz/pwrtelegrambot/document/file_6570.mp4';
|
||||
|
||||
\danog\MadelineProto\Logger::log($MadelineProto->resolve_username('@Palmas2012')); // Always use this method to resolve usernames, but you won't need to call this to get info about peers, as get_peer and get_input_peer will call it for you if needed
|
||||
|
||||
$mention = $MadelineProto->get_peer('@veetaw'); // Returns an object of type User or Chat
|
||||
$mention = $MadelineProto->constructor2inputpeer($mention); // Converts an object of type User or Chat to an object of type inputPeer
|
||||
$mention = $MadelineProto->get_info('@giuseppe_la_gaipa_2'); // Returns the following array: ['constructor' => $constructor, 'inputPeer' => $inputPeer, 'inputType' => $inputType, 'Peer' => $Peer, 'id' => $id, 'botApiId' => $bot_api_id]
|
||||
$mention = $mention['inputType']; // Selects only the inputType object
|
||||
|
||||
foreach (['@pwrtelegramgroup', '@pwrtelegramgroupita'] as $peer) {
|
||||
$peer = $MadelineProto->get_input_peer($peer); // Returns directly an inputPeer object, basically does the same thing I've done manually above
|
||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message.' & pony', 'entities' => [['_' => 'messageEntityUrl', 'offset' => strlen($message) + 1, 'length' => 6, 'url' => $flutter], ['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => strlen($message), 'user_id' => $mention]]]);
|
||||
$peer = $MadelineProto->get_info($peer)['inputPeer']; // Select the inputPeerType (alias inputPeer) object
|
||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => strlen($message), 'user_id' => $mention]]]);
|
||||
\danog\MadelineProto\Logger::log($sentMessage);
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
$MadelineProto->API->get_updates_difference();
|
||||
|
||||
echo 'Size of MadelineProto instance is '.strlen(serialize($MadelineProto)).' bytes'.PHP_EOL;
|
||||
if (file_exists('token.php')) {
|
||||
include_once 'token.php';
|
||||
$MadelineProto = new \danog\MadelineProto\API();
|
||||
$MadelineProto = new \danog\MadelineProto\API($settings);
|
||||
$authorization = $MadelineProto->bot_login($token);
|
||||
\danog\MadelineProto\Logger::log($authorization);
|
||||
}
|
||||
foreach (['@pwrtelegramgroup', '@pwrtelegramgroupita'] as $peer) {
|
||||
$peer = $MadelineProto->get_input_peer($peer);
|
||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message.' & pony', 'entities' => [['_' => 'messageEntityUrl', 'offset' => strlen($message) + 1, 'length' => 6, 'url' => $flutter], ['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => strlen($message), 'user_id' => $mention]]]);
|
||||
$peer = $MadelineProto->get_info($peer)['inputPeer']; // Select the inputPeerType (alias inputPeer) object
|
||||
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => strlen($message), 'user_id' => $mention]]]);
|
||||
\danog\MadelineProto\Logger::log($sentMessage);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue