Properly update database settings when deserializing; also enable optional database backend for event handler variables

This commit is contained in:
Daniil Gentili 2020-10-07 16:48:34 +02:00
parent 7e281c1589
commit 6ce4de6091
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
11 changed files with 63 additions and 63 deletions

View File

@ -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' => "<code>$res</code>", '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);

View File

@ -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]
);

View File

@ -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') {

View File

@ -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<DbType>
@ -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);
}
}

View File

@ -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});
}
}
}

View File

@ -8,12 +8,11 @@ use danog\MadelineProto\Settings\DatabaseAbstract;
interface DbType
{
/**
* @param string $name
* @param null $value
* @param string $tablePrefix
* @param string $table
* @param null|DbType|array $value
* @param DatabaseAbstract $settings
*
* @return Promise<self>
*/
public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise;
public static function getInstance(string $table, $value = null, $settings): Promise;
}

View File

@ -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<self>
*/
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) {

View File

@ -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<static>
*/
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 */

View File

@ -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();
}

View File

@ -4666,16 +4666,6 @@ class InternalDoc extends APIFactory
{
return $this->__call(__FUNCTION__, [$id]);
}
/**
* Check state of calls.
*
* @psalm-return void|\Amp\Promise<void>
* @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.
*

View File

@ -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;
@ -98,6 +100,7 @@ abstract class Serialization
* - Store IPC state
*
* @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<void, mixed, mixed, array{0: ChannelledSocket|APIWrapper|\Throwable|null|0, 1: callable|null}>
*/
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...");
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!");