Compare commits

...

2 Commits

Author SHA1 Message Date
Alexander Pankratov
9c8ea1d564
Merge branch 'master' into upstream_docker_image 2024-07-14 20:52:51 +02:00
Alexander Pankratov
ca478d07df Feat: uncaught errors notification 2024-07-14 20:42:33 +02:00
6 changed files with 103 additions and 8 deletions

View File

@ -15,7 +15,7 @@ TIMEZONE=UTC
# VALUE IN SECOND
# DECREASE TO REDUCE LATENCY, INCREASE TO REDUCE LOAD ON SERVER.
# SET to 0 to DISABLE
REQUESTS_BULK_INTERVAL=0.5
REQUESTS_BULK_INTERVAL=0.0
# List of allowed clients. Separate with comma.
# Leave blanc, to allow requests from all IP (THIS WILL MAKE API UNSECURE!)
@ -67,4 +67,11 @@ DB_SERIALIZER=serialize
# Enable to add cache info about users to database. Disable if you only read data from channels.
DB_ENABLE_MIN_DATABASE=0
# Enable file metadata cache
DB_ENABLE_FILE_REFERENCE_DATABASE=0
DB_ENABLE_FILE_REFERENCE_DATABASE=0
ERROR_NOTIFICATION_BOT_TOKEN=
#User id or Chat id or username of the target channel to send error messages. Comma separated
#Example: 123456,@sometestchannel
ERROR_NOTIFICATION_PEERS=
# Program will continue to work after fatal error (not recommended)
RESUME_ON_ERROR=0

View File

@ -16,7 +16,7 @@ TIMEZONE=UTC
# VALUE IN SECOND
# DECREASE TO REDUCE LATENCY, INCREASE TO REDUCE LOAD ON SERVER.
# SET to 0 to DISABLE
REQUESTS_BULK_INTERVAL=0.5
REQUESTS_BULK_INTERVAL=0.0
# List of allowed clients. Separate with comma.
# Leave blanc, to allow requests from all IP (THIS WILL MAKE API UNSECURE!)
@ -65,4 +65,11 @@ DB_SERIALIZER=serialize
# Enable to add cache info about users to database. Disable if you only read data from channels.
DB_ENABLE_MIN_DATABASE=0
# Enable file metadata cache
DB_ENABLE_FILE_REFERENCE_DATABASE=0
DB_ENABLE_FILE_REFERENCE_DATABASE=0
ERROR_NOTIFICATION_BOT_TOKEN=
#User id or Chat id or username of the target channel to send error messages. Comma separated
#Example: 123456,@sometestchannel
ERROR_NOTIFICATION_PEERS=
# Program will continue to work after fatal error (not recommended)
RESUME_ON_ERROR=0

View File

@ -27,8 +27,9 @@
"php": "^8.2",
"ext-json": "*",
"ext-mbstring": "*",
"amphp/http-server": "^3.3.1",
"amphp/http": "^2.1.1",
"ext-curl": "*",
"amphp/http-server": "^v3",
"amphp/http": "^v2",
"amphp/http-server-router": "^2",
"amphp/http-server-form-parser": "^v2",
"amphp/websocket-server": "^3.0.1",

View File

@ -11,6 +11,19 @@ $settings = [
'port' => (int)getenv('SERVER_PORT'),
'real_ip_header' => (string)(getenv('REAL_IP_HEADER') ?? ''),
],
'error' => [
'bot_token' => (string)getenv('ERROR_NOTIFICATION_BOT_TOKEN'),
'peers' => array_filter(
array_map(
static function(string $peer): string|int {
$peer = trim($peer);
return is_numeric($peer) ? (int)$peer : $peer;
},
explode(',', (string)getenv('ERROR_NOTIFICATION_PEERS'))
),
),
'resume_on_error' => ((bool)getenv('RESUME_ON_ERROR'))
],
'telegram' => [
'app_info' => [ // obtained in https://my.telegram.org
'api_id' => (int)getenv('TELEGRAM_API_ID'),

View File

@ -11,8 +11,11 @@ use danog\MadelineProto\SettingsAbstract;
use InvalidArgumentException;
use Psr\Log\LogLevel;
use ReflectionProperty;
use Revolt\EventLoop;
use RuntimeException;
use TelegramApiServer\EventObservers\EventObserver;
use function Amp\async;
use function Amp\delay;
final class Client
{
@ -32,6 +35,10 @@ final class Client
{
warning(PHP_EOL . 'Starting MadelineProto...' . PHP_EOL);
$this->setFatalErrorHandler();
EventLoop::queue(fn() => throw new \Exception('test'));
foreach ($sessionFiles as $file) {
$sessionName = Files::getSessionName($file);
$this->addSession($sessionName);
@ -198,4 +205,64 @@ final class Client
return $settingsObject;
}
private function setFatalErrorHandler(): void
{
$token = Config::getInstance()->get('error.bot_token');
$peers = Config::getInstance()->get('error.peers');
$resume = Config::getInstance()->get('error.resume_on_error');
$currentHandler = EventLoop::getErrorHandler();
EventLoop::setErrorHandler(static fn(\Throwable $e) => self::errorHandler($e, $currentHandler, $token, $peers, $resume));
}
private static function errorHandler(\Throwable $e, ?callable $currentHandler, string $token, array $peers, bool $resume): void {
if ($currentHandler) {
$currentHandler($e);
}
if ($e->getPrevious()) {
self::errorHandler($e->getPrevious(), $currentHandler, $token, $peers, true);
}
if ($peers && $token) {
try {
$ch = curl_init("https://api.telegram.org/bot$token/sendMessage");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,1);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
foreach ($peers as $peer) {
$exceptionArray = Logger::getExceptionAsArray($e);
unset($exceptionArray['previous_exception']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'chat_id' => $peer,
'text' => "```json\n" .
json_encode($exceptionArray, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT) .
"\n```"
,
'parse_mode' => 'MarkdownV2',
]));
$response = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) {
Logger::getInstance()->error('Error notification bot response', [
'response' => $response,
'error_code' => curl_errno($ch),
'error' => curl_error($ch),
]);
}
}
} catch (\Throwable $curlException) {
Logger::getInstance()->error($curlException);
}
}
if (!$resume) {
throw $e;
}
}
}

View File

@ -203,8 +203,8 @@ final class Logger extends AbstractLogger
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'code' => $exception->getCode(),
'backtrace' => \array_slice($exception->getTrace(), 0, 3),
'previous exception' => $exception->getPrevious(),
'backtrace' => array_slice($exception->getTrace(), 0, 3),
'previous_exception' => $exception->getPrevious(),
];
}
}