From f54fb0b6b3fbd92538266e1024a19342a8618e4f Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 4 Jan 2017 12:22:03 +0000 Subject: [PATCH] Written first MadelineProto bot, fixed update management, fixed bugs --- README.md | 4 +- bot.php | 28 +++++++++++ docs/index.md | 4 +- id.php | 17 ++++--- src/danog/MadelineProto/DocsBuilder.php | 4 +- src/danog/MadelineProto/MTProto.php | 2 +- .../MadelineProto/MTProtoTools/AckHandler.php | 2 +- .../MTProtoTools/MsgIdHandler.php | 10 ++-- .../MTProtoTools/ResponseHandler.php | 5 +- .../MTProtoTools/UpdateHandler.php | 49 ++++++++++--------- 10 files changed, 79 insertions(+), 46 deletions(-) create mode 100644 bot.php diff --git a/README.md b/README.md index be35374a..c34c7f66 100644 --- a/README.md +++ b/README.md @@ -209,10 +209,10 @@ $offset = 0; while (true) { $updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 1]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { - $offset = $update['update_id'] // Just like in the bot API, the offset must be set to the last update_id + $offset = $update['update_id']; // Just like in the bot API, the offset must be set to the last update_id // Parse $update['update'], that is an object of type Update } - var_dump($update); + var_dump($updates); } array(3) { diff --git a/bot.php b/bot.php new file mode 100644 index 00000000..09370840 --- /dev/null +++ b/bot.php @@ -0,0 +1,28 @@ +bot_login($token); + \danog\MadelineProto\Logger::log($authorization); +} +$offset = 0; +while (true) { + $updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout + foreach ($updates as $update) { + $offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id + var_dump($update); + switch ($update['update']['_']) { + case 'updateNewMessage': + if ($update['update']['message']['out']) continue; + $res = json_encode($update, JSON_PRETTY_PRINT); + if ($res == '') $res =var_export($update, true); + try { $MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $res, 'reply_to_msg_id' => $update['update']['message']['id'], 'entities' => [['_' => 'messageEntityPre', 'offset' => 0, 'length' => strlen($res), 'language' => 'json', ]]]); } catch (\danog\MadelineProto\RPCErrorException $e) { $MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]); } + } + } + echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('bot.madeline', $MadelineProto).' bytes'.PHP_EOL; +} + diff --git a/docs/index.md b/docs/index.md index f50e7dea..c5725919 100644 --- a/docs/index.md +++ b/docs/index.md @@ -213,10 +213,10 @@ $offset = 0; while (true) { $updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 1]); // Just like in the bot API, you can specify an offset, a limit and a timeout foreach ($updates as $update) { - $offset = $update['update_id'] // Just like in the bot API, the offset must be set to the last update_id + $offset = $update['update_id']; // Just like in the bot API, the offset must be set to the last update_id // Parse $update['update'], that is an object of type Update } - var_dump($update); + var_dump($updates); } array(3) { diff --git a/id.php b/id.php index f7a49334..7b3d75bc 100644 --- a/id.php +++ b/id.php @@ -11,21 +11,21 @@ If not, see . */ require 'vendor/autoload.php'; -require '../db_id.php'; +//require '../db:id.php'; -$select = $pdo->prepare('SELECT * FROM ul'); -$select->execute(); -$pdores = $select->fetchAll(PDO::FETCH_ASSOC); +//$select = $pdo->prepare('SELECT * FROM ul'); +//$select->execute(); +//$pdores = $select->fetchAll(PDO::FETCH_ASSOC); function foreach_offset_length($string) { $res = []; $strlen = strlen($string); for ($offset = 0; $offset < strlen($string); $offset++) { - for ($length = 1; $length > 0; $length--) { + for ($length = $strlen - $offset; $length > 0; $length--) { $s = substr($string, $offset, $length); - //$number = (string) (new \phpseclib\Math\BigInteger(strrev($s), 256)); - $number = ord($s); + $number = (string) (new \phpseclib\Math\BigInteger(strrev($s), 256)); + //$number = ord($s); $res[] = ['number' => $number, 'offset' => $offset, 'length' => $length]; } } @@ -33,6 +33,7 @@ function foreach_offset_length($string) return $res; } $res = []; +$pdores = [['file_id' => 'AwADBAADiQEAAo_aCgYAAc-fglzxcY0C']]; foreach ($pdores as $r) { $base256 = base64url_decode($r['file_id']); $res = foreach_offset_length($base256); @@ -46,7 +47,7 @@ foreach ($pdores as $r) { } } } -var_dump($same); +var_dump($res); function base64url_decode($data) { return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); diff --git a/src/danog/MadelineProto/DocsBuilder.php b/src/danog/MadelineProto/DocsBuilder.php index ade74992..a480ec06 100755 --- a/src/danog/MadelineProto/DocsBuilder.php +++ b/src/danog/MadelineProto/DocsBuilder.php @@ -63,8 +63,8 @@ description: '.$this->settings['description'].' \danog\MadelineProto\Logger::log('Generating methods documentation...'); - foreach ($this->methods->method as $key => $method) { - $method = str_replace('.', '_', $method); + foreach ($this->methods->method as $key => $rmethod) { + $method = str_replace('.', '_', $rmethod); $real_method = str_replace('.', '->', $method); $type = str_replace(['.', '<', '>'], ['_', '_of_', ''], $this->methods->type[$key]); $real_type = preg_replace('/.*_of_/', '', $type); diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 2c0cabe8..1ee80b8f 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -198,7 +198,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB 'outgoing' => 1000, ], 'updates' => [ - 'updates_array_limit' => 1000, // How big should be the array containing the updates processed with the default example_update_handler callback + 'handle_updates' => true, // Should I handle updates? '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 ], ]; diff --git a/src/danog/MadelineProto/MTProtoTools/AckHandler.php b/src/danog/MadelineProto/MTProtoTools/AckHandler.php index e6843d73..c69aa7aa 100644 --- a/src/danog/MadelineProto/MTProtoTools/AckHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AckHandler.php @@ -33,7 +33,7 @@ trait AckHandler { // I let the server know that I received its message if (!isset($this->datacenter->incoming_messages[$message_id])) { - \danog\MadelineProto\Logger::log("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?'); + \danog\MadelineProto\Logger::log("WARNING: Couldn't find message id ".$message_id.' in the array of incomgoing messages. Maybe try to increase its size?'); //throw new \danog\MadelineProto\Exception("Couldn't find message id ".$message_id.' in the array of incoming message ids. Maybe try to increase its size?'); } if ($this->datacenter->temp_auth_key['id'] === null || $this->datacenter->temp_auth_key['id'] == $this->string2bin('\x00\x00\x00\x00\x00\x00\x00\x00') || (isset($this->datacenter->incoming_messages[$message_id]['ack']) && $this->datacenter->incoming_messages[$message_id]['ack'])) { diff --git a/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php b/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php index 9ea7d0fd..8c542914 100644 --- a/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php @@ -37,10 +37,11 @@ trait MsgIdHandler if ($new_message_id <= end($keys)) { throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.end($keys).').', 1); } - $this->datacenter->outgoing_messages[$new_message_id] = []; if (count($this->datacenter->outgoing_messages) > $this->settings['msg_array_limit']['outgoing']) { - array_shift($this->datacenter->outgoing_messages); + reset($this->datacenter->outgoing_messages); + unset($this->datacenter->outgoing_messages[key($this->datacenter->outgoing_messages)]); } + $this->datacenter->outgoing_messages[$new_message_id] = []; } else { if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) { throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3'); @@ -59,10 +60,11 @@ trait MsgIdHandler } } } - $this->datacenter->incoming_messages[$new_message_id] = []; if (count($this->datacenter->incoming_messages) > $this->settings['msg_array_limit']['incoming']) { - array_shift($this->datacenter->incoming_messages); + reset($this->datacenter->outgoing_messages); + unset($this->datacenter->outgoing_messages[key($this->datacenter->outgoing_messages)]); } + $this->datacenter->incoming_messages[$new_message_id] = []; ksort($this->datacenter->incoming_messages); } } diff --git a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php index 10a73f32..7c9a08a4 100644 --- a/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/ResponseHandler.php @@ -82,8 +82,8 @@ trait ResponseHandler if (isset($response['result']['users'])) { $this->add_users($response['result']['users']); } - if (isset($response['result']['chats'])) { - $this->add_chats($response['result']['chats']); + if (isset($response['result']['_']) && $this->constructors->find_by_predicate($response['result']['_'])['type'] == 'Update') { + $this->handle_update($response['result']); } switch ($response['_']) { case 'msgs_ack': @@ -255,6 +255,7 @@ trait ResponseHandler public function handle_updates($updates) { + if (!$this->settings['updates']['handle_updates']) return; \danog\MadelineProto\Logger::log('Parsing updates received via the socket...'); if ($this->getting_state) { \danog\MadelineProto\Logger::log('Getting state, handle later'); diff --git a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php index 839b57c9..fdf6d74f 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php @@ -25,35 +25,34 @@ trait UpdateHandler public function get_updates_update_handler($update) { - if (count($this->updates) > $this->settings['updates']['updates_array_limit']) { - array_shift($this->updates); - } $this->updates[$this->updates_key++] = $update; //\danog\MadelineProto\Logger::log('Stored ', $update); } public function get_updates($params = []) { + $time = microtime(true); $this->force_get_updates_difference(); - if (empty($this->updates)) { - return []; - } - $default_params = ['offset' => array_keys($this->updates)[0], 'limit' => null, 'timeout' => 0]; + $default_params = ['offset' => 0, 'limit' => null, 'timeout' => 0]; foreach ($default_params as $key => $default) { if (!isset($params[$key])) { $params[$key] = $default; } } - $time = microtime(true); - $params['timeout'] = (int) ($params['timeout'] - (microtime(true) - $time)); - sleep($params['timeout'] > 0 ? $params['timeout'] : 0); - $result = array_slice($this->updates, $params['offset'], $params['limit'], true); - $updates = []; - foreach ($result as $key => $value) { - $updates[] = ['update_id' => $key, 'update' => $value]; - unset($this->updates[$key]); + $params['timeout'] = (int) ($params['timeout']*1000000 - (microtime(true) - $time)); + usleep($params['timeout'] > 0 ? $params['timeout'] : 0); + if (empty($this->updates)) { + return []; + } + if ($params['offset'] < 0) $params['offset'] = array_reverse(array_keys($this->updates))[abs($params['offset'])-1]; + $updates = []; + foreach ($this->updates as $key => $value) { + if ($params['offset'] > $key) { + unset($this->updates[$key]); + } else if ($params['limit'] == null || count($updates) < $params['limit']) { + $updates[] = ['update_id' => $key, 'update' => $value]; + } } - return $updates; } @@ -204,13 +203,13 @@ trait UpdateHandler } else { $cur_state = &$this->get_channel_state($channel_id, (isset($update['pts']) ? $update['pts'] : 0) - (isset($update['pts_count']) ? $update['pts_count'] : 0)); } - /* + if ($cur_state['sync_loading']) { \danog\MadelineProto\Logger::log('Sync loading, not handling update'); return false; } - */ + switch ($update['_']) { case 'updateChannelTooLong': $this->get_channel_difference($channel_id); @@ -220,7 +219,7 @@ trait UpdateHandler case 'updateEditMessage': case 'updateNewChannelMessage': case 'updateEditChannelMessage': - $message = $update['message']; + $message = &$update['message']; if ((isset($message['from_id']) && !$this->peer_isset($message['from_id'])) || !$this->peer_isset($message['to_id']) || (isset($message['via_bot_id']) && !$this->peer_isset($message['via_bot_id'])) || @@ -236,6 +235,7 @@ trait UpdateHandler return false; } + if ($message['from_id'] == $this->datacenter->authorization['user']['id']) { $message['out'] = true; } break; default: if ($channel_id !== false && !$this->peer_isset('channel#'.$channel_id)) { @@ -267,7 +267,7 @@ trait UpdateHandler $cur_state['pts'] = $update['pts']; $pop_pts = true; } elseif (isset($update['pts_count']) && $update['pts_count']) { - \danog\MadelineProto\Logger::log('Duplicate update. current pts: '.$cur_state['pts'].' + pts count: '.(isset($update['pts_count']) ? $update['pts_count'] : 0).' = new pts: '.$new_pts.'. update pts: '.$update['pts'].' <= current pts '.$cur_state['pts'].', channel id: '.$channel_id); + \danog\MadelineProto\Logger::log('Duplicate update. current pts: '.$cur_state['pts'].' + pts count: '.(isset($update['pts_count']) ? $update['pts_count'] : 0).' = new pts: '.$new_pts.'. update pts: '.$update['pts'].' <= current pts '.$cur_state['pts'].', channel id: '.$channel_id, $update); return false; } @@ -359,7 +359,7 @@ trait UpdateHandler public function handle_multiple_update($updates, $options = [], $channel = false) { - if ($channel == false) { + if ($channel === false) { foreach ($updates as $update) { switch ($update['_']) { case 'updateChannelTooLong': @@ -368,11 +368,11 @@ trait UpdateHandler $this->handle_update($update, $options); continue 2; } - $this->save_update($update); + $this->handle_update($update); } } else { foreach ($updates as $update) { - $this->save_update($update); + $this->handle_update($update); } } } @@ -380,12 +380,13 @@ trait UpdateHandler public function handle_update_messages($messages, $channel = false) { foreach ($messages as $message) { - $this->save_update(['_' => $channel == false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => $channel == false ? $this->get_update_state()['pts'] : $this->get_channel_state($channel)['pts'], 'pts_count' => 0]); + $this->handle_update(['_' => $channel == false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => $channel == false ? $this->get_update_state()['pts'] : $this->get_channel_state($channel)['pts'], 'pts_count' => 0]); } } public function save_update($update) { + if (!$this->settings['updates']['handle_updates']) return; \danog\MadelineProto\Logger::log('Saving an update of type '.$update['_'].'...'); $this->settings['updates']['callback']($update); }