Improve logging and settings logic
This commit is contained in:
parent
dbba5a1583
commit
0a33f69e8b
6
bot.php
6
bot.php
@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
use danog\MadelineProto\Stream\Proxy\SocksProxy;
|
||||
|
||||
/*
|
||||
Copyright 2016-2019 Daniil Gentili
|
||||
(https://daniil.it)
|
||||
@ -9,7 +11,7 @@ MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
See the GNU Affero General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with MadelineProto.
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
*/
|
||||
set_include_path(get_include_path().':'.realpath(dirname(__FILE__).'/MadelineProto/'));
|
||||
|
||||
/*
|
||||
@ -56,7 +58,7 @@ class EventHandler extends \danog\MadelineProto\EventHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
$settings = ['logger' => ['logger_level' => 5], 'connection_settings' => ['all' => ['protocol' => 'tcp_abridged']]];
|
||||
$settings = ['logger' => ['logger_level' => 5], 'connection_settings' => ['all' => ['protocol' => 'tcp_abridged', 'proxy' => SocksProxy::getName(), 'proxy_extra' => ['address' => '1.pwrtelegram.xyz', 'port' => 1080]]]];
|
||||
|
||||
$MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings);
|
||||
$MadelineProto->async(true);
|
||||
|
@ -49,6 +49,7 @@
|
||||
"files": [
|
||||
"src/BigIntegor.php",
|
||||
"src/YieldReturnValue.php",
|
||||
"src/ReflectionGenerator.php",
|
||||
"src/polyfill.php"
|
||||
]
|
||||
},
|
||||
|
36
src/ReflectionGenerator.php
Normal file
36
src/ReflectionGenerator.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
if (!class_exists('ReflectionGenerator')) {
|
||||
class ReflectionGenerator
|
||||
{
|
||||
private $generator;
|
||||
public function __construct(Generator $generator)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
}
|
||||
public function getExecutingFile(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
public function getExecutingGenerator(): Generator
|
||||
{
|
||||
return $this->generator;
|
||||
}
|
||||
public function getExecutingLine(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public function getFunction(): ReflectionFunctionAbstract
|
||||
{
|
||||
return new ReflectionFunction(function () {});
|
||||
}
|
||||
public function getThis(): object
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function getTrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
@ -57,17 +57,8 @@ class API extends APIFactory
|
||||
public function __construct_async($params, $settings, $deferred)
|
||||
{
|
||||
if (is_string($params)) {
|
||||
if (!\danog\MadelineProto\Logger::$default) {
|
||||
if (!isset($settings['logger']['logger_param'])) {
|
||||
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
||||
}
|
||||
Logger::constructorFromSettings($settings);
|
||||
|
||||
if (!isset($settings['logger']['logger'])) {
|
||||
$settings['logger']['logger'] = php_sapi_name() === 'cli' ? 3 : 2;
|
||||
}
|
||||
|
||||
\danog\MadelineProto\Logger::constructor($settings['logger']['logger'], $settings['logger']['logger_param'], '', isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE, isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
}
|
||||
$realpaths = Serialization::realpaths($params);
|
||||
$this->session = $realpaths['file'];
|
||||
|
||||
@ -157,15 +148,8 @@ class API extends APIFactory
|
||||
}
|
||||
$params = $settings;
|
||||
}
|
||||
if (!\danog\MadelineProto\Logger::$default) {
|
||||
if (!isset($settings['logger']['logger_param'])) {
|
||||
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
||||
}
|
||||
if (!isset($settings['logger']['logger'])) {
|
||||
$settings['logger']['logger'] = php_sapi_name() === 'cli' ? 3 : 2;
|
||||
}
|
||||
\danog\MadelineProto\Logger::constructor($settings['logger']['logger'], $settings['logger']['logger_param'], '', isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE, isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
}
|
||||
Logger::constructorFromSettings($settings);
|
||||
|
||||
if (!isset($params['app_info']['api_id']) || !$params['app_info']['api_id']) {
|
||||
$app = yield $this->api_start_async($params);
|
||||
$params['app_info']['api_id'] = $app['api_id'];
|
||||
|
@ -31,10 +31,10 @@ class Logger
|
||||
{
|
||||
use Tools;
|
||||
|
||||
const foreground = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97];
|
||||
const background = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107];
|
||||
const set = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6];
|
||||
const reset = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28];
|
||||
const FOREGROUND = ['default' => 39, 'black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'light_gray' => 37, 'dark_gray' => 90, 'light_red' => 91, 'light_green' => 92, 'light_yellow' => 93, 'light_blue' => 94, 'light_magenta' => 95, 'light_cyan' => 96, 'white' => 97];
|
||||
const BACKGROUND = ['default' => 49, 'black' => 40, 'red' => 41, 'magenta' => 45, 'yellow' => 43, 'green' => 42, 'blue' => 44, 'cyan' => 46, 'light_gray' => 47, 'dark_gray' => 100, 'light_red' => 101, 'light_green' => 102, 'light_yellow' => 103, 'light_blue' => 104, 'light_magenta' => 105, 'light_cyan' => 106, 'white' => 107];
|
||||
const SET = ['bold' => 1, 'dim' => 2, 'underlined' => 3, 'blink' => 4, 'reverse' => 5, 'hidden' => 6];
|
||||
const RESET = ['all' => 0, 'bold' => 21, 'dim' => 22, 'underlined' => 24, 'blink' => 25, 'reverse' => 26, 'hidden' => 28];
|
||||
|
||||
public $mode = 0;
|
||||
public $optional = null;
|
||||
@ -60,21 +60,72 @@ class Logger
|
||||
const ECHO_LOGGER = 3;
|
||||
const CALLABLE_LOGGER = 4;
|
||||
|
||||
/*
|
||||
* Constructor function
|
||||
* Accepts various logger modes:
|
||||
* 0 - No logger
|
||||
* 1 - Log to the default logger destination
|
||||
* 2 - Log to file defined in second parameter
|
||||
* 3 - Echo logs
|
||||
* 4 - Call callable provided in logger_param. logger_param must accept two parameters: array $message, int $level
|
||||
* $message is an array containing the messages the log, $level, is the logging level
|
||||
/**
|
||||
* Construct global logger
|
||||
*
|
||||
* @param [type] $mode
|
||||
* @param [type] $optional
|
||||
* @param string $prefix
|
||||
* @param [type] $level
|
||||
* @param [type] $max_size
|
||||
* @return void
|
||||
*/
|
||||
public static function constructor($mode, $optional = null, $prefix = '', $level = self::NOTICE, $max_size = 100 * 1024 * 1024)
|
||||
{
|
||||
self::$default = new self($mode, $optional, $prefix, $level, $max_size);
|
||||
}
|
||||
/**
|
||||
* Construct global static logger from MadelineProto settings
|
||||
*
|
||||
* @param array $settings
|
||||
* @return void
|
||||
*/
|
||||
public static function constructorFromSettings(array $settings) {
|
||||
if (!self::$default) {
|
||||
// The getLogger function will automatically init the static logger, but we'll do it again anyway
|
||||
self::$default = self::getLoggerFromSettings(MTProto::getSettings($settings));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get logger from MadelineProto settings
|
||||
*
|
||||
* @param array $settings
|
||||
* @param string $prefix Optional prefix
|
||||
* @return self
|
||||
*/
|
||||
public static function getLoggerFromSettings(array $settings, string $prefix = ''): self
|
||||
{
|
||||
if (isset($settings['logger']['rollbar_token']) && $settings['logger']['rollbar_token'] !== '' && class_exists('\\Rollbar\\Rollbar')) {
|
||||
@\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => isset($settings['logger']['rollbar_token']) && !in_array($settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718', '11a8c2fe4c474328b40a28193f8d63f5', 'beef2d426496462ba34dcaad33d44a14']) || $settings['pwr']['pwr'] ? $settings['logger']['rollbar_token'] : 'c07d9b2f73c2461297b0beaef6c1662f'], false, false);
|
||||
} else {
|
||||
Exception::$rollbar = false;
|
||||
RPCErrorException::$rollbar = false;
|
||||
}
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
if (isset($settings['logger']['logger_param']) && basename($settings['logger']['logger_param']) === 'MadelineProto.log') {
|
||||
$settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
||||
}
|
||||
}
|
||||
|
||||
$logger = new self($settings['logger']['logger'], isset($settings['logger']['logger_param']) ? $settings['logger']['logger_param'] : '', $prefix, isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE, isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
if (!self::$default) {
|
||||
self::$default = $logger;
|
||||
}
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
try {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
|
||||
error_log('Enabled PHP logging');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$logger->logger('Could not enable PHP logging');
|
||||
}
|
||||
}
|
||||
|
||||
return $logger;
|
||||
}
|
||||
public function __construct($mode, $optional = null, $prefix = '', $level = self::NOTICE, $max_size = 100 * 1024 * 1024)
|
||||
{
|
||||
if ($mode === null) {
|
||||
@ -97,12 +148,12 @@ class Logger
|
||||
unlink($this->optional);
|
||||
}
|
||||
|
||||
$this->colors[self::ULTRA_VERBOSE] = implode(';', [self::foreground['light_gray'], self::set['dim']]);
|
||||
$this->colors[self::VERBOSE] = implode(';', [self::foreground['green'], self::set['bold']]);
|
||||
$this->colors[self::NOTICE] = implode(';', [self::foreground['yellow'], self::set['bold']]);
|
||||
$this->colors[self::WARNING] = implode(';', [self::foreground['white'], self::set['dim'], self::background['red']]);
|
||||
$this->colors[self::ERROR] = implode(';', [self::foreground['white'], self::set['bold'], self::background['red']]);
|
||||
$this->colors[self::FATAL_ERROR] = implode(';', [self::foreground['red'], self::set['bold'], self::background['light_gray']]);
|
||||
$this->colors[self::ULTRA_VERBOSE] = implode(';', [self::FOREGROUND['light_gray'], self::SET['dim']]);
|
||||
$this->colors[self::VERBOSE] = implode(';', [self::FOREGROUND['green'], self::SET['bold']]);
|
||||
$this->colors[self::NOTICE] = implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
||||
$this->colors[self::WARNING] = implode(';', [self::FOREGROUND['white'], self::SET['dim'], self::BACKGROUND['red']]);
|
||||
$this->colors[self::ERROR] = implode(';', [self::FOREGROUND['white'], self::SET['bold'], self::BACKGROUND['red']]);
|
||||
$this->colors[self::FATAL_ERROR] = implode(';', [self::FOREGROUND['red'], self::SET['bold'], self::BACKGROUND['light_gray']]);
|
||||
$this->newline = PHP_EOL;
|
||||
|
||||
if ($this->mode === 3) {
|
||||
@ -138,14 +189,14 @@ class Logger
|
||||
}
|
||||
if (!self::$printed) {
|
||||
self::$printed = true;
|
||||
$this->colors[self::NOTICE] = implode(';', [self::foreground['light_gray'], self::set['bold'], self::background['blue']]);
|
||||
$this->colors[self::NOTICE] = implode(';', [self::FOREGROUND['light_gray'], self::SET['bold'], self::BACKGROUND['blue']]);
|
||||
|
||||
$this->logger('MadelineProto');
|
||||
$this->logger('Copyright (C) 2016-2019 Daniil Gentili');
|
||||
$this->logger('Licensed under AGPLv3');
|
||||
$this->logger('https://github.com/danog/MadelineProto');
|
||||
|
||||
$this->colors[self::NOTICE] = implode(';', [self::foreground['yellow'], self::set['bold']]);
|
||||
$this->colors[self::NOTICE] = implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
|
||||
}
|
||||
if ($this->mode === 4) {
|
||||
return call_user_func_array($this->optional, [$param, $level]);
|
||||
|
@ -507,18 +507,17 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$this->wrapper->serialize($this->wrapper->session);
|
||||
}
|
||||
}
|
||||
|
||||
public function parse_settings($settings)
|
||||
public static function getSettings($settings, $previousSettings = [])
|
||||
{
|
||||
if (isset($this->settings['connection_settings']['default_dc'])) {
|
||||
$settings['connection_settings']['default_dc'] = $this->settings['connection_settings']['default_dc'];
|
||||
if (isset($previousSettings['connection_settings']['default_dc'])) {
|
||||
$settings['connection_settings']['default_dc'] = $previousSettings['connection_settings']['default_dc'];
|
||||
}
|
||||
if (!isset($settings['app_info']['api_id']) || !$settings['app_info']['api_id']) {
|
||||
if (isset($this->settings['app_info']['api_id']) && $this->settings['app_info']['api_id']) {
|
||||
$settings['app_info']['api_id'] = $this->settings['app_info']['api_id'];
|
||||
$settings['app_info']['api_hash'] = $this->settings['app_info']['api_hash'];
|
||||
if (isset($previousSettings['app_info']['api_id']) && $previousSettings['app_info']['api_id']) {
|
||||
$settings['app_info']['api_id'] = $previousSettings['app_info']['api_id'];
|
||||
$settings['app_info']['api_hash'] = $previousSettings['app_info']['api_hash'];
|
||||
} else {
|
||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1);
|
||||
$settings['app_info'] = null;
|
||||
}
|
||||
}
|
||||
// Detect device model
|
||||
@ -795,10 +794,6 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
// Need info ?
|
||||
'requests' => true,
|
||||
]];
|
||||
|
||||
if (!is_array($settings)) {
|
||||
$settings = [];
|
||||
}
|
||||
$settings = array_replace_recursive($default_settings, $settings);
|
||||
if (isset(Lang::$lang[$settings['app_info']['lang_code']])) {
|
||||
Lang::$current_lang = &Lang::$lang[$settings['app_info']['lang_code']];
|
||||
@ -826,6 +821,14 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
$settings['logger']['logger_level'] = 0;
|
||||
break;
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
public function parse_settings($settings)
|
||||
{
|
||||
$settings = self::getSettings($settings, $this->settings);
|
||||
if ($this->settings['app_info'] === null) {
|
||||
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['api_not_set'], 0, null, 'MadelineProto', 1);
|
||||
}
|
||||
$this->settings = $settings;
|
||||
if (!$this->settings['updates']['handle_updates']) {
|
||||
$this->updates = [];
|
||||
@ -836,34 +839,7 @@ class MTProto extends AsyncConstruct implements TLCallback
|
||||
|
||||
public function setup_logger()
|
||||
{
|
||||
if (isset($this->settings['logger']['rollbar_token']) && $this->settings['logger']['rollbar_token'] !== '' && class_exists('\\Rollbar\\Rollbar')) {
|
||||
@\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => isset($this->settings['logger']['rollbar_token']) && !in_array($this->settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718', '11a8c2fe4c474328b40a28193f8d63f5', 'beef2d426496462ba34dcaad33d44a14']) || $this->settings['pwr']['pwr'] ? $this->settings['logger']['rollbar_token'] : 'c07d9b2f73c2461297b0beaef6c1662f'], false, false);
|
||||
} else {
|
||||
Exception::$rollbar = false;
|
||||
RPCErrorException::$rollbar = false;
|
||||
}
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
if (isset($this->settings['logger']['logger_param']) && basename($this->settings['logger']['logger_param']) === 'MadelineProto.log') {
|
||||
$this->settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger = new \danog\MadelineProto\Logger($this->settings['logger']['logger'], isset($this->settings['logger']['logger_param']) ? $this->settings['logger']['logger_param'] : '', isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : '', isset($this->settings['logger']['logger_level']) ? $this->settings['logger']['logger_level'] : Logger::VERBOSE, isset($this->settings['logger']['max_size']) ? $this->settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
if (!\danog\MadelineProto\Logger::$default) {
|
||||
\danog\MadelineProto\Logger::constructor($this->settings['logger']['logger'], $this->settings['logger']['logger_param'], isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : '', isset($this->settings['logger']['logger_level']) ? $this->settings['logger']['logger_level'] : Logger::VERBOSE, isset($this->settings['logger']['max_size']) ? $this->settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
}
|
||||
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
try {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', Magic::$script_cwd.'/MadelineProto.log');
|
||||
error_log('Enabled PHP logging');
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->logger->logger('Could not enable PHP logging');
|
||||
}
|
||||
}
|
||||
$this->logger = Logger::getLoggerFromSettings($this->settings, isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : '');
|
||||
}
|
||||
|
||||
public function reset_session($de = true, $auth_key = false)
|
||||
|
@ -32,7 +32,7 @@ class MyTelegramOrgWrapper
|
||||
private $token;
|
||||
private $number;
|
||||
private $creation_hash;
|
||||
private $settings;
|
||||
private $settings = [];
|
||||
private $async = true;
|
||||
const MY_TELEGRAM_URL = 'https://my.telegram.org';
|
||||
|
||||
@ -43,42 +43,18 @@ class MyTelegramOrgWrapper
|
||||
|
||||
public function __construct($settings = [])
|
||||
{
|
||||
if (!isset($settings['all'])) {
|
||||
$settings['connection_settings'] = ['all' => [
|
||||
// These settings will be applied on every datacenter that hasn't a custom settings subarray...
|
||||
'protocol' => Magic::$altervista ? 'http' : 'tcp_abridged',
|
||||
// can be tcp_full, tcp_abridged, tcp_intermediate, http, https, obfuscated2, udp (unsupported)
|
||||
'test_mode' => false,
|
||||
// decides whether to connect to the main telegram servers or to the testing servers (deep telegram)
|
||||
'ipv6' => \danog\MadelineProto\Magic::$ipv6,
|
||||
// decides whether to use ipv6, ipv6 attribute of API attribute of API class contains autodetected boolean
|
||||
'timeout' => 2,
|
||||
// timeout for sockets
|
||||
'proxy' => Magic::$altervista ? '\\HttpProxy' : '\\Socket',
|
||||
// The proxy class to use
|
||||
'proxy_extra' => Magic::$altervista ? ['address' => 'localhost', 'port' => 80] : [],
|
||||
// Extra parameters to pass to the proxy class using setExtra
|
||||
'obfuscated' => false,
|
||||
'transport' => 'tcp',
|
||||
'pfs' => extension_loaded('gmp'),
|
||||
],
|
||||
];
|
||||
}
|
||||
$this->settings = $settings;
|
||||
$this->settings = MTProto::getSettings($settings, $this->settings);
|
||||
$this->__wakeup();
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->datacenter = new DataCenter(
|
||||
new class($this->settings) {
|
||||
new class($this->settings)
|
||||
{
|
||||
public function __construct($settings)
|
||||
{
|
||||
$this->logger = new Logger(
|
||||
isset($settings['logger']['logger']) ? $settings['logger']['logger'] : php_sapi_name() === 'cli' ? 3 : 2,
|
||||
isset($settings['logger']['logger_param']) ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log',
|
||||
isset($settings['logger']['logger_level']) ? $settings['logger']['logger_level'] : Logger::VERBOSE,
|
||||
isset($settings['logger']['max_size']) ? $settings['logger']['max_size'] : 100 * 1024 * 1024);
|
||||
$this->logger = Logger::getLoggerFromSettings($settings);
|
||||
}
|
||||
},
|
||||
[],
|
||||
|
Loading…
Reference in New Issue
Block a user