hospital-applets-api/app/Amqp/Consumer/SendSubMessageConsumer.php

332 lines
13 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
declare(strict_types=1);
namespace App\Amqp\Consumer;
use App\Amqp\Producer\SendSmsMessageProducer;
use App\Constants\HttpEnumCode;
use App\Exception\BusinessException;
use App\Model\LogMessagePush;
use App\Model\SubTemplate;
use App\Model\User;
use App\Model\UserDoctor;
use App\Model\UserPatient;
use App\Services\UserService;
use App\Utils\Log;
use Extend\Wechat\Wechat;
use Hyperf\Amqp\Producer;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use Hyperf\DbConnection\Db;
use PhpAmqpLib\Message\AMQPMessage;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* 订阅消息推送
* 每条消息都需携带发送短信参数,用户可能拒绝接受订阅消息
*/
#[Consumer(exchange: 'amqp.direct', routingKey: 'SendSubMessage', queue: 'send.sub.message.queue', nums: 1)]
class SendSubMessageConsumer extends ConsumerMessage
{
/**
* @param $data
* @param AMQPMessage $message
* @return string
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function consumeMessage($data, AMQPMessage $message): string
{
Log::getInstance()->info("开始执行 订阅消息推送 队列:" . json_encode($data, JSON_UNESCAPED_UNICODE));
// 获取被推送用户信息
$params = array();
$params['user_id'] = $data['sub_data']['push_user_id'];
$user = User::getOne($params);
if (empty($user)){
Log::getInstance()->error("订阅消息推送执行失败:未查询到被推送用户信息");
return Result::ACK;
}
try {
// 验证发送参数
if (empty($data['sub_data']['params']['data'])){
Log::getInstance()->error("订阅消息推送执行失败:无推送数据");
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"无推送数据");
return Result::DROP;
}
// 处理发送参数
$send_data = array();
foreach ($data['sub_data']['params']['data'] as $key => $item){
$send_data[$key] = [
"value" => $item
];
}
if (empty($send_data)){
Log::getInstance()->error("订阅消息推送执行失败:发送参数处理失败");
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"发送参数处理失败");
return Result::DROP;
}
Log::getInstance()->info("订阅消息推送数据记录:" . json_encode($send_data,JSON_UNESCAPED_UNICODE));
// 获取open_id
$UserService = new UserService();
$open_id = $UserService->getOpenIdWithUserId($user['user_id'],$user['user_type']);
if (empty($open_id)){
Log::getInstance()->error("订阅消息推送执行失败未获取到被推送用户open_id");
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"未获取到被推送用户open_id");
// 执行发送短信步骤
$this->addSendSmsMessageQueue($data['sms_data']);
return Result::ACK;
}
// 处理发送环境
// $miniprogram_state = "developer";
$miniprogram_state = "trial";
if (env("APP_ENV") == "prod"){
$miniprogram_state = "formal";
}
$options = [
"template_id" => $data['sub_data']['wx_template_id'],
"page" => $data['sub_data']['params']['page'] ?: "",
"touser" => $open_id,
"data" => $send_data,
"miniprogram_state" => $miniprogram_state,
"lang" => "zh_CN",
];
// 发起推送
$Wechat = new Wechat($user['user_type']);
$result = $Wechat->sendSubscribeMessage($options);
if (empty($result)){
Log::getInstance()->error("订阅消息推送执行失败:推送失败");
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"推送失败");
}
if (!isset($result['errcode'])){
Log::getInstance()->error("订阅消息推送执行失败:推送失败,返回值错误" . json_encode($result,JSON_UNESCAPED_UNICODE));
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"推送失败,返回值错误");
}
if ($result['errcode'] == 43101){
Log::getInstance()->error("订阅消息推送执行失败:用户拒绝接收消息");
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],"用户拒绝接收消息");
// 执行发送短信步骤
$this->addSendSmsMessageQueue($data['sms_data']);
return Result::ACK;
}
Log::getInstance()->info("订阅消息推送执行成功");
$this->saveSuccessPushLog($user['user_type'],$data['sub_data']);
} catch (\Exception $e) {
Log::getInstance()->error("订阅消息推送执行失败:" . $e->getMessage());
$this->saveErrorPushLog($user['user_type'],$data['sub_data'],$e->getMessage());
}
return Result::ACK;
}
/**
* 记录成功日志
* @param string|int $user_type 用户类型
* @param array $sub_data 需发送的订阅消息数据
* @return void
*/
private function saveSuccessPushLog(string|int $user_type,array $sub_data): void
{
$data = array();
$data['to_user_id'] = $sub_data['push_user_id'];
$data['user_type'] = $user_type;
$data['type'] = 2;
$data['status'] = 1;
$data['content'] = json_encode($sub_data['params'],JSON_UNESCAPED_UNICODE);
$log_message_push = LogMessagePush::addLogMessagePush($data);
if (empty($log_message_push)){
Log::getInstance()->error("订阅消息推送成功,增加推送日志失败:" . json_encode($data,JSON_UNESCAPED_UNICODE));
}
}
/**
* 记录成功日志
* @param string|int $user_type 用户类型
* @param array $sub_data 需发送的订阅消息数据
* @param string $fail_reason 失败原因
* @return void
*/
private function saveErrorPushLog(string|int $user_type,array $sub_data,string $fail_reason): void
{
$data = array();
$data['to_user_id'] = $sub_data['push_user_id'];
$data['user_type'] = $user_type;
$data['type'] = 2;
$data['status'] = 2;
$data['fail_reason'] = $fail_reason ?: "";
$data['content'] = json_encode($sub_data['params'],JSON_UNESCAPED_UNICODE);
$log_message_push = LogMessagePush::addLogMessagePush($data);
if (empty($log_message_push)){
Log::getInstance()->error("订阅消息推送成功,增加推送日志失败:" . json_encode($data,JSON_UNESCAPED_UNICODE));
}
}
/**
* 添加短信队列
* 接收所有异常
* 只返回true失败情况不处理
* @param array $sms_data 短信发送参数
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function addSendSmsMessageQueue(array $sms_data): void
{
try {
if (empty($sms_data)){
// 无需发送短信
Log::getInstance()->info("无数据需添加短信推送队列");
return;
}
Log::getInstance()->info("添加短信推送队列");
// 增加至发送短信队列
$message = new SendSmsMessageProducer($sms_data);
$producer = $this->container->get(Producer::class);
$res = $producer->produce($message);
if (!$res) {
Log::getInstance()->error("添加短信推送队列失败" . json_encode($sms_data,JSON_UNESCAPED_UNICODE));
}
} catch (\Exception $e) {
Log::getInstance()->error("添加短信推送队列失败" . $e->getMessage());
}
Log::getInstance()->info("添加短信推送队列成功");
}
/**
* 获取数据库订阅消息模版
* 接收所有异常
* 异常记录log不进行处理
* @param string|int $user_type 用户类型
* @param string $template_title 模版名称
* @return array
* @throws ClientExceptionInterface
* @throws ContainerExceptionInterface
* @throws DecodingExceptionInterface
* @throws NotFoundExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function getSubTemplate(string|int $user_type, string $template_title): array
{
try {
Log::getInstance()->info("获取数据库消息订阅模版");
// 获取订阅消息模版数据
$params = array();
$params['client_type'] = $user_type; // 客户端类型1:患者端 2:医师端 3:药师端)
$params['template_title'] = $template_title;
$sub_template = SubTemplate::getOne($params);
if (empty($sub_template)){
// 下载消息模版数据
Log::getInstance()->info("消息模版:" . $template_title . " 在数据库中为空");
$this->downSubTemplate($user_type);
// 重新获取订阅消息模版
$params = array();
$params['client_type'] = $user_type; // 客户端类型1:患者端 2:医师端 3:药师端)
$params['template_title'] = $template_title;
$sub_template = SubTemplate::getOne($params);
}
} catch (\Exception $e) {
Log::getInstance()->error("获取数据库消息订阅模版失败:" . $e->getMessage());
}
if (empty($sub_template)){
return [];
}else{
return $sub_template->toArray();
}
}
/**
* 下载消息订阅模版
* 接收所有异常
* 只返回true失败情况不处理
* @param string|int $user_type
* @return void
* @throws ClientExceptionInterface
* @throws ContainerExceptionInterface
* @throws DecodingExceptionInterface
* @throws NotFoundExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
private function downSubTemplate(string|int $user_type): void
{
try {
Log::getInstance()->info("下载微信消息订阅模版");
$weChat = new Wechat($user_type);
$result = $weChat->getTemplate();
if (empty($result)){
return;
}
$template = json_decode($result, true);
foreach ($template['data'] as $item) {
$params = array();
$params['wx_template_id'] = $item['priTmplId'];
$sub_template = SubTemplate::getOne($params);
if (empty($sub_template)) {
// 新增模版
$data = array();
$data['client_type'] = 1;
$data['wx_template_id'] = $item['priTmplId'];
$data['template_title'] = $item['title'];
$data['template_type'] = $item['type'];
$data['template_content'] = $item['content'];
$sub_template = SubTemplate::addSubTemplate($data);
if (empty($sub_template)) {
// 此处添加失败不做处理记录log
Log::getInstance()->error("下载微信消息订阅模版失败:" . json_encode($data,JSON_UNESCAPED_UNICODE));
}
}
}
} catch (\Exception $e) {
Log::getInstance()->error("下载微信消息订阅模版失败:" . $e->getMessage());
}
Log::getInstance()->info("下载微信消息订阅模版成功");
}
}