Files
coruna-lab/routes/console.php
T
2026-08-26 03:14:15 +08:00

214 lines
6.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use App\Services\ChannelProjectService;
use App\Services\Tokenview\TokenviewClient;
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Schedule;
Schedule::command('coruna:auto-transfer')
->everyMinute()
->withoutOverlapping()
->runInBackground();
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
Artisan::command('tokenview:set-webhook {url?}', function (?string $url = null) {
/** @var TokenviewClient $client */
$client = app(TokenviewClient::class);
if (! $client->enabled()) {
$this->error('TOKENVIEW_API_KEY is empty');
return 1;
}
$url = $url ?: rtrim((string) config('app.url'), '/').'/hooks/tokenview';
$this->info('Setting webhook URL: '.$url);
if ($client->setWebhookUrl($url)) {
$this->info('OK');
return 0;
}
$this->error('Failed — check Tokenview API response / credentials');
return 1;
})->purpose('Register Tokenview address-tracking webhook URL');
Artisan::command('telegram:set-webhook {url?}', function (?string $url = null) {
$token = (string) config('nutgram.token', '');
if ($token === '') {
$this->error('TELEGRAM_BOT_TOKEN is empty');
return 1;
}
$url = $url ?: rtrim((string) config('app.url'), '/').'/hooks/telegram';
$secret = (string) config('coruna.telegram.webhook_secret', '');
$payload = [
'url' => $url,
'allowed_updates' => ['message', 'callback_query', 'my_chat_member'],
];
if ($secret !== '') {
$payload['secret_token'] = $secret;
}
$this->info('Setting Telegram webhook URL: '.$url);
$resp = Http::timeout(20)
->asJson()
->post("https://api.telegram.org/bot{$token}/setWebhook", $payload);
if ($resp->successful() && ($resp->json('ok') === true)) {
$this->info('OK');
return 0;
}
$this->error('Failed: '.$resp->body());
return 1;
})->purpose('Register the site Telegram webhook');
Artisan::command('xxbb:build {--channel-c=} {--random-c}', function () {
$channelC = trim((string) $this->option('channel-c'));
$random = (bool) $this->option('random-c');
try {
$result = app(ChannelProjectService::class)->buildSharedArtifacts(
$channelC !== '' ? $channelC : null,
$random,
);
} catch (Throwable $e) {
$this->error($e->getMessage());
return 1;
}
$c = (string) data_get($result, 'seeds.channel_c', '');
$this->info('XXBB_CHANNEL_C='.$c);
$this->info('details -> /details/');
$staged = (string) ($result['staged_weifile'] ?? '');
if ($staged !== '') {
$this->info('staged weifile -> '.$staged);
}
$this->line('domains:');
$domains = array_values((array) data_get($result, 'domains.deployment', []));
if ($domains === []) {
$this->warn('(empty)');
}
foreach ($domains as $i => $domain) {
$this->line(sprintf(' %03d %s', $i + 1, $domain));
}
$configured = strtolower(trim((string) config('coruna.xxbb.channel_c', '')));
if ($c !== '' && $configured !== $c) {
$this->warn('把上面的 XXBB_CHANNEL_C 写入 .env;新建渠道会始终用 env 中的 c 构建。');
}
return 0;
})->purpose('Build shared xxbb /details and staged weifile from channel c');
Artisan::command('xxbb:repack {ids?*} {--template=blank} {--skip-shared} {--dry-run}', function () {
$ids = array_values(array_filter(array_map('strval', (array) $this->argument('ids'))));
$template = trim((string) $this->option('template'));
$skipShared = (bool) $this->option('skip-shared');
$dryRun = (bool) $this->option('dry-run');
$projects = app(ChannelProjectService::class);
try {
$resolved = $projects->resolveNewChannelIds($ids === [] ? null : $ids);
} catch (Throwable $e) {
$this->error($e->getMessage());
return 1;
}
if ($resolved === []) {
$this->warn('没有可重打的新版渠道(builder_type=new)');
return 0;
}
$this->info(($dryRun ? '将重打' : '重打').' '.count($resolved).' 个新版渠道(渠道 ID / 投放域名不变):');
foreach ($resolved as $id) {
$this->line(' /channel/'.$id);
}
if ($dryRun) {
return 0;
}
try {
$result = $projects->rebuildNewChannels(
$resolved,
$template !== '' ? $template : ChannelProjectService::DEFAULT_SUPPORT_TEMPLATE,
! $skipShared,
);
} catch (Throwable $e) {
$this->error($e->getMessage());
return 1;
}
if (! $skipShared) {
$c = (string) data_get($result, 'shared.seeds.channel_c', config('coruna.xxbb.channel_c', ''));
$this->info('shared XXBB_CHANNEL_C='.$c);
$this->info('details -> /details/');
}
foreach ($result['channels'] as $row) {
$id = (string) ($row['channel_id'] ?? '');
$landing = (string) ($row['support_path'] ?? '/channel/'.$id.'/weifile/weifile.html');
$this->info('packed '.$id.' -> '.$landing);
}
return 0;
})->purpose('Repack existing new-builder channels with latest weifile / details / plugins');
Artisan::command('ds:build {--host=} {--port=} {--origin=}', function () {
$script = base_path('channel-builder-ds/tools/build.py');
if (! is_file($script)) {
$this->error('missing '.$script);
return 1;
}
$args = ['python3', $script];
$host = trim((string) $this->option('host'));
$port = trim((string) $this->option('port'));
$origin = trim((string) $this->option('origin'));
if ($origin === '' && $host === '') {
$origin = rtrim((string) config('app.url'), '/');
$this->warn('未传 --origin,使用 APP_URL: '.$origin);
$this->warn('线上必须显式指定 C2,例如: php artisan ds:build --origin https://你的域名');
}
if ($origin !== '') {
$args[] = '--origin';
$args[] = $origin;
}
if ($host !== '') {
$args[] = '--host';
$args[] = $host;
}
if ($port !== '') {
$args[] = '--port';
$args[] = $port;
}
$this->info(implode(' ', $args));
passthru(implode(' ', array_map('escapeshellarg', $args)), $code);
return $code;
})->purpose('Rewrite DarkSword source and publish public/next-chain');
Artisan::command('coruna:channel-domains {--json}', function () {
$domains = array_values(array_filter(config('coruna.channel_domains', [])));
if ($this->option('json')) {
$this->line(json_encode($domains, JSON_UNESCAPED_UNICODE));
return 0;
}
if ($domains === []) {
$this->warn('(empty)');
return 0;
}
foreach ($domains as $d) {
$this->line($d);
}
return 0;
})->purpose('Print configured channel delivery domains (settings / env)');