Properly update database settings when deserializing; also enable optional database backend for event handler variables
This commit is contained in:
parent
7e281c1589
commit
6ce4de6091
@ -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);
|
||||
|
||||
|
@ -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]
|
||||
);
|
||||
|
@ -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') {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<self>
|
||||
*/
|
||||
public static function getInstance(string $name, $value = null, string $tablePrefix = '', $settings): Promise;
|
||||
public static function getInstance(string $table, $value = null, $settings): Promise;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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<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...");
|
||||
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!");
|
||||
|
Loading…
Reference in New Issue
Block a user