Files
coruna-lab/app/Http/Controllers/Hooks/TelegramWebhookController.php
T
hashbro 6489808fa5 admin
2026-08-09 02:42:28 +08:00

93 lines
3.3 KiB
PHP

<?php
namespace App\Http\Controllers\Hooks;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use SergiX44\Nutgram\Nutgram;
use Throwable;
class TelegramWebhookController extends Controller
{
public function __invoke(Request $request): Response
{
// Log before resolving Nutgram — DI failures previously 500'd with no controller log.
$raw = $request->getContent();
$update = $request->all();
if ($update === [] && is_string($raw) && $raw !== '') {
$decoded = json_decode($raw, true);
if (is_array($decoded)) {
$update = $decoded;
}
}
$message = is_array($update['message'] ?? null) ? $update['message'] : [];
$chatId = $message['chat']['id'] ?? ($update['callback_query']['message']['chat']['id'] ?? null);
$text = is_string($message['text'] ?? null) ? $message['text'] : null;
$updateId = $update['update_id'] ?? null;
$secret = (string) config('coruna.telegram.webhook_secret', '');
$header = (string) $request->header('X-Telegram-Bot-Api-Secret-Token', '');
$this->webhookLog('info', 'telegram webhook hit', [
'ip' => $request->ip(),
'update_id' => $updateId,
'chat_id' => $chatId,
'text' => $text,
'has_secret_header' => $header !== '',
'secret_configured' => $secret !== '',
'body_bytes' => strlen($raw),
]);
if ($secret !== '') {
if ($header === '' || ! hash_equals($secret, $header)) {
$this->webhookLog('warning', 'telegram webhook rejected: bad secret', [
'ip' => $request->ip(),
'update_id' => $updateId,
]);
abort(403, 'Invalid webhook secret');
}
}
try {
/** @var Nutgram $bot */
$bot = app(Nutgram::class);
$bot->run();
$this->webhookLog('info', 'telegram webhook handled', [
'update_id' => $updateId,
'chat_id' => $chatId,
'handler' => $bot->currentHandler()?->getPattern(),
]);
} catch (Throwable $e) {
// Always ACK to Telegram — returning 500 causes pending_update backlog.
$this->webhookLog('error', 'telegram webhook failed', [
'message' => $e->getMessage(),
'exception' => $e::class,
'file' => $e->getFile().':'.$e->getLine(),
'update_id' => $updateId,
'chat_id' => $chatId,
'trace' => collect(explode("\n", $e->getTraceAsString()))->take(12)->all(),
]);
if (app()->runningUnitTests() && $e instanceof \InvalidArgumentException) {
// FakeNutgram with no queued update in unit tests.
return response()->noContent();
}
}
return response()->noContent();
}
/** @param array<string, mixed> $context */
private function webhookLog(string $level, string $message, array $context = []): void
{
try {
Log::{$level}($message, $context);
} catch (Throwable) {
error_log($message.' '.json_encode($context, JSON_UNESCAPED_UNICODE));
}
}
}