Files
journal/application/master/service/DbPushManager.php

203 lines
7.0 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
namespace app\master\service;
use think\Db;
use think\Queue;
use app\master\service\push\PushResult;
use app\master\service\push\PorticoPusher;
use app\master\service\push\ScopusPusher;
use app\master\service\push\EbscoPusher;
use app\master\service\push\CnkiPusher;
use app\master\service\push\EmailDataPusher;
/**
* 数据库收录推送编排器
* 职责:根据分期解析应推送的渠道 -> 逐个执行(或入队) -> 写推送日志。
*/
class DbPushManager
{
/** 推送器标识 => 实现类 */
protected static $registry = [
'portico' => PorticoPusher::class,
'scopus' => ScopusPusher::class,
'ebsco' => EbscoPusher::class,
'cnki' => CnkiPusher::class,
'email_data' => EmailDataPusher::class,
];
/** @var DbPushLogger */
protected $logger;
public function __construct()
{
$this->logger = new DbPushLogger();
}
/**
* 实例化推送器
* @return \app\master\service\push\PusherInterface|null
*/
public static function makePusher($code)
{
if (!isset(self::$registry[$code])) {
return null;
}
$class = self::$registry[$code];
return new $class();
}
/**
* 解析某期刊应推送的渠道列表(配置驱动,数据表优先,回退默认配置)
* @return array 每项 [channel_key, name, pusher, options]
*/
public function resolveChannels($journalId)
{
try {
$rows = Db::name('db_channel')->where('state', 0)->where('is_enable', 1)->order('sort desc')->select();
} catch (\Throwable $e) {
// 渠道表尚未创建时回退到默认配置
$rows = [];
}
$channels = [];
if (!empty($rows)) {
foreach ($rows as $r) {
$journalIds = trim($r['journal_ids']) === '' ? [] : array_map('intval', explode(',', $r['journal_ids']));
$options = empty($r['config']) ? [] : (json_decode($r['config'], true) ?: []);
$channels[] = [
'channel_key' => $r['channel_key'],
'name' => $r['name'],
'pusher' => $r['pusher'] !== '' ? $r['pusher'] : $r['channel_key'],
'journal_ids' => $journalIds,
'options' => $options,
];
}
} else {
foreach ((array) config('dbpush.default_channels') as $c) {
if (empty($c['is_enable'])) {
continue;
}
$channels[] = [
'channel_key' => $c['channel_key'],
'name' => $c['name'],
'pusher' => !empty($c['pusher']) ? $c['pusher'] : $c['channel_key'],
'journal_ids' => isset($c['journal_ids']) ? $c['journal_ids'] : [],
'options' => isset($c['config']) ? $c['config'] : [],
];
}
}
// 按期刊过滤journal_ids 为空表示全部
$result = [];
foreach ($channels as $c) {
if (empty($c['journal_ids']) || in_array((int) $journalId, $c['journal_ids'])) {
$result[] = $c;
}
}
return $result;
}
/**
* 推送整期到所有匹配渠道
* @param int $stageId
* @param string $operator 触发人
* @param bool|null $async 是否异步null 用配置默认
* @return array 各渠道执行概况
*/
public function run($stageId, $operator = '', $async = null)
{
if ($async === null) {
$async = (bool) config('dbpush.async');
}
$stage_info = Db::name('journal_stage')->where('journal_stage_id', $stageId)->find();
if (!$stage_info) {
return [];
}
$journalId = $stage_info['journal_id'];
$channels = $this->resolveChannels($journalId);
$summary = [];
foreach ($channels as $c) {
$logId = $this->logger->create($journalId, $stageId, $c['channel_key'], $c['name'], $operator);
if ($async) {
Queue::push('app\api\job\dbpush@handle', [
'log_id' => $logId,
'stage_id' => $stageId,
'pusher' => $c['pusher'],
'options' => $c['options'],
], 'dbpush');
$summary[] = ['channel' => $c['channel_key'], 'log_id' => $logId, 'queued' => true];
} else {
$ok = $this->executeAndLog($logId, $stageId, $c['pusher'], $c['options']);
$summary[] = ['channel' => $c['channel_key'], 'log_id' => $logId, 'ok' => $ok];
}
}
return $summary;
}
/**
* 执行单个推送器并写入日志结果(供同步执行 / 队列任务调用)
* @return bool 是否成功
*/
public function executeAndLog($logId, $stageId, $pusherCode, array $options = [])
{
try {
$pusher = self::makePusher($pusherCode);
if (!$pusher) {
$this->logger->finish($logId, false, '未知的推送器: ' . $pusherCode);
return false;
}
$result = $pusher->pushStage($stageId, $options);
if (!$result instanceof PushResult) {
$result = PushResult::success();
}
$this->logger->finish($logId, $result->ok, $result->message);
return $result->ok;
} catch (\Throwable $e) {
$this->logger->finish($logId, false, $e->getMessage());
return false;
}
}
/**
* 重推某条日志
* @return array [ok=>bool, queued=>bool]
*/
public function retry($logId, $async = null)
{
if ($async === null) {
$async = (bool) config('dbpush.async');
}
$log = $this->logger->find($logId);
if (!$log) {
return ['ok' => false, 'queued' => false, 'msg' => '日志不存在'];
}
// 依据日志里的渠道标识重新解析推送器与配置
$channels = $this->resolveChannels($log['journal_id']);
$pusher = $log['channel'];
$options = [];
foreach ($channels as $c) {
if ($c['channel_key'] === $log['channel']) {
$pusher = $c['pusher'];
$options = $c['options'];
break;
}
}
// 重置为待推送
Db::name('db_push_log')->where('log_id', $logId)->update(['status' => DbPushLogger::STATUS_PENDING, 'utime' => time()]);
if ($async) {
Queue::push('app\api\job\dbpush@handle', [
'log_id' => $logId,
'stage_id' => $log['journal_stage_id'],
'pusher' => $pusher,
'options' => $options,
], 'dbpush');
return ['ok' => true, 'queued' => true];
}
$ok = $this->executeAndLog($logId, $log['journal_stage_id'], $pusher, $options);
return ['ok' => $ok, 'queued' => false];
}
}