From 6ce4de6091c8819c35c6edbd0bb08347ce083039 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 7 Oct 2020 16:48:34 +0200 Subject: [PATCH] Properly update database settings when deserializing; also enable optional database backend for event handler variables --- examples/bot.php | 17 ++++++------ src/danog/MadelineProto/API.php | 2 +- .../MadelineProto/AnnotationsBuilder.php | 4 +-- .../MadelineProto/Db/DbPropertiesFactory.php | 16 +++++++----- .../MadelineProto/Db/DbPropertiesTrait.php | 5 +++- src/danog/MadelineProto/Db/DbType.php | 9 +++---- src/danog/MadelineProto/Db/MemoryArray.php | 5 ++-- src/danog/MadelineProto/Db/SqlArray.php | 10 +++---- src/danog/MadelineProto/EventHandler.php | 8 ++++++ src/danog/MadelineProto/InternalDoc.php | 26 ------------------- src/danog/MadelineProto/Serialization.php | 24 ++++++++++++++--- 11 files changed, 63 insertions(+), 63 deletions(-) diff --git a/examples/bot.php b/examples/bot.php index fed847d9..525ce416 100755 --- a/examples/bot.php +++ b/examples/bot.php @@ -22,6 +22,8 @@ use danog\MadelineProto\API; use danog\MadelineProto\EventHandler; use danog\MadelineProto\Logger; +use danog\MadelineProto\Settings; +use danog\MadelineProto\Settings\Database\Redis; /* * Various ways to load MadelineProto @@ -80,7 +82,6 @@ class MyEventHandler extends EventHandler return; } - $res = \json_encode($update, JSON_PRETTY_PRINT); yield $this->messages->sendMessage(['peer' => $update, 'message' => "$res", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']); if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') { @@ -88,14 +89,12 @@ class MyEventHandler extends EventHandler } } } -$settings = [ - 'logger' => [ - 'logger_level' => Logger::ULTRA_VERBOSE - ], - 'serialization' => [ - 'serialization_interval' => 30, - ] -]; + +$settings = new Settings; +$settings->getLogger()->setLevel(Logger::LEVEL_ULTRA_VERBOSE); + +// You can also use MySQL or PostgreSQL +// $settings->setDb(new Redis); $MadelineProto = new API('bot.madeline', $settings); diff --git a/src/danog/MadelineProto/API.php b/src/danog/MadelineProto/API.php index 8646da8a..8834b48e 100644 --- a/src/danog/MadelineProto/API.php +++ b/src/danog/MadelineProto/API.php @@ -193,7 +193,7 @@ class API extends InternalDoc } [$unserialized, $this->unlock] = yield Tools::timeoutWithDefault( - Serialization::unserialize($this->session, $forceFull), + Serialization::unserialize($this->session, $settings, $forceFull), 30000, [0, null] ); diff --git a/src/danog/MadelineProto/AnnotationsBuilder.php b/src/danog/MadelineProto/AnnotationsBuilder.php index 61fc9a3e..12f7968e 100644 --- a/src/danog/MadelineProto/AnnotationsBuilder.php +++ b/src/danog/MadelineProto/AnnotationsBuilder.php @@ -172,9 +172,9 @@ class AnnotationsBuilder $internalDoc[$namespace][$method]['return'] = $type; } $class = new \ReflectionClass($this->reflectionClasses['MTProto']); - $methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC); + $methods = $class->getMethods((\ReflectionMethod::IS_STATIC & \ReflectionMethod::IS_PUBLIC) | \ReflectionMethod::IS_PUBLIC); $class = new \ReflectionClass(Tools::class); - $methods = \array_merge($methods, $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC)); + $methods = \array_merge($methods, $class->getMethods((\ReflectionMethod::IS_STATIC & \ReflectionMethod::IS_PUBLIC) | \ReflectionMethod::IS_PUBLIC)); foreach ($methods as $key => $method) { $name = $method->getName(); if ($method == 'methodCallAsyncRead') { diff --git a/src/danog/MadelineProto/Db/DbPropertiesFactory.php b/src/danog/MadelineProto/Db/DbPropertiesFactory.php index b9bba22f..f77a76af 100644 --- a/src/danog/MadelineProto/Db/DbPropertiesFactory.php +++ b/src/danog/MadelineProto/Db/DbPropertiesFactory.php @@ -11,11 +11,15 @@ use danog\MadelineProto\Settings\DatabaseAbstract; class DbPropertiesFactory { + /** + * Indicates a simple K-V array stored in a database backend. + * Values can be objects or other arrays, but when lots of nesting is required, it's best to split the array into multiple arrays. + */ + const TYPE_ARRAY = 'array'; /** * @param DatabaseAbstract $dbSettings - * @param string $namePrefix - * @param string|array $propertyType - * @param string $name + * @param string $table + * @param self::TYPE_*|array $propertyType * @param $value * * @return Promise @@ -25,7 +29,7 @@ class DbPropertiesFactory * @uses \danog\MadelineProto\Db\PostgresArray * @uses \danog\MadelineProto\Db\RedisArray */ - public static function get(DatabaseAbstract $dbSettings, string $namePrefix, $propertyType, string $name, $value = null): Promise + public static function get(DatabaseAbstract $dbSettings, string $table, $propertyType, $value = null): Promise { $config = $propertyType['config'] ?? []; $propertyType = \is_array($propertyType) ? $propertyType['type'] : $propertyType; @@ -54,13 +58,13 @@ class DbPropertiesFactory /** @var DbType $class */ switch (\strtolower($propertyType)) { - case 'array': + case self::TYPE_ARRAY: $class .= 'Array'; break; default: throw new \InvalidArgumentException("Unknown $propertyType: {$propertyType}"); } - return $class::getInstance($name, $value, $namePrefix, $dbSettings); + return $class::getInstance($table, $value, $dbSettings); } } diff --git a/src/danog/MadelineProto/Db/DbPropertiesTrait.php b/src/danog/MadelineProto/Db/DbPropertiesTrait.php index 809d5f4a..5cb902ec 100644 --- a/src/danog/MadelineProto/Db/DbPropertiesTrait.php +++ b/src/danog/MadelineProto/Db/DbPropertiesTrait.php @@ -9,6 +9,8 @@ trait DbPropertiesTrait /** * Initialize database instance. * + * @internal + * * @param MTProto $MadelineProto * @param boolean $reset * @return \Generator @@ -25,7 +27,8 @@ trait DbPropertiesTrait if ($reset) { unset($this->{$property}); } else { - $this->{$property} = yield DbPropertiesFactory::get($dbSettings, $prefix, $type, $property, $this->{$property}); + $table = "{$prefix}_{$property}"; + $this->{$property} = yield DbPropertiesFactory::get($dbSettings, $table, $type, $this->{$property}); } } } diff --git a/src/danog/MadelineProto/Db/DbType.php b/src/danog/MadelineProto/Db/DbType.php index af39e339..93d8a235 100644 --- a/src/danog/MadelineProto/Db/DbType.php +++ b/src/danog/MadelineProto/Db/DbType.php @@ -8,12 +8,11 @@ use danog\MadelineProto\Settings\DatabaseAbstract; interface DbType { /** - * @param string $name - * @param null $value - * @param string $tablePrefix - * @param DatabaseAbstract $settings + * @param string $table + * @param null|DbType|array $value + * @param DatabaseAbstract $settings * * @return Promise */ - public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise; + public static function getInstance(string $table, $value = null, $settings): Promise; } diff --git a/src/danog/MadelineProto/Db/MemoryArray.php b/src/danog/MadelineProto/Db/MemoryArray.php index 71d5cb31..4b96a90b 100644 --- a/src/danog/MadelineProto/Db/MemoryArray.php +++ b/src/danog/MadelineProto/Db/MemoryArray.php @@ -20,13 +20,12 @@ class MemoryArray extends \ArrayIterator implements DbArray /** * Get instance. * - * @param string $name + * @param string $table * @param mixed $value - * @param string $tablePrefix * @param Memory $settings * @return Promise */ - public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise + public static function getInstance(string $table, $value = null, $settings): Promise { return call(static function () use ($value) { if ($value instanceof MemoryArray) { diff --git a/src/danog/MadelineProto/Db/SqlArray.php b/src/danog/MadelineProto/Db/SqlArray.php index d21aa02c..1e10dba8 100644 --- a/src/danog/MadelineProto/Db/SqlArray.php +++ b/src/danog/MadelineProto/Db/SqlArray.php @@ -24,23 +24,21 @@ abstract class SqlArray extends DriverArray /** - * @param string $name + * @param string $table * @param DbArray|array|null $value - * @param string $tablePrefix * @param DatabaseAbstract $settings * * @return Promise * * @psalm-return Promise */ - public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise + public static function getInstance(string $table, $value = null, $settings): Promise { - $tableName = "{$tablePrefix}_{$name}"; - if ($value instanceof static && $value->table === $tableName) { + if ($value instanceof static && $value->table === $table) { $instance = &$value; } else { $instance = new static(); - $instance->table = $tableName; + $instance->table = $table; } /** @psalm-suppress UndefinedPropertyAssignment */ diff --git a/src/danog/MadelineProto/EventHandler.php b/src/danog/MadelineProto/EventHandler.php index 842d583c..a8c206a2 100644 --- a/src/danog/MadelineProto/EventHandler.php +++ b/src/danog/MadelineProto/EventHandler.php @@ -19,11 +19,16 @@ namespace danog\MadelineProto; +use danog\MadelineProto\Db\DbPropertiesTrait; + /** * Event handler. */ abstract class EventHandler extends InternalDoc { + use DbPropertiesTrait { + DbPropertiesTrait::initDb as private internalInitDb; + } /** * Whether the event handler was started. */ @@ -57,6 +62,9 @@ abstract class EventHandler extends InternalDoc if ($this->startedInternal) { return; } + if (isset(static::$dbProperties)) { + yield from $this->internalInitDb($this->API); + } if (\method_exists($this, 'onStart')) { yield $this->onStart(); } diff --git a/src/danog/MadelineProto/InternalDoc.php b/src/danog/MadelineProto/InternalDoc.php index a0cff163..4d408807 100644 --- a/src/danog/MadelineProto/InternalDoc.php +++ b/src/danog/MadelineProto/InternalDoc.php @@ -4666,16 +4666,6 @@ class InternalDoc extends APIFactory { return $this->__call(__FUNCTION__, [$id]); } - /** - * Check state of calls. - * - * @psalm-return void|\Amp\Promise - * @return mixed - */ - public function checkCalls() - { - $this->__call(__FUNCTION__, []); - } /** * Check for terms of service update. * @@ -5422,11 +5412,6 @@ class InternalDoc extends APIFactory { return $this->__call(__FUNCTION__, [$extra]); } - - public function getSessionId(\danog\MadelineProto\MTProto $madelineProto): string - { - return \danog\MadelineProto\MTProto::getSessionId($madelineProto); - } /** * Return current settings. * @@ -5551,17 +5536,6 @@ class InternalDoc extends APIFactory { return \danog\MadelineProto\Tools::inflateStripped($stripped); } - /** - * Initialize database instance. - * - * @param MTProto $MadelineProto - * @param boolean $reset - * @return \Amp\Promise - */ - public function initDb(\danog\MadelineProto\MTProto $MadelineProto, bool $reset = false, array $extra = []) - { - return $this->__call(__FUNCTION__, [$MadelineProto, $reset, $extra]); - } /** * Initialize self-restart hack. * diff --git a/src/danog/MadelineProto/Serialization.php b/src/danog/MadelineProto/Serialization.php index 368e5730..2cde7e45 100644 --- a/src/danog/MadelineProto/Serialization.php +++ b/src/danog/MadelineProto/Serialization.php @@ -23,9 +23,11 @@ use Amp\Deferred; use Amp\Ipc\Sync\ChannelledSocket; use Amp\Loop; use Amp\Promise; +use danog\MadelineProto\Db\DbPropertiesFactory; use danog\MadelineProto\Db\DriverArray; use danog\MadelineProto\Ipc\Server; use danog\MadelineProto\MTProtoSession\Session; +use danog\MadelineProto\Settings\DatabaseAbstract; use function Amp\File\exists; use function Amp\File\get; @@ -97,8 +99,9 @@ abstract class Serialization * - Start IPC server * - Store IPC state * - * @param SessionPaths $session Session name - * @param bool $forceFull Whether to force full session deserialization + * @param SessionPaths $session Session name + * @param SettingsAbstract $settings Settings + * @param bool $forceFull Whether to force full session deserialization * * @internal * @@ -106,7 +109,7 @@ abstract class Serialization * * @psalm-return \Generator */ - public static function unserialize(SessionPaths $session, bool $forceFull = false): \Generator + public static function unserialize(SessionPaths $session, SettingsAbstract $settings, bool $forceFull = false): \Generator { if (yield exists($session->getSessionPath())) { // Is new session @@ -197,7 +200,20 @@ abstract class Serialization $unserialized = yield from $session->unserialize(); if ($unserialized instanceof DriverArray) { Logger::log("Extracting session from database..."); - yield from $unserialized->initStartup(); + if ($settings instanceof Settings) { + $settings = $settings->getDb(); + } + if ($settings instanceof DatabaseAbstract) { + $tableName = (string) $unserialized; + $unserialized = yield DbPropertiesFactory::get( + $settings, + $tableName, + DbPropertiesFactory::TYPE_ARRAY, + $unserialized + ); + } else { + yield from $unserialized->initStartup(); + } $unserialized = yield $unserialized['data']; if (!$unserialized) { throw new Exception("Could not extract session from database!");