Async refactor
This commit is contained in:
parent
a883684f05
commit
46f7e63734
@ -5,10 +5,13 @@ namespace danog\MadelineProto\Db;
|
||||
use Amp\Producer;
|
||||
use Amp\Promise;
|
||||
|
||||
interface DbArray extends DbType, \ArrayAccess, \Countable, \Iterator, \SeekableIterator
|
||||
interface DbArray extends DbType, \ArrayAccess, \Countable
|
||||
{
|
||||
public function getArrayCopy();
|
||||
public function offsetGetAsync(string $offset): Promise;
|
||||
public function offsetSetAsync(string $offset, $value): Promise;
|
||||
public function getArrayCopy(): array;
|
||||
public function offsetExists($offset): Promise;
|
||||
public function offsetGet($offset): Promise;
|
||||
public function offsetSet($offset, $value);
|
||||
public function offsetUnset($offset): Promise;
|
||||
public function count(): Promise;
|
||||
public function getIterator(): Producer;
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace danog\MadelineProto\Db;
|
||||
|
||||
use danog\MadelineProto\API;
|
||||
use danog\MadelineProto\MTProto;
|
||||
|
||||
class DbPropertiesFabric
|
||||
@ -13,7 +12,7 @@ class DbPropertiesFabric
|
||||
* @param string $name
|
||||
* @param $value
|
||||
*
|
||||
* @return mixed
|
||||
* @return DbType
|
||||
*
|
||||
* @uses \danog\MadelineProto\Db\MemoryArray
|
||||
* @uses \danog\MadelineProto\Db\SharedMemoryArray
|
||||
@ -44,8 +43,18 @@ class DbPropertiesFabric
|
||||
throw new \InvalidArgumentException("Unknown $propertyType: {$propertyType}");
|
||||
}
|
||||
|
||||
$prefix = (string) ($madelineProto->getSelf()['id'] ?? 'tmp');
|
||||
$prefix = static::getSessionId($madelineProto);
|
||||
return $class::getInstance($name, $value, $prefix, $dbSettings[$dbSettings['type']]??[]);
|
||||
}
|
||||
|
||||
private static function getSessionId(MTProto $madelineProto): string
|
||||
{
|
||||
$result = $madelineProto->getSelf()['id'] ?? null;
|
||||
if (!$result) {
|
||||
$result = 'tmp_';
|
||||
$result .= str_replace('0','', spl_object_hash($madelineProto));
|
||||
}
|
||||
return (string) $result;
|
||||
}
|
||||
|
||||
}
|
@ -4,5 +4,5 @@ namespace danog\MadelineProto\Db;
|
||||
|
||||
interface DbType
|
||||
{
|
||||
static function getInstance(string $name, $value, string $tablePrefix, array $settings): self;
|
||||
static function getInstance(string $name, $value = null, string $tablePrefix = '', array $settings = []): self;
|
||||
}
|
@ -13,7 +13,7 @@ class MemoryArray extends \ArrayIterator implements DbArray
|
||||
parent::__construct((array) $array, $flags | self::STD_PROP_LIST);
|
||||
}
|
||||
|
||||
public static function getInstance(string $name, $value, string $tablePrefix, array $settings): DbArray
|
||||
public static function getInstance(string $name, $value = null, string $tablePrefix = '', array $settings = []): DbArray
|
||||
{
|
||||
if ($value instanceof DbArray) {
|
||||
$value = $value->getArrayCopy();
|
||||
@ -21,26 +21,36 @@ class MemoryArray extends \ArrayIterator implements DbArray
|
||||
return new static($value);
|
||||
}
|
||||
|
||||
public static function getDbConnection(array $settings)
|
||||
public function offsetExists($offset): Promise
|
||||
{
|
||||
return null;
|
||||
return call(fn() => parent::offsetExists($offset));
|
||||
}
|
||||
|
||||
public function offsetGetAsync(string $offset): Promise
|
||||
public function offsetGet($offset): Promise
|
||||
{
|
||||
return call(fn() => $this->offsetGet($offset));
|
||||
return call(fn() => parent::offsetGet($offset));
|
||||
}
|
||||
|
||||
public function offsetSetAsync(string $offset, $value): Promise
|
||||
public function offsetUnset($offset): Promise
|
||||
{
|
||||
return call(fn() => $this->offsetSet($offset, $value));
|
||||
return call(fn() => parent::offsetUnset($offset));
|
||||
}
|
||||
|
||||
public function count(): Promise
|
||||
{
|
||||
return call(fn() => parent::count());
|
||||
}
|
||||
|
||||
public function getArrayCopy(): array
|
||||
{
|
||||
return parent::getArrayCopy();
|
||||
}
|
||||
|
||||
public function getIterator(): Producer
|
||||
{
|
||||
return new Producer(function (callable $emit) {
|
||||
foreach ($this as $value) {
|
||||
yield $emit($value);
|
||||
foreach ($this as $key => $value) {
|
||||
yield $emit([$key, $value]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace danog\MadelineProto\Db;
|
||||
|
||||
use Amp\Mysql\ConnectionConfig;
|
||||
use Amp\Mysql\Pool;
|
||||
use function Amp\call;
|
||||
use function Amp\Mysql\Pool;
|
||||
use function Amp\Promise\wait;
|
||||
|
||||
@ -52,12 +53,17 @@ class Mysql
|
||||
* @throws \Amp\Sql\FailureException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
private static function createDb(ConnectionConfig $config) {
|
||||
$db = $config->getDatabase();
|
||||
wait(pool($config->withDatabase(null))->query("
|
||||
CREATE DATABASE IF NOT EXISTS `{$db}`
|
||||
CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci
|
||||
"));
|
||||
private static function createDb(ConnectionConfig $config)
|
||||
{
|
||||
wait(call(function() use($config) {
|
||||
$db = $config->getDatabase();
|
||||
$connection = pool($config->withDatabase(null));
|
||||
yield $connection->query("
|
||||
CREATE DATABASE IF NOT EXISTS `{$db}`
|
||||
CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci
|
||||
");
|
||||
$connection->close();
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,6 @@ class MysqlArray implements DbArray
|
||||
private string $table;
|
||||
private array $settings;
|
||||
private Pool $db;
|
||||
private ?string $key = null;
|
||||
private $current;
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
@ -42,7 +40,7 @@ class MysqlArray implements DbArray
|
||||
|
||||
}
|
||||
|
||||
public static function getInstance(string $name, $value, string $tablePrefix, array $settings): DbType
|
||||
public static function getInstance(string $name, $value = null, string $tablePrefix = '', array $settings = []): DbType
|
||||
{
|
||||
$instance = new static();
|
||||
|
||||
@ -52,13 +50,18 @@ class MysqlArray implements DbArray
|
||||
$instance->ttl = $settings['cache_ttl'] ?? $instance->ttl;
|
||||
|
||||
if ($value instanceof static) {
|
||||
if ($instance->table !== $value->table) {
|
||||
if (
|
||||
mb_strpos($value->table, 'tmp') === 0 &&
|
||||
mb_strpos($instance->table, 'tmp') !== 0
|
||||
) {
|
||||
$instance->renameTable($value->table, $instance->table);
|
||||
} elseif (mb_strpos($instance->table, 'tmp') === 0){
|
||||
$instance->table = $value->table;
|
||||
}
|
||||
}
|
||||
$instance->prepareTable();
|
||||
|
||||
Loop::defer(function() use($value, $instance){
|
||||
Loop::defer(static function() use($value, $instance) {
|
||||
if (!empty($value) && !$value instanceof static) {
|
||||
Logger::log('Converting database.', Logger::ERROR);
|
||||
if ($value instanceof DbArray) {
|
||||
@ -81,7 +84,6 @@ class MysqlArray implements DbArray
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
@ -94,33 +96,16 @@ class MysqlArray implements DbArray
|
||||
* The offset being checked.
|
||||
* </p>
|
||||
*
|
||||
* @return bool true if the offset exists, otherwise false
|
||||
* @return Promise<bool> true if the offset exists, otherwise false
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function offsetExists($index)
|
||||
public function offsetExists($index): Promise
|
||||
{
|
||||
return $this->offsetGet($index) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for an offset
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.offsetget.php
|
||||
*
|
||||
* @param string $index <p>
|
||||
* The offset to get the value from.
|
||||
* </p>
|
||||
*
|
||||
* @return mixed The value at offset <i>index</i>.
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function offsetGet($index)
|
||||
{
|
||||
return wait($this->offsetGetAsync($index));
|
||||
return call(fn() => yield $this->offsetGet($index) !== null);
|
||||
}
|
||||
|
||||
|
||||
public function offsetGetAsync(string $offset): Promise
|
||||
public function offsetGet($offset): Promise
|
||||
{
|
||||
return call(function() use($offset) {
|
||||
if ($cached = $this->getCache($offset)) {
|
||||
@ -150,19 +135,15 @@ class MysqlArray implements DbArray
|
||||
* </p>
|
||||
* @param $value
|
||||
*
|
||||
* @return void
|
||||
* @return Promise
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function offsetSet($index, $value)
|
||||
{
|
||||
wait($this->offsetSetAsync($index, $value));
|
||||
}
|
||||
|
||||
public function offsetSetAsync($index, $value): Promise
|
||||
public function offsetSet($index, $value): void
|
||||
{
|
||||
$this->setCache($index, $value);
|
||||
|
||||
return $this->request("
|
||||
$this->request("
|
||||
INSERT INTO `{$this->table}`
|
||||
SET `key` = :index, `value` = :value
|
||||
ON DUPLICATE KEY UPDATE `value` = :value
|
||||
@ -183,14 +164,14 @@ class MysqlArray implements DbArray
|
||||
* The offset to unset.
|
||||
* </p>
|
||||
*
|
||||
* @return void
|
||||
* @return Promise
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function offsetUnset($index)
|
||||
public function offsetUnset($index): Promise
|
||||
{
|
||||
$this->unsetCache($index);
|
||||
|
||||
$this->syncRequest("
|
||||
return $this->request("
|
||||
DELETE FROM `{$this->table}`
|
||||
WHERE `key` = :index
|
||||
",
|
||||
@ -211,7 +192,7 @@ class MysqlArray implements DbArray
|
||||
$rows = $this->syncRequest("SELECT `key`, `value` FROM {$this->table}");
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$result[$row['key']] = unserialize($row['value']);
|
||||
$result[$row['key']] = $this->getValue($row);
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -225,7 +206,7 @@ class MysqlArray implements DbArray
|
||||
while (yield $request->advance()) {
|
||||
$row = $request->getCurrent();
|
||||
|
||||
yield $emit($this->getValue($row));
|
||||
yield $emit([$row['key'], $this->getValue($row)]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -234,40 +215,16 @@ class MysqlArray implements DbArray
|
||||
* Count elements
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.count.php
|
||||
* @return int The number of elements or public properties in the associated
|
||||
* @return Promise<int> The number of elements or public properties in the associated
|
||||
* array or object, respectively.
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function count(): int
|
||||
public function count(): Promise
|
||||
{
|
||||
$row = $this->syncRequest("SELECT count(`key`) as `count` FROM {$this->table}");
|
||||
return $row[0]['count'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind array back to the start
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.rewind.php
|
||||
* @return void
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->key = null;
|
||||
$this->key();
|
||||
$this->current = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current array entry
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.current.php
|
||||
* @return mixed The current array entry.
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->current ?: $this->offsetGet($this->key());
|
||||
return call(function(){
|
||||
$row = yield $this->request("SELECT count(`key`) as `count` FROM {$this->table}");
|
||||
return $row[0]['count'] ?? 0;
|
||||
});
|
||||
}
|
||||
|
||||
private function getValue(array $row)
|
||||
@ -281,71 +238,6 @@ class MysqlArray implements DbArray
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current array key
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.key.php
|
||||
* @return string|float|int|bool|null The current array key.
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function key(): ?string
|
||||
{
|
||||
if ($this->key === null) {
|
||||
$row = $this->syncRequest(
|
||||
"SELECT `key` FROM {$this->table} ORDER BY `key` LIMIT 1"
|
||||
);
|
||||
$this->key = $row[0]['key'] ?? null;
|
||||
}
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to next entry
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.next.php
|
||||
* @return void
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$row = $this->syncRequest(
|
||||
"SELECT `key`, `value` FROM {$this->table} WHERE `key` > :key ORDER BY `key` LIMIT 1",
|
||||
['key' => $this->key()]
|
||||
);
|
||||
|
||||
$this->key = $row[0]['key'] ?? null;
|
||||
$this->current = $this->getValue($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether array contains more entries
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayiterator.valid.php
|
||||
* @return bool
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function valid():bool
|
||||
{
|
||||
return $this->key !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to position
|
||||
* @link https://php.net/manual/en/arrayiterator.seek.php
|
||||
* @param int $position <p>
|
||||
* The position to seek to.
|
||||
* </p>
|
||||
* @return void
|
||||
*/
|
||||
public function seek($position)
|
||||
{
|
||||
$row = $this->syncRequest(
|
||||
"SELECT `key` FROM {$this->table} ORDER BY `key` LIMIT 1 OFFSET :position",
|
||||
['offset' => $position]
|
||||
);
|
||||
$this->key = $row[0]['key'] ?? $this->key;
|
||||
}
|
||||
|
||||
public static function getDbConnection(array $settings): Pool
|
||||
{
|
||||
return Mysql::getConnection(
|
||||
@ -384,6 +276,14 @@ class MysqlArray implements DbArray
|
||||
");
|
||||
} catch (\Throwable $e) {
|
||||
Logger::log("Cant rename table {$from} to {$to}", Logger::WARNING);
|
||||
|
||||
try {
|
||||
$this->syncRequest("
|
||||
DROP TABLE {$from};
|
||||
");
|
||||
} catch (\Throwable $e) {
|
||||
Logger::log("Cant drop table {$from}", Logger::WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4285,11 +4285,12 @@ class InternalDoc extends APIFactory
|
||||
*
|
||||
* @param array $user User info
|
||||
*
|
||||
* @return void
|
||||
* @return \Generator<void>
|
||||
* @throws Exception
|
||||
*/
|
||||
public function addUser(array $user): void
|
||||
public function addUser(array $user): \Generator
|
||||
{
|
||||
$this->API->addUser($user);
|
||||
yield from $this->API->addUser($user);
|
||||
}
|
||||
/**
|
||||
* Call promise $b after promise $a.
|
||||
@ -4754,11 +4755,11 @@ class InternalDoc extends APIFactory
|
||||
*
|
||||
* @param mixed $id Chat ID
|
||||
*
|
||||
* @return integer
|
||||
* @return \Generator<integer>
|
||||
*/
|
||||
public function fullChatLastUpdated($id): int
|
||||
public function fullChatLastUpdated($id): \Generator
|
||||
{
|
||||
return $this->API->fullChatLastUpdated($id);
|
||||
return yield from $this->API->fullChatLastUpdated($id);
|
||||
}
|
||||
/**
|
||||
* Get info about the logged-in user, not cached.
|
||||
|
@ -22,6 +22,7 @@ namespace danog\MadelineProto;
|
||||
use Amp\Dns\Resolver;
|
||||
use Amp\File\StatCache;
|
||||
use Amp\Http\Client\HttpClient;
|
||||
use Amp\Promise;
|
||||
use danog\MadelineProto\Async\AsyncConstruct;
|
||||
use danog\MadelineProto\Db\DbArray;
|
||||
use danog\MadelineProto\Db\DbPropertiesFabric;
|
||||
@ -288,13 +289,13 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
/**
|
||||
* Cache of usernames for chats
|
||||
*
|
||||
* @var DbArray
|
||||
* @var DbArray|Promise[]
|
||||
*/
|
||||
public $usernames;
|
||||
/**
|
||||
* Cached parameters for fetching channel participants.
|
||||
*
|
||||
* @var DbArray
|
||||
* @var DbArray|Promise[]
|
||||
*/
|
||||
public $channel_participants;
|
||||
/**
|
||||
@ -312,7 +313,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
/**
|
||||
* Full chat info database.
|
||||
*
|
||||
* @var DbArray
|
||||
* @var DbArray|Promise[]
|
||||
*/
|
||||
public $full_chats;
|
||||
/**
|
||||
@ -454,7 +455,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
// Parse and store settings
|
||||
yield from $this->updateSettings($settings, false);
|
||||
$this->logger->logger(Lang::$current_lang['inst_dc'], Logger::ULTRA_VERBOSE);
|
||||
$this->cleanupProperties();
|
||||
yield from $this->cleanupProperties();
|
||||
// Load rsa keys
|
||||
$this->logger->logger(Lang::$current_lang['load_rsa'], Logger::ULTRA_VERBOSE);
|
||||
$this->rsa_keys = [];
|
||||
@ -565,7 +566,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
];
|
||||
}
|
||||
|
||||
public function initDb(bool $reset = false): void
|
||||
public function initDb(bool $reset = false): \Generator
|
||||
{
|
||||
foreach ($this->dbProperies as $property => $type) {
|
||||
if ($reset) {
|
||||
@ -575,18 +576,16 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
}
|
||||
}
|
||||
|
||||
if (!$reset && count($this->usernames) === 0) {
|
||||
\Amp\Loop::run(function() {
|
||||
$this->logger('Filling database cache. This can take few minutes.', Logger::WARNING);
|
||||
$iterator = $this->chats->getIterator();
|
||||
while (yield $iterator->advance()) {
|
||||
$chat = $iterator->getCurrent();
|
||||
if (isset($chat['username'])) {
|
||||
$this->usernames->offsetSetAsync(\strtolower($chat['username']), $this->getId($chat));
|
||||
}
|
||||
if (!$reset && yield $this->usernames->count() === 0) {
|
||||
$this->logger('Filling database cache. This can take few minutes.', Logger::WARNING);
|
||||
$iterator = $this->chats->getIterator();
|
||||
while (yield $iterator->advance()) {
|
||||
[$id, $chat] = $iterator->getCurrent();
|
||||
if (isset($chat['username'])) {
|
||||
$this->usernames[\strtolower($chat['username'])] = $this->getId($chat);
|
||||
}
|
||||
$this->logger('Cache filled.', Logger::WARNING);
|
||||
});
|
||||
}
|
||||
$this->logger('Cache filled.', Logger::WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,13 +801,17 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$this->TL->init($this->settings['tl_schema']['src'], $callbacks);
|
||||
}
|
||||
|
||||
$this->initDb();
|
||||
yield from $this->initDb();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade MadelineProto instance.
|
||||
*
|
||||
* @return \Generator
|
||||
* @throws Exception
|
||||
* @throws RPCErrorException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
private function upgradeMadelineProto(): \Generator
|
||||
{
|
||||
@ -831,16 +834,19 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
unset($settings['authorization']['rsa_key']);
|
||||
}
|
||||
|
||||
$this->initDb();
|
||||
yield from $this->initDb();
|
||||
|
||||
if (!isset($this->secret_chats)) {
|
||||
$this->secret_chats = [];
|
||||
}
|
||||
foreach ($this->full_chats as $id => $full) {
|
||||
$iterator = $this->full_chats->getIterator();
|
||||
while (yield $iterator->advance()) {
|
||||
[$id, $full] = $iterator->getCurrent();
|
||||
if (isset($full['full'], $full['last_update'])) {
|
||||
$this->full_chats[$id] = ['full' => $full['full'], 'last_update' => $full['last_update']];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->secret_chats as $key => &$chat) {
|
||||
if (!\is_array($chat)) {
|
||||
unset($this->secret_chats[$key]);
|
||||
@ -942,7 +948,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$force = true;
|
||||
}
|
||||
// Cleanup old properties, init new stuffs
|
||||
$this->cleanupProperties();
|
||||
yield from $this->cleanupProperties();
|
||||
// Update TL callbacks
|
||||
$callbacks = [$this, $this->referenceDatabase];
|
||||
if (!($this->authorization['user']['bot'] ?? false)) {
|
||||
@ -1509,9 +1515,9 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return void
|
||||
* @return \Generator<void>
|
||||
*/
|
||||
public function resetSession(): void
|
||||
public function resetSession(): \Generator
|
||||
{
|
||||
if (isset($this->seqUpdater)) {
|
||||
$this->seqUpdater->signal(true);
|
||||
@ -1544,7 +1550,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$this->updates = [];
|
||||
$this->secret_chats = [];
|
||||
|
||||
$this->initDb(true);
|
||||
yield from $this->initDb(true);
|
||||
|
||||
$this->tos = ['expires' => 0, 'accepted' => true];
|
||||
$this->referenceDatabase = new ReferenceDatabase($this);
|
||||
|
@ -22,6 +22,7 @@ namespace danog\MadelineProto\MTProtoTools;
|
||||
use Amp\Http\Client\Request;
|
||||
use danog\Decoder\FileId;
|
||||
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhoto;
|
||||
use danog\MadelineProto\Db\DbArray;
|
||||
|
||||
use const danog\Decoder\PROFILE_PHOTO;
|
||||
|
||||
@ -82,26 +83,29 @@ trait PeerHandler
|
||||
{
|
||||
$this->supportUser = $support['user']['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user info.
|
||||
*
|
||||
* @param array $user User info
|
||||
*
|
||||
* @return void
|
||||
* @return \Generator
|
||||
* @throws \danog\MadelineProto\Exception
|
||||
*/
|
||||
public function addUser(array $user): void
|
||||
public function addUser(array $user): \Generator
|
||||
{
|
||||
$existingChat = yield $this->chats[$user['id']];
|
||||
if (!isset($user['access_hash']) && !($user['min'] ?? false)) {
|
||||
if (isset($this->chats[$user['id']]['access_hash']) && $this->chats[$user['id']]['access_hash']) {
|
||||
if (!empty($existingChat['access_hash'])) {
|
||||
$this->logger->logger("No access hash with user {$user['id']}, using backup");
|
||||
$user['access_hash'] = $this->chats[$user['id']]['access_hash'];
|
||||
$user['access_hash'] = $existingChat['access_hash'];
|
||||
} elseif (!isset($this->caching_simple[$user['id']]) && !(isset($user['username']) && isset($this->caching_simple_username[$user['username']]))) {
|
||||
$this->logger->logger("No access hash with user {$user['id']}, trying to fetch by ID...");
|
||||
if (isset($user['username']) && !isset($this->caching_simple_username[$user['username']])) {
|
||||
$this->caching_possible_username[$user['id']] = $user['username'];
|
||||
}
|
||||
$this->cachePwrChat($user['id'], false, true);
|
||||
} elseif (isset($user['username']) && !isset($this->chats[$user['id']]) && !isset($this->caching_simple_username[$user['username']])) {
|
||||
} elseif (isset($user['username']) && !$existingChat && !isset($this->caching_simple_username[$user['username']])) {
|
||||
$this->logger->logger("No access hash with user {$user['id']}, trying to fetch by username...");
|
||||
$this->cachePwrChat($user['username'], false, true);
|
||||
} else {
|
||||
@ -111,13 +115,13 @@ trait PeerHandler
|
||||
}
|
||||
switch ($user['_']) {
|
||||
case 'user':
|
||||
if (!isset($this->chats[$user['id']]) || $this->chats[$user['id']] !== $user) {
|
||||
if (!$existingChat || $existingChat !== $user) {
|
||||
$this->logger->logger("Updated user {$user['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if (($user['min'] ?? false) && isset($this->chats[$user['id']]) && !($this->chats[$user['id']]['min'] ?? false)) {
|
||||
if (($user['min'] ?? false) && !($existingChat['min'] ?? false)) {
|
||||
$this->logger->logger("{$user['id']} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if (isset($this->chats[$user['id']]['access_hash'])) {
|
||||
if (isset($existingChat['access_hash'])) {
|
||||
$user['min'] = false;
|
||||
$user['access_hash'] = $this->chats[$user['id']]['access_hash'];
|
||||
$user['access_hash'] = $existingChat['access_hash'];
|
||||
}
|
||||
}
|
||||
$this->chats[$user['id']] = $user;
|
||||
@ -138,7 +142,7 @@ trait PeerHandler
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @return void
|
||||
* @return \Generator<void>
|
||||
*/
|
||||
public function addChat($chat): \Generator
|
||||
{
|
||||
@ -146,7 +150,8 @@ trait PeerHandler
|
||||
case 'chat':
|
||||
case 'chatEmpty':
|
||||
case 'chatForbidden':
|
||||
if (!isset($this->chats[-$chat['id']]) || $this->chats[-$chat['id']] !== $chat) {
|
||||
$existingChat = yield $this->chats[-$chat['id']];
|
||||
if (!$existingChat || $existingChat !== $chat) {
|
||||
$this->logger->logger("Updated chat -{$chat['id']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$this->chats[-$chat['id']] = $chat;
|
||||
$this->cacheChatUsername(-$chat['id'], $chat);
|
||||
@ -165,7 +170,7 @@ trait PeerHandler
|
||||
$this->caching_possible_username[$bot_api_id] = $chat['username'];
|
||||
}
|
||||
$this->cachePwrChat($bot_api_id, false, true);
|
||||
} elseif (isset($chat['username']) && !isset($this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) {
|
||||
} elseif (isset($chat['username']) && !(yield $this->chats[$bot_api_id]) && !isset($this->caching_simple_username[$chat['username']])) {
|
||||
$this->logger->logger("No access hash with {$chat['_']} {$bot_api_id}, trying to fetch by username...");
|
||||
$this->cachePwrChat($chat['username'], false, true);
|
||||
} else {
|
||||
@ -173,11 +178,12 @@ trait PeerHandler
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isset($this->chats[$bot_api_id]) || $this->chats[$bot_api_id] !== $chat) {
|
||||
$existingChat = yield $this->chats[$bot_api_id];
|
||||
if (!$existingChat || $existingChat !== $chat) {
|
||||
$this->logger->logger("Updated chat {$bot_api_id}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if (($chat['min'] ?? false) && isset($this->chats[$bot_api_id]) && !($this->chats[$bot_api_id]['min'] ?? false)) {
|
||||
if (($chat['min'] ?? false) && $existingChat && !($existingChat['min'] ?? false)) {
|
||||
$this->logger->logger("{$bot_api_id} is min, filling missing fields", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$newchat = $this->chats[$bot_api_id];
|
||||
$newchat = $existingChat;
|
||||
foreach (['title', 'username', 'photo', 'banned_rights', 'megagroup', 'verified'] as $field) {
|
||||
if (isset($chat[$field])) {
|
||||
$newchat[$field] = $chat[$field];
|
||||
@ -187,7 +193,8 @@ trait PeerHandler
|
||||
}
|
||||
$this->chats[$bot_api_id] = $chat;
|
||||
$this->cacheChatUsername($bot_api_id, $chat);
|
||||
if ($this->settings['peer']['full_fetch'] && (!isset($this->full_chats[$bot_api_id]) || $this->full_chats[$bot_api_id]['full']['participants_count'] !== (yield from $this->getFullInfo($bot_api_id))['full']['participants_count'])) {
|
||||
$fullChat = yield $this->full_chats[$bot_api_id];
|
||||
if ($this->settings['peer']['full_fetch'] && (!$fullChat || $fullChat['full']['participants_count'] !== (yield from $this->getFullInfo($bot_api_id))['full']['participants_count'])) {
|
||||
$this->cachePwrChat($bot_api_id, $this->settings['peer']['full_fetch'], true);
|
||||
}
|
||||
}
|
||||
@ -224,7 +231,9 @@ trait PeerHandler
|
||||
public function peerIsset($id): \Generator
|
||||
{
|
||||
try {
|
||||
return isset($this->chats[(yield from $this->getInfo($id))['bot_api_id']]);
|
||||
$info = yield from $this->getInfo($id);
|
||||
$chatId = $info['bot_api_id'];
|
||||
return (yield $this->chats[$chatId]) !== null;
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
return false;
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
@ -481,7 +490,7 @@ trait PeerHandler
|
||||
}
|
||||
$tried_simple = false;
|
||||
if (\is_numeric($id)) {
|
||||
if (!isset($this->chats[$id])) {
|
||||
if (! yield $this->chats[$id]) {
|
||||
try {
|
||||
$this->logger->logger("Try fetching {$id} with access hash 0");
|
||||
$this->caching_simple[$id] = true;
|
||||
@ -505,15 +514,15 @@ trait PeerHandler
|
||||
$tried_simple = true;
|
||||
}
|
||||
}
|
||||
if (isset($this->chats[$id])) {
|
||||
if (($this->chats[$id]['min'] ?? false) && $this->minDatabase->hasPeer($id) && !isset($this->caching_full_info[$id])) {
|
||||
if (yield $this->chats[$id]) {
|
||||
if (((yield $this->chats[$id])['min'] ?? false) && $this->minDatabase->hasPeer($id) && !isset($this->caching_full_info[$id])) {
|
||||
$this->caching_full_info[$id] = true;
|
||||
$this->logger->logger("Only have min peer for {$id} in database, trying to fetch full info");
|
||||
try {
|
||||
if ($id < 0) {
|
||||
yield from $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
yield from $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll(yield $this->chats[$id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
} else {
|
||||
yield from $this->methodCallAsyncRead('users.getUsers', ['id' => [$this->genAll($this->chats[$id], $folder_id)['InputUser']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
yield from $this->methodCallAsyncRead('users.getUsers', ['id' => [$this->genAll(yield $this->chats[$id], $folder_id)['InputUser']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
}
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING);
|
||||
@ -524,10 +533,10 @@ trait PeerHandler
|
||||
}
|
||||
}
|
||||
try {
|
||||
return $this->genAll($this->chats[$id], $folder_id);
|
||||
return $this->genAll(yield $this->chats[$id], $folder_id);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
if ($e->getMessage() === 'This peer is not present in the internal peer database') {
|
||||
unset($this->chats[$id]);
|
||||
yield $this->chats->offsetUnset($id);/** @uses DbArray::offsetUnset() */
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
@ -574,10 +583,10 @@ trait PeerHandler
|
||||
}
|
||||
return yield from $this->getInfo($this->supportUser);
|
||||
}
|
||||
if ($bot_api_id = $this->usernames[$id] ?? null) {
|
||||
$chat = $this->chats[$bot_api_id];
|
||||
if ($bot_api_id = yield $this->usernames[$id]) {
|
||||
$chat = yield $this->chats[$bot_api_id];
|
||||
if (empty($chat['username']) || \strtolower($chat['username']) !== $id) {
|
||||
unset($this->usernames[$id]);
|
||||
yield $this->usernames->offsetUnset($id); /** @uses DbArray::offsetUnset() */
|
||||
}
|
||||
|
||||
if (isset($chat['username']) && \strtolower($chat['username']) === $id) {
|
||||
@ -586,9 +595,9 @@ trait PeerHandler
|
||||
$this->logger->logger("Only have min peer for {$bot_api_id} in database, trying to fetch full info");
|
||||
try {
|
||||
if ($bot_api_id < 0) {
|
||||
yield from $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll($this->chats[$bot_api_id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
yield from $this->methodCallAsyncRead('channels.getChannels', ['id' => [$this->genAll(yield $this->chats[$bot_api_id], $folder_id)['InputChannel']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
} else {
|
||||
yield from $this->methodCallAsyncRead('users.getUsers', ['id' => [$this->genAll($this->chats[$bot_api_id], $folder_id)['InputUser']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
yield from $this->methodCallAsyncRead('users.getUsers', ['id' => [$this->genAll(yield $this->chats[$bot_api_id], $folder_id)['InputUser']]], ['datacenter' => $this->datacenter->curdc]);
|
||||
}
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->logger->logger($e->getMessage(), \danog\MadelineProto\Logger::WARNING);
|
||||
@ -598,7 +607,7 @@ trait PeerHandler
|
||||
unset($this->caching_full_info[$bot_api_id]);
|
||||
}
|
||||
}
|
||||
return $this->genAll($this->chats[$bot_api_id], $folder_id);
|
||||
return $this->genAll(yield $this->chats[$bot_api_id], $folder_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -674,11 +683,11 @@ trait PeerHandler
|
||||
*
|
||||
* @param mixed $id Chat ID
|
||||
*
|
||||
* @return integer
|
||||
* @return \Generator<integer>
|
||||
*/
|
||||
public function fullChatLastUpdated($id): int
|
||||
public function fullChatLastUpdated($id): \Generator
|
||||
{
|
||||
return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0;
|
||||
return (yield $this->full_chats[$id])['last_update'] ?? 0;
|
||||
}
|
||||
/**
|
||||
* Get full info about peer, returns an FullInfo object.
|
||||
@ -692,8 +701,8 @@ trait PeerHandler
|
||||
public function getFullInfo($id): \Generator
|
||||
{
|
||||
$partial = (yield from $this->getInfo($id));
|
||||
if (\time() - $this->fullChatLastUpdated($partial['bot_api_id']) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) {
|
||||
return \array_merge($partial, $this->full_chats[$partial['bot_api_id']]);
|
||||
if (\time() - (yield from $this->fullChatLastUpdated($partial['bot_api_id'])) < (isset($this->settings['peer']['full_info_cache_time']) ? $this->settings['peer']['full_info_cache_time'] : 0)) {
|
||||
return \array_merge($partial, yield $this->full_chats[$partial['bot_api_id']]);
|
||||
}
|
||||
switch ($partial['type']) {
|
||||
case 'user':
|
||||
@ -912,10 +921,10 @@ trait PeerHandler
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
if ($cached = $gres['_'] === 'channels.channelParticipantsNotModified') {
|
||||
$gres = $this->fetchParticipantsCache($channel, $filter, $q, $offset, $limit);
|
||||
if ($cached = ($gres['_'] === 'channels.channelParticipantsNotModified')) {
|
||||
$gres = yield from $this->fetchParticipantsCache($channel, $filter, $q, $offset, $limit);
|
||||
} else {
|
||||
$this->storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit);
|
||||
yield from $this->storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit);
|
||||
}
|
||||
if ($last_count !== -1 && $last_count !== $gres['count']) {
|
||||
$has_more = true;
|
||||
@ -975,11 +984,10 @@ trait PeerHandler
|
||||
}
|
||||
private function fetchParticipantsCache($channel, $filter, $q, $offset, $limit)
|
||||
{
|
||||
return $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit];
|
||||
return (yield $this->channel_participants[$channel['channel_id']])[$filter][$q][$offset][$limit];
|
||||
}
|
||||
private function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit)
|
||||
private function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit): \Generator
|
||||
{
|
||||
//return;
|
||||
unset($gres['users']);
|
||||
$ids = [];
|
||||
foreach ($gres['participants'] as $participant) {
|
||||
@ -987,13 +995,13 @@ trait PeerHandler
|
||||
}
|
||||
\sort($ids, SORT_NUMERIC);
|
||||
$gres['hash'] = \danog\MadelineProto\Tools::genVectorHash($ids);
|
||||
$participant = $this->channel_participants[$channel['channel_id']];
|
||||
$participant = yield $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)
|
||||
{
|
||||
return isset($this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]) ? $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]['hash'] : 0;
|
||||
return (yield $this->channel_participants[$channel['channel_id']])[$filter][$q][$offset][$limit]['hash'] ?? 0;
|
||||
}
|
||||
private function storeDb($res, $force = false): \Generator
|
||||
{
|
||||
@ -1054,6 +1062,12 @@ trait PeerHandler
|
||||
}
|
||||
}
|
||||
if ($res['_'] === 'contacts.resolvedPeer') {
|
||||
foreach ($res['chats'] as $chat) {
|
||||
yield from $this->addChat($chat);
|
||||
}
|
||||
foreach ($res['users'] as $user) {
|
||||
yield from $this->addUser($user);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
return false;
|
||||
|
@ -422,10 +422,10 @@ class ReferenceDatabase implements TLCallback
|
||||
break;
|
||||
// Peer + photo ID
|
||||
case self::PEER_PHOTO_ORIGIN:
|
||||
if (isset($this->API->full_chats[$origin['peer']]['last_update'])) {
|
||||
$chat = $this->API->full_chats[$origin['peer']];
|
||||
$chat['last_update'] = 0;
|
||||
$this->API->full_chats[$origin['peer']] = $chat;
|
||||
$fullChat = yield $this->API->full_chats[$origin['peer']];
|
||||
if (isset($fullChat['last_update'])) {
|
||||
$fullChat['last_update'] = 0;
|
||||
$this->API->full_chats[$origin['peer']] = $fullChat;
|
||||
}
|
||||
$this->API->getFullInfo($origin['peer']);
|
||||
break;
|
||||
|
@ -332,7 +332,7 @@ trait UpdateHandler
|
||||
}
|
||||
if (\in_array($update['_'], ['updateUserName', 'updateUserPhone', 'updateUserBlocked', 'updateUserPhoto', 'updateContactRegistered', 'updateContactLink'])) {
|
||||
$id = $this->getId($update);
|
||||
$chat = $this->full_chats[$id];
|
||||
$chat = yield $this->full_chats[$id];
|
||||
$chat['last_update'] = 0;
|
||||
$this->full_chats[$id] = $chat;
|
||||
yield from $this->getFullInfo($id);
|
||||
|
@ -32,13 +32,15 @@ trait DialogHandler
|
||||
{
|
||||
if ($this->authorization['user']['bot']) {
|
||||
$res = [];
|
||||
foreach ($this->chats as $chat) {
|
||||
/** @uses DbArray::getIterator() */
|
||||
$iterator = $this->chats->getIterator();
|
||||
while (yield $iterator->advance()) {
|
||||
[$id, $chat] = $iterator->getCurrent();
|
||||
try {
|
||||
$res[] = $this->genAll($chat)['Peer'];
|
||||
} catch (\Throwable $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ trait Login
|
||||
public function logout(): \Generator
|
||||
{
|
||||
yield from $this->methodCallAsyncRead('auth.logOut', [], ['datacenter' => $this->datacenter->curdc]);
|
||||
$this->resetSession();
|
||||
yield from $this->resetSession();
|
||||
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['logout_ok'], \danog\MadelineProto\Logger::NOTICE);
|
||||
$this->startUpdateSystem();
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user