restore bootstrap and seo helper chain after rebase drop
This commit is contained in:
304
code/app/api/controller/SeoCollector.php
Normal file
304
code/app/api/controller/SeoCollector.php
Normal file
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\api\BaseController;
|
||||
use app\common\helper\DomainExternalSeoSnapshotHelper;
|
||||
use app\common\helper\DomainExternalSeoSnapshotSchemaHelper;
|
||||
use app\common\helper\DomainExternalSeoSnapshotRunHelper;
|
||||
use app\common\helper\DomainExternalSeoSnapshotTrendHelper;
|
||||
use app\common\helper\DomainExternalSeoCnOverviewHelper;
|
||||
use app\common\helper\DomainExternalSeoSnapshotValidateRunHelper;
|
||||
use app\common\helper\DomainSpiderCrawlLogHelper;
|
||||
use app\common\helper\DomainSpiderCrawlLogRunHelper;
|
||||
use app\common\helper\DomainSpiderCrawlLogSchemaHelper;
|
||||
use think\Request;
|
||||
|
||||
class SeoCollector extends BaseController
|
||||
{
|
||||
protected function codeRoot(): string
|
||||
{
|
||||
return dirname(__DIR__, 3);
|
||||
}
|
||||
|
||||
protected function publicRoot(): string
|
||||
{
|
||||
return $this->codeRoot() . '/public';
|
||||
}
|
||||
|
||||
protected function storageRoot(): string
|
||||
{
|
||||
return $this->codeRoot() . '/storage';
|
||||
}
|
||||
|
||||
protected function summaryRoot(): string
|
||||
{
|
||||
return $this->publicRoot() . '/_admin_templates/domain-seo-external/latest';
|
||||
}
|
||||
|
||||
protected function snapshotRunRoot(): string
|
||||
{
|
||||
return $this->publicRoot() . '/_admin_templates/domain-seo-external/snapshot-runs';
|
||||
}
|
||||
|
||||
protected function snapshotValidateRunRoot(): string
|
||||
{
|
||||
return $this->publicRoot() . '/_admin_templates/domain-seo-external/snapshot-validate-runs';
|
||||
}
|
||||
|
||||
protected function spiderCrawlLatestRoot(): string
|
||||
{
|
||||
return $this->storageRoot() . '/domain-spider-crawl/latest';
|
||||
}
|
||||
|
||||
protected function spiderCrawlRunRoot(): string
|
||||
{
|
||||
return $this->storageRoot() . '/domain-spider-crawl/runs';
|
||||
}
|
||||
|
||||
protected function publicRelativePath(string $path): string
|
||||
{
|
||||
$publicRoot = str_replace('\\', '/', rtrim($this->publicRoot(), '/'));
|
||||
$path = str_replace('\\', '/', $path);
|
||||
if (str_starts_with($path, $publicRoot . '/')) {
|
||||
return substr($path, strlen($publicRoot . '/'));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function storageRelativePath(string $path): string
|
||||
{
|
||||
$storageRoot = str_replace('\\', '/', rtrim($this->storageRoot(), '/'));
|
||||
$path = str_replace('\\', '/', $path);
|
||||
if (str_starts_with($path, $storageRoot . '/')) {
|
||||
return substr($path, strlen($storageRoot . '/'));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function success(array $data = [])
|
||||
{
|
||||
return json([
|
||||
'code' => '1000',
|
||||
'msg' => '成功',
|
||||
'data' => $data,
|
||||
], 200, [], [JSON_UNESCAPED_UNICODE]);
|
||||
}
|
||||
|
||||
protected function error(string $code, string $msg)
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'data' => [],
|
||||
], 200, [], [JSON_UNESCAPED_UNICODE]);
|
||||
}
|
||||
|
||||
public function collectHosts(Request $request)
|
||||
{
|
||||
try {
|
||||
$limit = max(1, min(5000, (int)$request->get('limit', 1000)));
|
||||
$includeWildcard = (int)$request->get('include_wildcard', 0) === 1;
|
||||
return $this->success(DomainExternalSeoSnapshotHelper::buildCollectHosts($limit, $includeWildcard));
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '读取站外采集域名列表失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function snapshotSchema()
|
||||
{
|
||||
try {
|
||||
return $this->success(DomainExternalSeoSnapshotSchemaHelper::buildSchema());
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '读取站外 SEO 快照字段规则失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function snapshotChecklist()
|
||||
{
|
||||
try {
|
||||
return $this->success(DomainExternalSeoSnapshotSchemaHelper::buildChecklist());
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '读取站外 SEO 快照字段校验清单失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function validateSnapshots(Request $request)
|
||||
{
|
||||
try {
|
||||
$snapshots = $this->resolveSnapshots($request);
|
||||
if (empty($snapshots)) {
|
||||
return $this->error('9999', '请提交 snapshots');
|
||||
}
|
||||
|
||||
$result = DomainExternalSeoSnapshotSchemaHelper::validateSnapshots((array)$snapshots);
|
||||
$runRoot = DomainExternalSeoSnapshotValidateRunHelper::createRunRoot($this->snapshotValidateRunRoot(), 'snapshot_validate');
|
||||
$result = DomainExternalSeoSnapshotValidateRunHelper::writeRunArtifacts(
|
||||
$this->publicRoot(),
|
||||
$runRoot,
|
||||
$result,
|
||||
(array)$snapshots
|
||||
);
|
||||
$result['run_root'] = $this->publicRelativePath($runRoot);
|
||||
$result['summary_json_path'] = $this->publicRelativePath((string)($result['summary_json_path'] ?? ''));
|
||||
$result['summary_html_path'] = $this->publicRelativePath((string)($result['summary_html_path'] ?? ''));
|
||||
$result['payload_json_path'] = $this->publicRelativePath((string)($result['payload_json_path'] ?? ''));
|
||||
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '校验站外 SEO 快照失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function saveSnapshots(Request $request)
|
||||
{
|
||||
try {
|
||||
$snapshots = $this->resolveSnapshots($request);
|
||||
if (empty($snapshots)) {
|
||||
return $this->error('9999', '请提交 snapshots');
|
||||
}
|
||||
|
||||
$source = trim((string)$request->post('source', 'push_api'));
|
||||
$result = DomainExternalSeoSnapshotHelper::ingestSnapshots((array)$snapshots, $source);
|
||||
$runRoot = DomainExternalSeoSnapshotRunHelper::createRunRoot($this->snapshotRunRoot(), 'snapshot_push');
|
||||
$result = DomainExternalSeoSnapshotRunHelper::writeRunArtifacts(
|
||||
$this->publicRoot(),
|
||||
$runRoot,
|
||||
$result,
|
||||
(array)$snapshots
|
||||
);
|
||||
$result['run_root'] = $this->publicRelativePath($runRoot);
|
||||
$result['summary_json_path'] = $this->publicRelativePath((string)($result['summary_json_path'] ?? ''));
|
||||
$result['summary_html_path'] = $this->publicRelativePath((string)($result['summary_html_path'] ?? ''));
|
||||
$result['payload_json_path'] = $this->publicRelativePath((string)($result['payload_json_path'] ?? ''));
|
||||
|
||||
$overview = DomainExternalSeoCnOverviewHelper::buildOverview(14, 10);
|
||||
$overview = DomainExternalSeoCnOverviewHelper::writeArtifacts($this->summaryRoot(), $overview);
|
||||
$overview['summary_json_path'] = $this->publicRelativePath((string)($overview['summary_json_path'] ?? ''));
|
||||
$overview['summary_html_path'] = $this->publicRelativePath((string)($overview['summary_html_path'] ?? ''));
|
||||
|
||||
$snapshotTrend = DomainExternalSeoSnapshotTrendHelper::buildSummary($this->snapshotRunRoot(), 10);
|
||||
$snapshotTrend = DomainExternalSeoSnapshotTrendHelper::writeArtifacts($this->summaryRoot(), $snapshotTrend);
|
||||
$snapshotTrend['summary_json_path'] = $this->publicRelativePath((string)($snapshotTrend['summary_json_path'] ?? ''));
|
||||
$snapshotTrend['summary_html_path'] = $this->publicRelativePath((string)($snapshotTrend['summary_html_path'] ?? ''));
|
||||
|
||||
$result['post_ingest_overview'] = $overview;
|
||||
$result['post_ingest_snapshot_trend'] = $snapshotTrend;
|
||||
$result = DomainExternalSeoSnapshotRunHelper::writeRunArtifacts(
|
||||
$this->publicRoot(),
|
||||
$runRoot,
|
||||
$result,
|
||||
(array)$snapshots
|
||||
);
|
||||
$result['summary_json_path'] = $this->publicRelativePath((string)($result['summary_json_path'] ?? ''));
|
||||
$result['summary_html_path'] = $this->publicRelativePath((string)($result['summary_html_path'] ?? ''));
|
||||
$result['payload_json_path'] = $this->publicRelativePath((string)($result['payload_json_path'] ?? ''));
|
||||
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '保存站外 SEO 快照失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function crawlLogSchema()
|
||||
{
|
||||
try {
|
||||
return $this->success(DomainSpiderCrawlLogSchemaHelper::buildSchema());
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '读取蜘蛛抓取日志字段规则失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function crawlLogChecklist()
|
||||
{
|
||||
try {
|
||||
return $this->success(DomainSpiderCrawlLogSchemaHelper::buildChecklist());
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '读取蜘蛛抓取日志校验清单失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function validateCrawlLogs(Request $request)
|
||||
{
|
||||
try {
|
||||
$payload = $this->resolveCrawlLogPayload($request);
|
||||
$result = DomainSpiderCrawlLogSchemaHelper::validatePayload($payload);
|
||||
$runRoot = DomainSpiderCrawlLogRunHelper::createRunRoot($this->spiderCrawlRunRoot(), 'crawl_log_validate');
|
||||
$result = DomainSpiderCrawlLogRunHelper::writeRunArtifacts($this->storageRoot(), $runRoot, $result, $payload);
|
||||
$result['run_root'] = $this->storageRelativePath($runRoot);
|
||||
$result['summary_json_path'] = $this->storageRelativePath((string)($result['summary_json_path'] ?? ''));
|
||||
$result['summary_html_path'] = $this->storageRelativePath((string)($result['summary_html_path'] ?? ''));
|
||||
$result['payload_json_path'] = $this->storageRelativePath((string)($result['payload_json_path'] ?? ''));
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '校验蜘蛛抓取日志失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function saveCrawlLogs(Request $request)
|
||||
{
|
||||
try {
|
||||
$payload = $this->resolveCrawlLogPayload($request);
|
||||
$source = trim((string)($payload['source'] ?? $request->post('source', 'frontend_nginx_push')));
|
||||
$result = DomainSpiderCrawlLogHelper::ingestPayload($payload, $source);
|
||||
$runRoot = DomainSpiderCrawlLogRunHelper::createRunRoot($this->spiderCrawlRunRoot(), 'crawl_log_push');
|
||||
$result = DomainSpiderCrawlLogRunHelper::writeRunArtifacts($this->storageRoot(), $runRoot, $result, $payload);
|
||||
$latest = DomainSpiderCrawlLogHelper::writeLatestArtifacts($this->spiderCrawlLatestRoot(), $result);
|
||||
|
||||
$result['run_root'] = $this->storageRelativePath($runRoot);
|
||||
$result['summary_json_path'] = $this->storageRelativePath((string)($result['summary_json_path'] ?? ''));
|
||||
$result['summary_html_path'] = $this->storageRelativePath((string)($result['summary_html_path'] ?? ''));
|
||||
$result['payload_json_path'] = $this->storageRelativePath((string)($result['payload_json_path'] ?? ''));
|
||||
$result['latest_summary_json_path'] = $this->storageRelativePath((string)($latest['summary_json_path'] ?? ''));
|
||||
$result['latest_summary_html_path'] = $this->storageRelativePath((string)($latest['summary_html_path'] ?? ''));
|
||||
|
||||
return $this->success($result);
|
||||
} catch (\Throwable $throwable) {
|
||||
return $this->error('9999', '保存蜘蛛抓取日志失败:' . $throwable->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected function resolveSnapshots(Request $request): array
|
||||
{
|
||||
$snapshots = $request->post('snapshots/a', []);
|
||||
if (empty($snapshots)) {
|
||||
$snapshotsJson = trim((string)$request->post('snapshots_json', ''));
|
||||
if ($snapshotsJson !== '') {
|
||||
$decoded = json_decode($snapshotsJson, true);
|
||||
$snapshots = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
}
|
||||
if (empty($snapshots) && $request->getContent()) {
|
||||
$decoded = json_decode((string)$request->getContent(), true);
|
||||
if (is_array($decoded)) {
|
||||
$snapshots = (array)($decoded['snapshots'] ?? $decoded);
|
||||
}
|
||||
}
|
||||
|
||||
return (array)$snapshots;
|
||||
}
|
||||
|
||||
protected function resolveCrawlLogPayload(Request $request): array
|
||||
{
|
||||
$arrPayload = [
|
||||
'source' => trim((string)$request->post('source', 'frontend_nginx_push')),
|
||||
'summary_records' => $request->post('summary_records/a', []),
|
||||
'anomaly_records' => $request->post('anomaly_records/a', []),
|
||||
];
|
||||
|
||||
if ((!empty($arrPayload['summary_records']) || !empty($arrPayload['anomaly_records'])) === false && $request->getContent()) {
|
||||
$arrDecoded = json_decode((string)$request->getContent(), true);
|
||||
if (is_array($arrDecoded)) {
|
||||
$arrPayload['source'] = trim((string)($arrDecoded['source'] ?? $arrPayload['source']));
|
||||
$arrPayload['summary_records'] = array_values((array)($arrDecoded['summary_records'] ?? []));
|
||||
$arrPayload['anomaly_records'] = array_values((array)($arrDecoded['anomaly_records'] ?? []));
|
||||
}
|
||||
}
|
||||
|
||||
return $arrPayload;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user