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\API;
use danog\MadelineProto\EventHandler; use danog\MadelineProto\EventHandler;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\Settings;
use danog\MadelineProto\Settings\Database\Redis;
/* /*
* Various ways to load MadelineProto * Various ways to load MadelineProto
@ -80,7 +82,6 @@ class MyEventHandler extends EventHandler
return; return;
} }
$res = \json_encode($update, JSON_PRETTY_PRINT); $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']); 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') { if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') {
@ -88,14 +89,12 @@ class MyEventHandler extends EventHandler
} }
} }
} }
$settings = [
'logger' => [ $settings = new Settings;
'logger_level' => Logger::ULTRA_VERBOSE $settings->getLogger()->setLevel(Logger::LEVEL_ULTRA_VERBOSE);
],
'serialization' => [ // You can also use MySQL or PostgreSQL
'serialization_interval' => 30, // $settings->setDb(new Redis);
]
];
$MadelineProto = new API('bot.madeline', $settings); $MadelineProto = new API('bot.madeline', $settings);

View File

@ -193,7 +193,7 @@ class API extends InternalDoc
} }
[$unserialized, $this->unlock] = yield Tools::timeoutWithDefault( [$unserialized, $this->unlock] = yield Tools::timeoutWithDefault(
Serialization::unserialize($this->session, $forceFull), Serialization::unserialize($this->session, $settings, $forceFull),
30000, 30000,
[0, null] [0, null]
); );

View File

@ -172,9 +172,9 @@ class AnnotationsBuilder
$internalDoc[$namespace][$method]['return'] = $type; $internalDoc[$namespace][$method]['return'] = $type;
} }
$class = new \ReflectionClass($this->reflectionClasses['MTProto']); $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); $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) { foreach ($methods as $key => $method) {
$name = $method->getName(); $name = $method->getName();
if ($method == 'methodCallAsyncRead') { if ($method == 'methodCallAsyncRead') {

View File

@ -11,11 +11,15 @@ use danog\MadelineProto\Settings\DatabaseAbstract;
class DbPropertiesFactory 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 DatabaseAbstract $dbSettings
* @param string $namePrefix * @param string $table
* @param string|array $propertyType * @param self::TYPE_*|array $propertyType
* @param string $name
* @param $value * @param $value
* *
* @return Promise<DbType> * @return Promise<DbType>
@ -25,7 +29,7 @@ class DbPropertiesFactory
* @uses \danog\MadelineProto\Db\PostgresArray * @uses \danog\MadelineProto\Db\PostgresArray
* @uses \danog\MadelineProto\Db\RedisArray * @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'] ?? []; $config = $propertyType['config'] ?? [];
$propertyType = \is_array($propertyType) ? $propertyType['type'] : $propertyType; $propertyType = \is_array($propertyType) ? $propertyType['type'] : $propertyType;
@ -54,13 +58,13 @@ class DbPropertiesFactory
/** @var DbType $class */ /** @var DbType $class */
switch (\strtolower($propertyType)) { switch (\strtolower($propertyType)) {
case 'array': case self::TYPE_ARRAY:
$class .= 'Array'; $class .= 'Array';
break; break;
default: default:
throw new \InvalidArgumentException("Unknown $propertyType: {$propertyType}"); 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. * Initialize database instance.
* *
* @internal
*
* @param MTProto $MadelineProto * @param MTProto $MadelineProto
* @param boolean $reset * @param boolean $reset
* @return \Generator * @return \Generator
@ -25,7 +27,8 @@ trait DbPropertiesTrait
if ($reset) { if ($reset) {
unset($this->{$property}); unset($this->{$property});
} else { } 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 interface DbType
{ {
/** /**
* @param string $name * @param string $table
* @param null $value * @param null|DbType|array $value
* @param string $tablePrefix * @param DatabaseAbstract $settings
* @param DatabaseAbstract $settings
* *
* @return Promise<self> * @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. * Get instance.
* *
* @param string $name * @param string $table
* @param mixed $value * @param mixed $value
* @param string $tablePrefix
* @param Memory $settings * @param Memory $settings
* @return Promise<self> * @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) { return call(static function () use ($value) {
if ($value instanceof MemoryArray) { 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 DbArray|array|null $value
* @param string $tablePrefix
* @param DatabaseAbstract $settings * @param DatabaseAbstract $settings
* *
* @return Promise * @return Promise
* *
* @psalm-return Promise<static> * @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 === $table) {
if ($value instanceof static && $value->table === $tableName) {
$instance = &$value; $instance = &$value;
} else { } else {
$instance = new static(); $instance = new static();
$instance->table = $tableName; $instance->table = $table;
} }
/** @psalm-suppress UndefinedPropertyAssignment */ /** @psalm-suppress UndefinedPropertyAssignment */

View File

@ -19,11 +19,16 @@
namespace danog\MadelineProto; namespace danog\MadelineProto;
use danog\MadelineProto\Db\DbPropertiesTrait;
/** /**
* Event handler. * Event handler.
*/ */
abstract class EventHandler extends InternalDoc abstract class EventHandler extends InternalDoc
{ {
use DbPropertiesTrait {
DbPropertiesTrait::initDb as private internalInitDb;
}
/** /**
* Whether the event handler was started. * Whether the event handler was started.
*/ */
@ -57,6 +62,9 @@ abstract class EventHandler extends InternalDoc
if ($this->startedInternal) { if ($this->startedInternal) {
return; return;
} }
if (isset(static::$dbProperties)) {
yield from $this->internalInitDb($this->API);
}
if (\method_exists($this, 'onStart')) { if (\method_exists($this, 'onStart')) {
yield $this->onStart(); yield $this->onStart();
} }

View File

@ -4666,16 +4666,6 @@ class InternalDoc extends APIFactory
{ {
return $this->__call(__FUNCTION__, [$id]); 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. * Check for terms of service update.
* *
@ -5422,11 +5412,6 @@ class InternalDoc extends APIFactory
{ {
return $this->__call(__FUNCTION__, [$extra]); return $this->__call(__FUNCTION__, [$extra]);
} }
public function getSessionId(\danog\MadelineProto\MTProto $madelineProto): string
{
return \danog\MadelineProto\MTProto::getSessionId($madelineProto);
}
/** /**
* Return current settings. * Return current settings.
* *
@ -5551,17 +5536,6 @@ class InternalDoc extends APIFactory
{ {
return \danog\MadelineProto\Tools::inflateStripped($stripped); 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. * Initialize self-restart hack.
* *

View File

@ -23,9 +23,11 @@ use Amp\Deferred;
use Amp\Ipc\Sync\ChannelledSocket; use Amp\Ipc\Sync\ChannelledSocket;
use Amp\Loop; use Amp\Loop;
use Amp\Promise; use Amp\Promise;
use danog\MadelineProto\Db\DbPropertiesFactory;
use danog\MadelineProto\Db\DriverArray; use danog\MadelineProto\Db\DriverArray;
use danog\MadelineProto\Ipc\Server; use danog\MadelineProto\Ipc\Server;
use danog\MadelineProto\MTProtoSession\Session; use danog\MadelineProto\MTProtoSession\Session;
use danog\MadelineProto\Settings\DatabaseAbstract;
use function Amp\File\exists; use function Amp\File\exists;
use function Amp\File\get; use function Amp\File\get;
@ -97,8 +99,9 @@ abstract class Serialization
* - Start IPC server * - Start IPC server
* - Store IPC state * - Store IPC state
* *
* @param SessionPaths $session Session name * @param SessionPaths $session Session name
* @param bool $forceFull Whether to force full session deserialization * @param SettingsAbstract $settings Settings
* @param bool $forceFull Whether to force full session deserialization
* *
* @internal * @internal
* *
@ -106,7 +109,7 @@ abstract class Serialization
* *
* @psalm-return \Generator<void, mixed, mixed, array{0: ChannelledSocket|APIWrapper|\Throwable|null|0, 1: callable|null}> * @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())) { if (yield exists($session->getSessionPath())) {
// Is new session // Is new session
@ -197,7 +200,20 @@ abstract class Serialization
$unserialized = yield from $session->unserialize(); $unserialized = yield from $session->unserialize();
if ($unserialized instanceof DriverArray) { if ($unserialized instanceof DriverArray) {
Logger::log("Extracting session from database..."); 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']; $unserialized = yield $unserialized['data'];
if (!$unserialized) { if (!$unserialized) {
throw new Exception("Could not extract session from database!"); throw new Exception("Could not extract session from database!");