From 0d191f4157fddc8af6db87309de40b10f88406b1 Mon Sep 17 00:00:00 2001 From: Alexander Pankratov Date: Mon, 27 Apr 2020 03:21:18 +0300 Subject: [PATCH] Bugfixes and optimizations --- src/danog/MadelineProto/Db/DbArray.php | 7 +- src/danog/MadelineProto/Db/MemoryArray.php | 6 +- src/danog/MadelineProto/Db/Mysql.php | 8 +- src/danog/MadelineProto/Db/MysqlArray.php | 155 ++++-------------- .../MadelineProto/Db/SharedMemoryArray.php | 7 +- src/danog/MadelineProto/MTProto.php | 18 +- .../MTProtoTools/PeerHandler.php | 18 +- .../MTProtoTools/ReferenceDatabase.php | 4 +- .../MTProtoTools/UpdateHandler.php | 4 +- .../MadelineProto/Wrappers/DialogHandler.php | 7 +- 10 files changed, 97 insertions(+), 137 deletions(-) diff --git a/src/danog/MadelineProto/Db/DbArray.php b/src/danog/MadelineProto/Db/DbArray.php index 263d9a93b..631bb3028 100644 --- a/src/danog/MadelineProto/Db/DbArray.php +++ b/src/danog/MadelineProto/Db/DbArray.php @@ -2,10 +2,7 @@ namespace danog\MadelineProto\Db; -abstract class DbArray extends \ArrayIterator implements DbType +interface DbArray extends DbType, \ArrayAccess, \Countable, \Iterator, \SeekableIterator { - protected function __construct($array = [], $flags = 0) - { - parent::__construct((array) $array, $flags | self::STD_PROP_LIST); - } + public function getArrayCopy(); } \ No newline at end of file diff --git a/src/danog/MadelineProto/Db/MemoryArray.php b/src/danog/MadelineProto/Db/MemoryArray.php index 6cab009bb..658edc562 100644 --- a/src/danog/MadelineProto/Db/MemoryArray.php +++ b/src/danog/MadelineProto/Db/MemoryArray.php @@ -2,8 +2,12 @@ namespace danog\MadelineProto\Db; -class MemoryArray extends DbArray +class MemoryArray extends \ArrayIterator implements DbArray { + protected function __construct($array = [], $flags = 0) + { + parent::__construct((array) $array, $flags | self::STD_PROP_LIST); + } static function getInstance(array $settings, string $name, $value = []): DbArray { diff --git a/src/danog/MadelineProto/Db/Mysql.php b/src/danog/MadelineProto/Db/Mysql.php index cada90afb..4374d71ea 100644 --- a/src/danog/MadelineProto/Db/Mysql.php +++ b/src/danog/MadelineProto/Db/Mysql.php @@ -2,7 +2,6 @@ namespace danog\MadelineProto\Db; -use Amp\Loop; use Amp\Mysql\ConnectionConfig; use Amp\Mysql\Pool; use function Amp\Mysql\Pool; @@ -42,4 +41,11 @@ class Mysql return static::$connections[$dbKey]; } + public function __destruct() + { + foreach (static::$connections as $connection) { + $connection->close(); + } + } + } \ No newline at end of file diff --git a/src/danog/MadelineProto/Db/MysqlArray.php b/src/danog/MadelineProto/Db/MysqlArray.php index 83ec30236..0bb89057a 100644 --- a/src/danog/MadelineProto/Db/MysqlArray.php +++ b/src/danog/MadelineProto/Db/MysqlArray.php @@ -7,18 +7,18 @@ use Amp\Sql\ResultSet; use danog\MadelineProto\Tools; use function Amp\call; -class MysqlArray extends DbArray +class MysqlArray implements DbArray { private string $table; private array $settings; private Pool $db; private ?string $key = null; + private $current; public function __serialize(): array { return [ 'table' => $this->table, - 'key' => $this->key, 'settings' => $this->settings ]; } @@ -71,8 +71,7 @@ class MysqlArray extends DbArray ['index' => $index] ); - $row = reset($row); - return !empty($row['count']); + return !empty($row[0]['count']); } /** @@ -93,11 +92,7 @@ class MysqlArray extends DbArray "SELECT `value` FROM {$this->table} WHERE `key` = :index LIMIT 1", ['index' => $index] ); - $row = reset($row); - if ($row) { - return unserialize($row['value']); - } - return null; + return $this->getValue($row); } @@ -150,19 +145,6 @@ class MysqlArray extends DbArray ); } - /** - * Append an element - * @link https://php.net/manual/en/arrayiterator.append.php - * @param mixed $value

- * The value to append. - *

- * @return void - */ - public function append($value) - { - throw new \BadMethodCallException('Append operation does not supported'); - } - /** * Get array copy * @@ -178,6 +160,7 @@ class MysqlArray extends DbArray foreach ($rows as $row) { $result[$row['key']] = unserialize($row['value']); } + return $result; } @@ -191,73 +174,8 @@ class MysqlArray extends DbArray */ public function count(): int { - return $this->syncRequest("SELECT count(`key`) as `count` FROM {$this->table}")['count'] ?? 0; - } - - /** - * Sort array by values - * @link https://php.net/manual/en/arrayiterator.asort.php - * @return void - */ - public function asort() - { - throw new \BadMethodCallException('Sort operation does not supported'); - } - - /** - * Sort array by keys - * @link https://php.net/manual/en/arrayiterator.ksort.php - * @return void - */ - public function ksort() - { - throw new \BadMethodCallException('Sort operation does not supported'); - } - - /** - * User defined sort - * @link https://php.net/manual/en/arrayiterator.uasort.php - * @param string $cmp_function

- * The compare function used for the sort. - *

- * @return void - */ - public function uasort($cmp_function) - { - throw new \BadMethodCallException('Sort operation does not supported'); - } - - /** - * User defined sort - * @link https://php.net/manual/en/arrayiterator.uksort.php - * @param string $cmp_function

- * The compare function used for the sort. - *

- * @return void - */ - public function uksort($cmp_function) - { - throw new \BadMethodCallException('Sort operation does not supported'); - } - - /** - * Sort an array naturally - * @link https://php.net/manual/en/arrayiterator.natsort.php - * @return void - */ - public function natsort() - { - throw new \BadMethodCallException('Sort operation does not supported'); - } - - /** - * Sort an array naturally, case insensitive - * @link https://php.net/manual/en/arrayiterator.natcasesort.php - * @return void - */ - public function natcasesort() - { - throw new \BadMethodCallException('Sort operation does not supported'); + $row = $this->syncRequest("SELECT count(`key`) as `count` FROM {$this->table}"); + return $row[0]['count'] ?? 0; } /** @@ -271,6 +189,7 @@ class MysqlArray extends DbArray { $this->key = null; $this->key(); + $this->current = null; } /** @@ -282,7 +201,16 @@ class MysqlArray extends DbArray */ public function current() { - return $this->offsetGet($this->key()); + return $this->current ?: $this->offsetGet($this->key()); + } + + private function getValue(array $row) + { + if ($row) { + $row = reset($row); + return unserialize($row['value']); + } + return null; } /** @@ -298,11 +226,7 @@ class MysqlArray extends DbArray $row = $this->syncRequest( "SELECT `key` FROM {$this->table} ORDER BY `key` LIMIT 1" ); - if ($row) { - $row = reset($row); - $this->key = $row['key'] ?? null; - } - + $this->key = $row[0]['key'] ?? null; } return $this->key; } @@ -314,13 +238,15 @@ class MysqlArray extends DbArray * @return void * @throws \Throwable */ - public function next() { + public function next() + { $row = $this->syncRequest( - "SELECT `key` FROM {$this->table} WHERE `key` > :key LIMIT 1", + "SELECT `key`, `value` FROM {$this->table} WHERE `key` > :key ORDER BY `key` LIMIT 1", ['key' => $this->key()] ); - $row = reset($row); - $this->key = $row['key'] ?? null; + + $this->key = $row[0]['key'] ?? null; + $this->current = $this->getValue($row); } /** @@ -330,17 +256,9 @@ class MysqlArray extends DbArray * @return bool * @throws \Throwable */ - public function valid() { - if ($this->key() === null) { - return false; - } - - $row = $this->syncRequest( - "SELECT `key` FROM {$this->table} WHERE `key` > :key LIMIT 1", - ['key' => $this->key()] - ); - - return $row !== null; + public function valid():bool + { + return $this->key !== null; } /** @@ -357,14 +275,12 @@ class MysqlArray extends DbArray "SELECT `key` FROM {$this->table} ORDER BY `key` LIMIT 1, :position", ['offset' => $position] ); - $row = reset($row); - if (isset($row['key'])) { - $this->key = $row['key']; - } + $this->key = $row[0]['key'] ?? $this->key; } private function initDbConnection() { + //TODO Use MtProto::$settings $this->db = Mysql::getConnection( $this->settings['host'], $this->settings['port'], @@ -386,7 +302,7 @@ class MysqlArray extends DbArray CREATE TABLE IF NOT EXISTS `{$this->table}` ( `key` VARCHAR(255) NOT NULL, - `value` LONGTEXT NULL, + `value` MEDIUMBLOB NULL, `ts` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`key`) ) @@ -411,13 +327,7 @@ class MysqlArray extends DbArray $result = []; if ($request instanceof ResultSet) { while (yield $request->advance()) { - $row = $request->getCurrent(); - if (isset($row['key'])) { - $result[$row['key']] = $row; - } else { - $result[] = $row; - } - + $result[] = $request->getCurrent(); } } return $result; @@ -425,5 +335,4 @@ class MysqlArray extends DbArray ) ); } - } \ No newline at end of file diff --git a/src/danog/MadelineProto/Db/SharedMemoryArray.php b/src/danog/MadelineProto/Db/SharedMemoryArray.php index 2252556c6..2d82c1dc7 100644 --- a/src/danog/MadelineProto/Db/SharedMemoryArray.php +++ b/src/danog/MadelineProto/Db/SharedMemoryArray.php @@ -2,10 +2,15 @@ namespace danog\MadelineProto\Db; -class SharedMemoryArray extends DbArray +class SharedMemoryArray extends \ArrayIterator implements DbArray { private static SharedMemoryArray $instance; + protected function __construct($array = [], $flags = 0) + { + parent::__construct((array) $array, $flags | self::STD_PROP_LIST); + } + public static function getInstance(array $settings, string $name, $value = []): DbArray { if (empty(static::$instance)) { diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index a6c43204a..c738173fd 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -24,7 +24,6 @@ use Amp\File\StatCache; use Amp\Http\Client\HttpClient; use danog\MadelineProto\Async\AsyncConstruct; use danog\MadelineProto\Db\DbArray; -use danog\MadelineProto\Db\DbType; use danog\MadelineProto\Db\Engines\DbInterface; use danog\MadelineProto\Db\DbPropertiesFabric; use danog\MadelineProto\Db\Mysql; @@ -422,7 +421,12 @@ class MTProto extends AsyncConstruct implements TLCallback private array $dbProperies = [ 'chats' => 'array', 'full_chats' => 'array', - 'channel_participants' => 'array' + 'channel_participants' => 'array', + 'caching_simple' => 'array', + 'caching_simple_username' => 'array', + 'caching_possible_username' => 'array', + 'caching_full_info' => 'array', + 'caching_username_id' => 'array', ]; /** @@ -568,6 +572,16 @@ class MTProto extends AsyncConstruct implements TLCallback $this->{$property} = DbPropertiesFabric::get($this->settings['db'], $type, $property, $this->{$property}); } } + + if (!$reset && count($this->caching_username_id) === 0) { + $this->logger('Filling database cache. This can take few minutes.', Logger::WARNING); + foreach ($this->chats as $id => $chat) { + if (isset($chat['username'])) { + $this->caching_username_id[$chat['username']] = $id; + } + } + $this->logger('Cache filled.', Logger::WARNING); + } } /** diff --git a/src/danog/MadelineProto/MTProtoTools/PeerHandler.php b/src/danog/MadelineProto/MTProtoTools/PeerHandler.php index debf2f8fa..cdb395e4d 100644 --- a/src/danog/MadelineProto/MTProtoTools/PeerHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/PeerHandler.php @@ -34,6 +34,8 @@ trait PeerHandler public $caching_simple_username = []; public $caching_possible_username = []; public $caching_full_info = []; + public $caching_username_id = []; + /** * Convert MTProto channel ID to bot API channel ID. * @@ -562,7 +564,19 @@ trait PeerHandler } return yield from $this->getInfo($this->supportUser); } + if ($bot_api_id = $this->caching_username_id[$id] ?? null) { + $chat = $this->chats[$bot_api_id]; + if (empty($chat['username']) || $chat['username'] !== $id) { + unset($this->caching_username_id[$id]); + } else { + return $this->genAll($this->chats[$bot_api_id], $folder_id); + } + } + foreach ($this->chats as $bot_api_id => $chat) { + if (isset($chat['username'])) { + $this->caching_username_id[$id] = $bot_api_id; + } if (isset($chat['username']) && \strtolower($chat['username']) === $id) { if ($chat['min'] ?? false && !isset($this->caching_full_info[$bot_api_id])) { $this->caching_full_info[$bot_api_id] = true; @@ -969,7 +983,9 @@ trait PeerHandler } \sort($ids, SORT_NUMERIC); $gres['hash'] = \danog\MadelineProto\Tools::genVectorHash($ids); - $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres; + $participant = $this->channel_participants[$channel['channel_id']]; + $participant[$filter][$q][$offset][$limit] = $gres; + $this->channel_participants[$channel['channel_id']] = $participant; } private function getParticipantsHash($channel, $filter, $q, $offset, $limit) { diff --git a/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php b/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php index 236fb4f96..72dd357b3 100644 --- a/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php +++ b/src/danog/MadelineProto/MTProtoTools/ReferenceDatabase.php @@ -423,7 +423,9 @@ class ReferenceDatabase implements TLCallback // Peer + photo ID case self::PEER_PHOTO_ORIGIN: if (isset($this->API->full_chats[$origin['peer']]['last_update'])) { - $this->API->full_chats[$origin['peer']]['last_update'] = 0; + $chat = $this->API->full_chats[$origin['peer']]; + $chat['last_update'] = 0; + $this->API->full_chats[$origin['peer']] = $chat; } $this->API->getFullInfo($origin['peer']); break; diff --git a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php index 67424f42c..facb7475b 100644 --- a/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/UpdateHandler.php @@ -332,7 +332,9 @@ trait UpdateHandler } if (\in_array($update['_'], ['updateUserName', 'updateUserPhone', 'updateUserBlocked', 'updateUserPhoto', 'updateContactRegistered', 'updateContactLink'])) { $id = $this->getId($update); - $this->full_chats[$id]['last_update'] = 0; + $chat = $this->full_chats[$id]; + $chat['last_update'] = 0; + $this->full_chats[$id] = $chat; yield from $this->getFullInfo($id); } if ($update['_'] === 'updateDcOptions') { diff --git a/src/danog/MadelineProto/Wrappers/DialogHandler.php b/src/danog/MadelineProto/Wrappers/DialogHandler.php index c9d807671..d7de64179 100644 --- a/src/danog/MadelineProto/Wrappers/DialogHandler.php +++ b/src/danog/MadelineProto/Wrappers/DialogHandler.php @@ -33,7 +33,12 @@ trait DialogHandler if ($this->authorization['user']['bot']) { $res = []; foreach ($this->chats as $chat) { - $res[] = $this->genAll($chat)['Peer']; + try { + $res[] = $this->genAll($chat)['Peer']; + } catch (\Throwable $e) { + continue; + } + } return $res; }