49 lines
2.5 KiB
PHP
49 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
namespace App\Services\Freenode;
|
|
|
|
use App\Models\CrawlFreenode;
|
|
use App\Models\SiteMap;
|
|
use RuntimeException;
|
|
|
|
final class Pipeline
|
|
{
|
|
public static function enabled(): bool { return config('freenode.engine', 'legacy') === 'v2'; }
|
|
|
|
public static function store(): ReleaseStore
|
|
{
|
|
return new ReleaseStore(storage_path('app/freenode-v2'), public_path('freenode/merge'));
|
|
}
|
|
|
|
public static function prepare(): array
|
|
{
|
|
$sources = [];
|
|
$cycle = strtotime(date('Y-m-d').' '.sprintf('%02d', intdiv((int) date('H'), 6) * 6).':00:00');
|
|
foreach (CrawlFreenode::where('status', 1)->get() as $source) {
|
|
if (!preg_match('/^[a-zA-Z0-9_-]+$/D', $source->name)) throw new RuntimeException('invalid_source_name');
|
|
$row = ['name' => $source->name];
|
|
foreach (json_decode($source->file_real ?? '[]', true, 512, JSON_THROW_ON_ERROR) as $format => $file) {
|
|
if (!in_array($format, ['v2ray', 'clash'], true)) continue;
|
|
if (!preg_match('/^'.date('Ymd').'-(v2ray\.txt|clash\.yaml)$/D', $file)) throw new RuntimeException('stale_source_date:'.$source->name);
|
|
$path = public_path('freenode/from/'.$source->name.'/'.$file);
|
|
if (!is_file($path) || filemtime($path) < $cycle) throw new RuntimeException('stale_source_cycle:'.$source->name);
|
|
$row[$format] = file_get_contents($path);
|
|
}
|
|
if (!isset($row['v2ray'], $row['clash'])) throw new RuntimeException('incomplete_source:'.$source->name);
|
|
$sources[] = $row;
|
|
}
|
|
$sites = [];
|
|
foreach (SiteMap::whereIn('group_code', ['fn_a', 'fn_b'])->where('status', 1)->get() as $site) {
|
|
$config = json_decode($site->config ?? '[]', true, 512, JSON_THROW_ON_ERROR);
|
|
$sites[] = ['code' => $site->code, 'clients' => $config['freenode_client'] ?? []];
|
|
}
|
|
if (!$sources || !$sites) throw new RuntimeException('no_enabled_sources_or_sites');
|
|
$sites[] = ['code' => '_admin', 'clients' => ['v2ray', 'clash', 'singbox']];
|
|
$clashTemplate = \Symfony\Component\Yaml\Yaml::parseFile(public_path('freenode/template/clash.txt'));
|
|
$validator = new NativeValidator(config('freenode.singbox_binary'), config('freenode.mihomo_binary'), $clashTemplate);
|
|
$result = (new Builder())->build($sources, $sites, $validator);
|
|
return self::store()->stage($result, date('Y-m-d'), (float) config('freenode.minimum_ratio', 0.5));
|
|
}
|
|
}
|