Files
coruna-lab/app/Providers/AppServiceProvider.php
2026-09-29 05:25:55 +08:00

157 lines
5.5 KiB
PHP

<?php
namespace App\Providers;
use App\Services\Alchemy\AlchemyBalanceService;
use App\Services\CorunaArchive;
use App\Services\CorunaCrypto;
use App\Services\Ocr\OcrDriver;
use App\Services\Ocr\TesseractOcrDriver;
use App\Services\SettingsService;
use App\Telegram\TelegramBotContext;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
use Nutgram\Laravel\RunningMode\LaravelWebhook;
use SergiX44\Nutgram\Nutgram;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(TelegramBotContext::class);
$this->app->singleton(CorunaCrypto::class, function () {
$override = config('coruna.session_key');
return new CorunaCrypto(is_string($override) && $override !== '' ? $override : null);
});
$this->app->singleton('xxbb.crypto', function () {
$key = config('coruna.xxbb.session_key', 'Ek8pl31K2yeHgQwy');
return new CorunaCrypto(is_string($key) && $key !== '' ? $key : 'Ek8pl31K2yeHgQwy');
});
$this->app->singleton(CorunaArchive::class, function ($app) {
return new CorunaArchive(
$app->make(CorunaCrypto::class),
(string) config('coruna.seven_zip', ''),
);
});
$this->app->bind(OcrDriver::class, TesseractOcrDriver::class);
$this->app->singleton(AlchemyBalanceService::class, function () {
return AlchemyBalanceService::make();
});
}
public function boot(): void
{
// Floor for outbound calls that don't set their own timeout. Explicit
// Http::timeout() still wins. 120s leaves room for slow uploads;
// connect fails fast enough that a dead host doesn't sit for the full window.
Http::globalOptions([
'connect_timeout' => 20,
'timeout' => 120,
]);
if (! $this->app->runningInConsole()) {
$limit = (int) ini_get('max_execution_time');
if ($limit > 0 && $limit < 60) {
@set_time_limit(60);
}
}
try {
$this->app->make(SettingsService::class)->applyToConfig();
} catch (\Throwable) {
// settings table may not exist yet during migrate
}
if (! $this->app->runningUnitTests()) {
$this->recordLastSql();
}
// Override Nutgram's production safe_mode (md5 APP_KEY) so webhook updates
// are not silently dropped when Telegram secret_token is unset/mismatched.
$this->app->afterResolving(Nutgram::class, function (Nutgram $bot): void {
if ($this->app->runningUnitTests() || $this->app->runningInConsole()) {
return;
}
$secret = (string) config('coruna.telegram.webhook_secret', '');
$webhook = $secret !== ''
? new LaravelWebhook(
getToken: static fn () => request()?->header('X-Telegram-Bot-Api-Secret-Token'),
secretToken: $secret,
)
: new LaravelWebhook;
$webhook->setSafeMode($secret !== '');
$bot->setRunningMode($webhook);
});
}
/**
* Keep the current process's last SQL in memory. On memory-exhaustion
* shutdown, append it to oom-sql.log (shared last-sql.json is useless
* under many FPM workers).
*/
private function recordLastSql(): void
{
$oomPath = storage_path('logs/oom-sql.log');
$snap = (object) ['line' => ''];
DB::beforeExecuting(function (string $query, array $bindings) use ($snap): void {
$uri = 'cli';
try {
if (app()->runningInConsole()) {
$uri = 'cli:'.implode(' ', $_SERVER['argv'] ?? []);
} else {
$req = request();
$uri = $req->method().' '.$req->getRequestUri();
}
} catch (\Throwable) {
}
$snap->line = json_encode([
'at' => date('c'),
'pid' => getmypid(),
'mem' => memory_get_usage(true),
'uri' => $uri,
'sql' => substr($query, 0, 1500),
'bindings' => array_slice($bindings, 0, 8),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '';
});
register_shutdown_function(function () use ($oomPath, $snap): void {
$err = error_get_last();
$msg = (string) ($err['message'] ?? '');
if ($msg === '' || ! str_contains($msg, 'Allowed memory size')) {
return;
}
$line = $snap->line !== '' ? $snap->line : json_encode([
'at' => date('c'),
'pid' => getmypid(),
'mem' => memory_get_usage(true),
'uri' => 'unknown',
'sql' => '',
'error' => substr($msg, 0, 240),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
@file_put_contents($oomPath, $line."\n", FILE_APPEND | LOCK_EX);
});
DB::listen(function ($event): void {
if ($event->time < 800 && memory_get_usage(true) < 80 * 1024 * 1024) {
return;
}
Log::warning('slow_or_heavy_query', [
'ms' => $event->time,
'mem' => memory_get_usage(true),
'sql' => substr((string) $event->sql, 0, 400),
]);
});
}
}