mirror of
https://github.com/danog/MadelineProto.git
synced 2025-01-22 22:51:11 +01:00
Remove non-IPC fallback, improve IPC logic
This commit is contained in:
parent
b2446fd4d7
commit
76446a2d82
2
docs
2
docs
@ -1 +1 @@
|
||||
Subproject commit 31abc3950cba076c9db6c79f209203ac6cd35cad
|
||||
Subproject commit 84c66b69ecdb6407ce254f1d901a253f6b6c00a0
|
@ -159,5 +159,7 @@
|
||||
|
||||
"account_banned": "!!!!!!! WARNING !!!!!!!\nTelegram's flood prevention system suspended this account.\nTo continue, manual verification is required.\nSend an email to recover@telegram.org, asking to unban the phone number %s, and shortly describe what will you do with this phone number.\nThen login again.\nIf you intentionally deleted this account, ignore this message.",
|
||||
|
||||
"plugin_path_does_not_exist": "Plugin path %s does not exist!"
|
||||
"plugin_path_does_not_exist": "Plugin path %s does not exist!",
|
||||
|
||||
"could_not_connect_to_MadelineProto": "Could not connect to MadelineProto, please enable proc_open or disable webserver path rewrites to fix!"
|
||||
}
|
||||
|
14
src/API.php
14
src/API.php
@ -311,7 +311,7 @@ final class API extends AbstractAPI
|
||||
$this->session,
|
||||
$settings,
|
||||
$forceFull
|
||||
)->await(Tools::getTimeoutCancellation(30.0));
|
||||
)->await(Tools::getTimeoutCancellation(3.0));
|
||||
} catch (CancelledException $e) {
|
||||
if (!$e->getPrevious() instanceof TimeoutException) {
|
||||
throw $e;
|
||||
@ -322,16 +322,10 @@ final class API extends AbstractAPI
|
||||
|
||||
if ($unserialized === 0) {
|
||||
// Timeout
|
||||
Logger::log('!!! Could not connect to MadelineProto, please check and report the logs for more details. !!!', Logger::FATAL_ERROR);
|
||||
if (!$tryReconnect || (\defined('MADELINEPROTO_TEST') && \constant('MADELINEPROTO_TEST') === 'testing')) {
|
||||
throw new Exception('Could not connect to MadelineProto, please check the MadelineProto.log file to debug!');
|
||||
}
|
||||
Logger::log('!!! Reconnecting using slower method. !!!', Logger::FATAL_ERROR);
|
||||
// IPC server error, try fetching full session
|
||||
return $this->connectToMadelineProto($settings, true, false);
|
||||
throw new Exception(Lang::$current_lang['could_not_connect_to_MadelineProto']);
|
||||
} elseif ($unserialized instanceof Throwable) {
|
||||
// IPC server error, try fetching full session
|
||||
return $this->connectToMadelineProto($settings, true);
|
||||
// IPC server error
|
||||
throw $unserialized;
|
||||
} elseif ($unserialized instanceof ChannelledSocket) {
|
||||
// Success, IPC client
|
||||
$this->wrapper->setAPI(new Client($unserialized, $this->session, Logger::$default));
|
||||
|
@ -53,7 +53,7 @@ abstract class AbstractMessage extends Update implements SimpleFilters
|
||||
$this->id = $rawMessage['id'];
|
||||
$this->chatId = $info['bot_api_id'];
|
||||
$this->senderId = isset($rawMessage['from_id'])
|
||||
? $this->API->getIdInternal($rawMessage['from_id'])
|
||||
? $this->getClient()->getIdInternal($rawMessage['from_id'])
|
||||
: $this->chatId;
|
||||
$this->date = $rawMessage['date'];
|
||||
$this->mentioned = $rawMessage['mentioned'];
|
||||
@ -131,14 +131,14 @@ abstract class AbstractMessage extends Update implements SimpleFilters
|
||||
}
|
||||
return $this->replyCache;
|
||||
}
|
||||
$messages = $this->API->methodCallAsyncRead(
|
||||
$messages = $this->getClient()->methodCallAsyncRead(
|
||||
API::isSupergroup($this->chatId) ? 'channels.getMessages' : 'messages.getMessages',
|
||||
[
|
||||
'channel' => $this->chatId,
|
||||
'id' => [['_' => 'inputMessageReplyTo', 'id' => $this->id]]
|
||||
]
|
||||
)['messages'];
|
||||
$this->replyCache = $messages ? $this->API->wrapMessage($messages[0]) : null;
|
||||
$this->replyCache = $messages ? $this->getClient()->wrapMessage($messages[0]) : null;
|
||||
$this->replyCached = true;
|
||||
if (!$this->replyCache instanceof $class) {
|
||||
return null;
|
||||
@ -153,7 +153,7 @@ abstract class AbstractMessage extends Update implements SimpleFilters
|
||||
*/
|
||||
public function delete(bool $revoke = true): void
|
||||
{
|
||||
$this->API->methodCallAsyncRead(
|
||||
$this->getClient()->methodCallAsyncRead(
|
||||
API::isSupergroup($this->chatId) ? 'channels.deleteMessages' : 'messages.deleteMessages',
|
||||
[
|
||||
'channel' => $this->chatId,
|
||||
@ -191,7 +191,7 @@ abstract class AbstractMessage extends Update implements SimpleFilters
|
||||
bool $noWebpage = false,
|
||||
bool $updateStickersetsOrder = false,
|
||||
): Message {
|
||||
return $this->API->sendMessage(
|
||||
return $this->getClient()->sendMessage(
|
||||
peer: $this->chatId,
|
||||
message: $message,
|
||||
parseMode: $parseMode,
|
||||
|
@ -82,7 +82,7 @@ abstract class Media extends IpcCapable implements JsonSerializable
|
||||
*/
|
||||
public function getDownloadLink(?string $scriptUrl = null): string
|
||||
{
|
||||
return $this->API->getDownloadLink($this, $scriptUrl);
|
||||
return $this->getClient()->getDownloadLink($this, $scriptUrl);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -95,13 +95,13 @@ abstract class Message extends AbstractMessage
|
||||
$this->fwdInfo = new ForwardedInfo(
|
||||
$fwdFrom['date'],
|
||||
isset($fwdFrom['from_id'])
|
||||
? $this->API->getIdInternal($fwdFrom['from_id'])
|
||||
? $this->getClient()->getIdInternal($fwdFrom['from_id'])
|
||||
: null,
|
||||
$fwdFrom['from_name'] ?? null,
|
||||
$fwdFrom['channel_post'] ?? null,
|
||||
$fwdFrom['post_author'] ?? null,
|
||||
isset($fwdFrom['saved_from_peer'])
|
||||
? $this->API->getIdInternal($fwdFrom['saved_from_peer'])
|
||||
? $this->getClient()->getIdInternal($fwdFrom['saved_from_peer'])
|
||||
: null,
|
||||
$fwdFrom['saved_from_msg_id'] ?? null
|
||||
);
|
||||
|
@ -27,6 +27,7 @@ use Amp\Ipc\Sync\ChannelledSocket;
|
||||
use danog\MadelineProto\Exception;
|
||||
use danog\MadelineProto\FileCallbackInterface;
|
||||
use danog\MadelineProto\Logger;
|
||||
use danog\MadelineProto\MTProto;
|
||||
use danog\MadelineProto\MTProtoTools\FilesLogic;
|
||||
use danog\MadelineProto\SessionPaths;
|
||||
use danog\MadelineProto\Tools;
|
||||
@ -55,9 +56,9 @@ final class Client extends ClientAbstract
|
||||
/**
|
||||
* Returns an instance of a client by session name.
|
||||
*/
|
||||
public static function giveInstanceBySession(string $session): Client
|
||||
public static function giveInstanceBySession(string $session): Client|MTProto
|
||||
{
|
||||
return self::$instances[$session];
|
||||
return self::$instances[$session] ?? MTProto::giveInstanceBySession($session);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@ final class EventHandlerProxy extends IpcCapable
|
||||
}
|
||||
public function __call(string $name, array $arguments): mixed
|
||||
{
|
||||
return $this->API->callPluginMethod(
|
||||
return $this->getClient()->callPluginMethod(
|
||||
$this->__plugin,
|
||||
$name,
|
||||
$arguments
|
||||
@ -23,18 +23,18 @@ final class EventHandlerProxy extends IpcCapable
|
||||
}
|
||||
public function __get(string $name): mixed
|
||||
{
|
||||
return $this->API->getPluginProperty($this->__plugin, $name);
|
||||
return $this->getClient()->getPluginProperty($this->__plugin, $name);
|
||||
}
|
||||
public function __set(string $name, mixed $value): void
|
||||
{
|
||||
$this->API->setPluginProperty($this->__plugin, $name, $value);
|
||||
$this->getClient()->setPluginProperty($this->__plugin, $name, $value);
|
||||
}
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return $this->API->issetPluginProperty($this->__plugin, $name);
|
||||
return $this->getClient()->issetPluginProperty($this->__plugin, $name);
|
||||
}
|
||||
public function __unset(string $name): void
|
||||
{
|
||||
$this->API->unsetPluginProperty($this->__plugin, $name);
|
||||
$this->getClient()->unsetPluginProperty($this->__plugin, $name);
|
||||
}
|
||||
}
|
||||
|
@ -11,35 +11,30 @@ use danog\MadelineProto\MTProto;
|
||||
*/
|
||||
abstract class IpcCapable
|
||||
{
|
||||
private readonly string $session;
|
||||
protected MTProto|Client|null $API;
|
||||
protected readonly string $session;
|
||||
private MTProto|Client|null $API;
|
||||
|
||||
/** @internal */
|
||||
protected function __construct(
|
||||
MTProto|Client $API,
|
||||
) {
|
||||
protected function __construct(MTProto $API)
|
||||
{
|
||||
$this->API = $API;
|
||||
if ($API instanceof MTProto) {
|
||||
$this->session = $API->wrapper->getSession()->getSessionDirectoryPath();
|
||||
} else {
|
||||
$this->session = $API->getSession()->getSessionDirectoryPath();
|
||||
}
|
||||
$this->session = $API->getSessionName();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function __sleep()
|
||||
final public function __sleep()
|
||||
{
|
||||
$vars = \get_object_vars($this);
|
||||
unset($vars['API']);
|
||||
return \array_keys($vars);
|
||||
}
|
||||
/** @internal */
|
||||
public function __wakeup(): void
|
||||
|
||||
final protected function getClient(): MTProto|Client
|
||||
{
|
||||
$this->API = Client::giveInstanceBySession($this->session);
|
||||
return $this->API ??= Client::giveInstanceBySession($this->session);
|
||||
}
|
||||
|
||||
public function __debugInfo()
|
||||
final public function __debugInfo()
|
||||
{
|
||||
$vars = \get_object_vars($this);
|
||||
unset($vars['API']);
|
||||
|
@ -419,6 +419,16 @@ final class MTProto implements TLCallback, LoggerGetter
|
||||
'session' => ['innerMadelineProto' => true, 'enableCache' => false],
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns an instance of a client by session name.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function giveInstanceBySession(string $session): MTProto
|
||||
{
|
||||
return self::$references[$session];
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize session, returning object to serialize to db.
|
||||
*
|
||||
@ -482,8 +492,8 @@ final class MTProto implements TLCallback, LoggerGetter
|
||||
public function __construct(Settings|SettingsEmpty $settings, ?APIWrapper $wrapper = null)
|
||||
{
|
||||
if ($wrapper) {
|
||||
self::$references[\spl_object_hash($this)] = $this;
|
||||
$this->wrapper = $wrapper;
|
||||
self::$references[$this->getSessionName()] = $this;
|
||||
}
|
||||
|
||||
$initDeferred = new DeferredFuture;
|
||||
@ -974,10 +984,10 @@ final class MTProto implements TLCallback, LoggerGetter
|
||||
// Setup one-time stuffs
|
||||
Magic::start(light: false);
|
||||
|
||||
// Set reference to itself
|
||||
self::$references[\spl_object_hash($this)] = $this;
|
||||
// Set API wrapper
|
||||
$this->wrapper = $wrapper;
|
||||
// Set reference to itself
|
||||
self::$references[$this->getSessionName()] = $this;
|
||||
|
||||
$deferred = new DeferredFuture;
|
||||
$this->initPromise = $deferred->getFuture();
|
||||
@ -1072,8 +1082,8 @@ final class MTProto implements TLCallback, LoggerGetter
|
||||
$this->logger = new Logger(new \danog\MadelineProto\Settings\Logger);
|
||||
}
|
||||
$this->logger->logger('Will unreference instance');
|
||||
if (isset(self::$references[\spl_object_hash($this)])) {
|
||||
unset(self::$references[\spl_object_hash($this)]);
|
||||
if (isset(self::$references[$this->getSessionName()])) {
|
||||
unset(self::$references[$this->getSessionName()]);
|
||||
}
|
||||
$this->stopLoops();
|
||||
if (isset($this->seqUpdater)) {
|
||||
|
@ -35,6 +35,7 @@ use Revolt\EventLoop;
|
||||
use Throwable;
|
||||
|
||||
use const LOCK_EX;
|
||||
|
||||
use function Amp\File\exists;
|
||||
use function Amp\Ipc\connect;
|
||||
|
||||
|
@ -21,7 +21,7 @@ declare(strict_types=1);
|
||||
namespace danog\MadelineProto\TL\Types;
|
||||
|
||||
use ArrayAccess;
|
||||
use danog\MadelineProto\Ipc\Client;
|
||||
use danog\MadelineProto\Ipc\IpcCapable;
|
||||
use danog\MadelineProto\MTProto;
|
||||
use JsonSerializable;
|
||||
|
||||
@ -30,7 +30,7 @@ use JsonSerializable;
|
||||
*
|
||||
* @implements ArrayAccess<array-key, mixed>
|
||||
*/
|
||||
final class Button implements JsonSerializable, ArrayAccess
|
||||
final class Button extends IpcCapable implements JsonSerializable, ArrayAccess
|
||||
{
|
||||
/** Button label */
|
||||
public readonly string $label;
|
||||
@ -40,15 +40,6 @@ final class Button implements JsonSerializable, ArrayAccess
|
||||
* @var array<array-key, mixed>
|
||||
*/
|
||||
private array $button = [];
|
||||
/**
|
||||
* Session name.
|
||||
*/
|
||||
private string $session = '';
|
||||
/**
|
||||
* MTProto instance.
|
||||
*
|
||||
*/
|
||||
private MTProto|Client|null $API = null;
|
||||
/**
|
||||
* Message ID.
|
||||
*/
|
||||
@ -69,6 +60,7 @@ final class Button implements JsonSerializable, ArrayAccess
|
||||
*/
|
||||
public function __construct(MTProto $API, array $message, array $button)
|
||||
{
|
||||
parent::__construct($API);
|
||||
if (!isset($message['from_id']) // No other option
|
||||
// It's a channel/chat, 100% what we need
|
||||
|| $message['peer_id']['_'] !== 'peerUser'
|
||||
@ -82,15 +74,6 @@ final class Button implements JsonSerializable, ArrayAccess
|
||||
$this->label = $button['text'];
|
||||
$this->button = $button;
|
||||
$this->id = $message['id'];
|
||||
$this->API = $API;
|
||||
$this->session = $API->getWrapper()->getSession()->getSessionDirectoryPath();
|
||||
}
|
||||
/**
|
||||
* Sleep function.
|
||||
*/
|
||||
public function __sleep(): array
|
||||
{
|
||||
return ['button', 'peer', 'id', 'session'];
|
||||
}
|
||||
/**
|
||||
* Click on button.
|
||||
@ -99,18 +82,17 @@ final class Button implements JsonSerializable, ArrayAccess
|
||||
*/
|
||||
public function click(bool $donotwait = true)
|
||||
{
|
||||
$this->API ??= Client::giveInstanceBySession($this->session);
|
||||
switch ($this->button['_']) {
|
||||
default:
|
||||
return false;
|
||||
case 'keyboardButtonUrl':
|
||||
return $this->button['url'];
|
||||
case 'keyboardButton':
|
||||
return $this->API->clickInternal($donotwait, 'messages.sendMessage', ['peer' => $this->peer, 'message' => $this->button['text'], 'reply_to_msg_id' => $this->id]);
|
||||
return $this->getClient()->clickInternal($donotwait, 'messages.sendMessage', ['peer' => $this->peer, 'message' => $this->button['text'], 'reply_to_msg_id' => $this->id]);
|
||||
case 'keyboardButtonCallback':
|
||||
return $this->API->clickInternal($donotwait, 'messages.getBotCallbackAnswer', ['peer' => $this->peer, 'msg_id' => $this->id, 'data' => $this->button['data']]);
|
||||
return $this->getClient()->clickInternal($donotwait, 'messages.getBotCallbackAnswer', ['peer' => $this->peer, 'msg_id' => $this->id, 'data' => $this->button['data']]);
|
||||
case 'keyboardButtonGame':
|
||||
return $this->API->clickInternal($donotwait, 'messages.getBotCallbackAnswer', ['peer' => $this->peer, 'msg_id' => $this->id, 'game' => true]);
|
||||
return $this->getClient()->clickInternal($donotwait, 'messages.getBotCallbackAnswer', ['peer' => $this->peer, 'msg_id' => $this->id, 'game' => true]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -30,7 +30,7 @@ use BaconQrCode\Renderer\ImageRenderer;
|
||||
use BaconQrCode\Renderer\PlainTextRenderer;
|
||||
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||
use BaconQrCode\Writer;
|
||||
use danog\MadelineProto\Ipc\Client;
|
||||
use danog\MadelineProto\Ipc\IpcCapable;
|
||||
use danog\MadelineProto\MTProto;
|
||||
use danog\MadelineProto\Tools;
|
||||
use JsonSerializable;
|
||||
@ -38,27 +38,17 @@ use JsonSerializable;
|
||||
/**
|
||||
* Represents a login QR code.
|
||||
*/
|
||||
final class LoginQrCode implements JsonSerializable
|
||||
final class LoginQrCode extends IpcCapable implements JsonSerializable
|
||||
{
|
||||
private string $session;
|
||||
|
||||
/** @internal */
|
||||
public function __construct(
|
||||
private MTProto|Client $API,
|
||||
MTProto $API,
|
||||
/** @var non-empty-string The [QR code login link](https://core.telegram.org/api/links#qr-code-login-links) */
|
||||
public readonly string $link,
|
||||
/** @var positive-int The expiry date of the link */
|
||||
public readonly int $expiry
|
||||
) {
|
||||
$this->session = $API->getWrapper()->getSession()->getSessionDirectoryPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __sleep(): array
|
||||
{
|
||||
return ['link', 'expiry', 'session'];
|
||||
parent::__construct($API);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@ -95,8 +85,7 @@ final class LoginQrCode implements JsonSerializable
|
||||
|
||||
public function getLoginCancellation(): Cancellation
|
||||
{
|
||||
$this->API ??= Client::giveInstanceBySession($this->session);
|
||||
return $this->API->getQrLoginCancellation();
|
||||
return $this->getClient()->getQrLoginCancellation();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,7 +115,7 @@ final class LoginQrCode implements JsonSerializable
|
||||
(new DeferredFuture)->getFuture()->await($cancellation);
|
||||
} catch (CancelledException) {
|
||||
$customCancellation?->throwIfRequested();
|
||||
return $this->API->qrLogin();
|
||||
return $this->getClient()->qrLogin();
|
||||
}
|
||||
throw new AssertionError("Unreachable!");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user