|
@@ -0,0 +1,357 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+
|
|
|
+namespace App\Modules\Push\Services;
|
|
|
+
|
|
|
+
|
|
|
+use App\Cache\PushCache;
|
|
|
+use App\Consts\PushConst;
|
|
|
+use App\Libs\Push\OPPOPush\OPPOPushCommon;
|
|
|
+use App\Libs\Push\XMPush\MiPushCommon;
|
|
|
+use App\Libs\Utils;
|
|
|
+use App\Consts\ErrorConst;
|
|
|
+use App\Libs\Push\HuaWei\HwPushCommon;
|
|
|
+use App\Modules\Push\Models\QappPushApp;
|
|
|
+use App\Exceptions\ApiException;
|
|
|
+use App\Modules\Push\Models\QappPushTask;
|
|
|
+use App\Modules\Push\Models\QappPushTaskLogs;
|
|
|
+use App\Modules\Push\Models\QappPushTaskUsers;
|
|
|
+use App\Modules\Push\Models\QappPushUser;
|
|
|
+use App\Modules\User\Models\QappPackage;
|
|
|
+use Exception;
|
|
|
+use GuzzleHttp\Exception\GuzzleException;
|
|
|
+
|
|
|
+class PushService
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 设置用户reg_id
|
|
|
+ * @param $uid
|
|
|
+ * @param string $regId
|
|
|
+ * @param string $provider
|
|
|
+ * @param string $package
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public static function setUserRegId($uid, string $regId, string $provider, string $package): bool
|
|
|
+ {
|
|
|
+ myLog('push')->info('setUserRegId', compact('uid', 'regId', 'provider', 'package'));
|
|
|
+
|
|
|
+ // push服务商(转小写)
|
|
|
+ $provider = strtolower($provider);
|
|
|
+ if (empty($uid) || empty($regId) || empty($package) || empty($provider)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取缓存
|
|
|
+ $userCacheRegId = PushCache::getUserPushRegId($uid);
|
|
|
+ if ($regId === $userCacheRegId) {
|
|
|
+ myLog('push')->info('setUserRegId', ['cache' => 'match']);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取包信息
|
|
|
+ $packageInfo = QappPackage::getPackageByPackage($package);
|
|
|
+ $packageId = getProp($packageInfo, 'id');
|
|
|
+ $channelId = getProp($packageInfo, 'channel_id');
|
|
|
+ $company = getProp($packageInfo, 'company');
|
|
|
+ myLog('push')->info('setUserRegId', compact('packageId', 'channelId', 'company'));
|
|
|
+ if (empty($packageId)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取app信息
|
|
|
+ $pushApp = QappPushApp::getPushAppByPackageIdAndProvider($packageId, $provider);
|
|
|
+ $pushAppId = getProp($pushApp, 'app_id');
|
|
|
+ myLog('push')->info('setUserRegId', compact('pushAppId'));
|
|
|
+ if (!$pushAppId) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置
|
|
|
+ $pushUser = QappPushUser::getPushUserByUid($uid);
|
|
|
+ $pushUserRegId = (string)getProp($pushUser, 'reg_id');
|
|
|
+ myLog('push')->info('setUserRegId', compact('pushUserRegId'));
|
|
|
+ if ($pushUserRegId === $regId) {
|
|
|
+ PushCache::setUserPushRegId($uid, $regId);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化用户Push信息
|
|
|
+ if (!$pushUser) {
|
|
|
+ // 初始化push_users
|
|
|
+ QappPushUser::initPushUser($uid, $regId, $pushAppId, $provider, $channelId);
|
|
|
+
|
|
|
+ // 针对华为用户需要主动订阅topic,方便后续全量推送
|
|
|
+ if ($provider === PushConst::PROVIDER_HW) {
|
|
|
+ $client = new HwPushCommon($pushAppId, getProp($pushApp, 'app_secret'));
|
|
|
+ $client->subscribeTopic(PushConst::TOPIC_ALL, [$regId]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新用户reg id缓存
|
|
|
+ $result = QappPushUser::setUserRegId($uid, $regId);
|
|
|
+ if ($result) {
|
|
|
+ PushCache::setUserPushRegId($uid, $regId);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 推送消息
|
|
|
+ * @param $taskId
|
|
|
+ * @return bool
|
|
|
+ * @throws ApiException
|
|
|
+ * @throws GuzzleException
|
|
|
+ */
|
|
|
+ public static function sendMessage($taskId): bool
|
|
|
+ {
|
|
|
+ if (empty($taskId)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取任务数据
|
|
|
+ $pushTask = QappPushTask::getPushTaskById($taskId);
|
|
|
+ if ((int)getProp($pushTask, 'status') !== 1) {
|
|
|
+ Utils::throwError(ErrorConst::PUSH_TASK_INVALID);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断任务时间
|
|
|
+ if (getProp($pushTask, 'push_time') > date('Y-m-d H:i:s')) {
|
|
|
+ Utils::throwError(ErrorConst::PUSH_TASK_NOT_START);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取全部子任务
|
|
|
+ $subTasks = QappPushTaskLogs::getPushTaskLogsByTaskId($taskId);
|
|
|
+ if (!$subTasks) {
|
|
|
+ Utils::throwError(ErrorConst::PUSH_TASK_LOGS_NOT_FOUND);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取推送应用信息
|
|
|
+ $pushAppIds = array_column($subTasks, 'app_id');
|
|
|
+ $pushApps = QappPushApp::getPushAppByAppIds($pushAppIds);
|
|
|
+ if (!$pushApps) {
|
|
|
+ Utils::throwError(ErrorConst::PUSH_APP_NOT_SET);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新任务开始状态
|
|
|
+ QappPushTask::updatePushTask(getProp($pushTask, 'id'), [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_DOING,
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 判断是全量发送还是批量发送
|
|
|
+ if (getProp($pushTask, 'push_filter') === 'all') {
|
|
|
+ $result = self::pushMessageToAll($pushTask, $subTasks, $pushApps);
|
|
|
+ } else {
|
|
|
+ $result = self::pushMessageToUsers($pushTask, $subTasks, $pushApps);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新任务执行状态
|
|
|
+ QappPushTask::updatePushTask(getProp($pushTask, 'id'), [
|
|
|
+ 'status' => $result ? PushConst::PUSH_STATUS_SUCCESS : PushConst::PUSH_STATUS_FAIL,
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 全部发送
|
|
|
+ * @param $pushTask
|
|
|
+ * @param $subTasks
|
|
|
+ * @param $pushApps
|
|
|
+ * @return bool
|
|
|
+ * @throws GuzzleException
|
|
|
+ */
|
|
|
+ private static function pushMessageToAll($pushTask, $subTasks, $pushApps): bool
|
|
|
+ {
|
|
|
+ if (empty($pushTask) || empty($subTasks) || empty($pushApps)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ $pushResult = true;
|
|
|
+
|
|
|
+ // 循环群发
|
|
|
+ foreach ($subTasks as $subTask) {
|
|
|
+ $appId = getProp($subTask, 'app_id');
|
|
|
+ $subTaskId = getProp($subTask, 'id');
|
|
|
+ $pushApp = collect($pushApps)->firstWhere('app_id', $appId);
|
|
|
+ if (empty($pushApp)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // push app相关
|
|
|
+ $title = getProp($pushTask, 'title');
|
|
|
+ $content = getProp($pushTask, 'content');
|
|
|
+ $url = getProp($pushTask, 'url');
|
|
|
+ $provider = strtolower(getProp($pushApp, 'provider'));
|
|
|
+ $package = getProp($pushApp, 'package');
|
|
|
+ $appId = getProp($pushApp, 'app_id');
|
|
|
+ $appSecret = getProp($pushApp, 'app_secret');
|
|
|
+ $appKey = getProp($pushApp, 'app_key');
|
|
|
+ $masterSecret = getProp($pushApp, 'master_secret');
|
|
|
+ $topic = PushConst::TOPIC_ALL;
|
|
|
+
|
|
|
+ // 更新开始状态
|
|
|
+ QappPushTaskLogs::updateData(['id' => $subTaskId], [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_DOING,
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $result = [];
|
|
|
+ try {
|
|
|
+ // 针对渠道做不同处理
|
|
|
+ switch ($provider) {
|
|
|
+ case PushConst::PROVIDER_HW:
|
|
|
+ // 开发状态还是生产状态
|
|
|
+ $target = env('APP_ENV') === 'production' ? 2 : 1;
|
|
|
+
|
|
|
+ // 设置相关配置
|
|
|
+ $client = new HwPushCommon($appId, $appSecret);
|
|
|
+ $client->setFastAppTarget($target);
|
|
|
+ $client->setTopic($topic);
|
|
|
+ $client->setBigTag('Task_' . getProp($pushTask, 'id'));
|
|
|
+ $result = $client->sendPushMessage($title, $content, $url);
|
|
|
+ break;
|
|
|
+ case PushConst::PROVIDER_MI:
|
|
|
+ $client = new MiPushCommon($package, $appSecret);
|
|
|
+ $result = $client->sendMessageToAll($title, $content, $url);
|
|
|
+ break;
|
|
|
+ case PushConst::PROVIDER_OPPO:
|
|
|
+ // 实例化OPPO
|
|
|
+ $client = new OPPOPushCommon($appKey, $masterSecret);
|
|
|
+ $messageId = $client->getMessageId($title, $content, $url);
|
|
|
+ $result = $client->broadCastAll($messageId);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (Exception $e) {
|
|
|
+ $pushResult = 0 && $pushResult;
|
|
|
+
|
|
|
+ // 更新子任务失败状态
|
|
|
+ QappPushTaskLogs::updateData(['id' => $subTaskId], [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_FAIL,
|
|
|
+ 'push_result' => json_encode($result, JSON_UNESCAPED_UNICODE),
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新成功状态
|
|
|
+ QappPushTaskLogs::updateData(['id' => $subTaskId], [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_SUCCESS,
|
|
|
+ 'push_result' => json_encode($result, JSON_UNESCAPED_UNICODE),
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $pushResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param $pushTask
|
|
|
+ * @param $subTasks
|
|
|
+ * @param $pushApps
|
|
|
+ * @return bool
|
|
|
+ * @throws ApiException
|
|
|
+ * @throws GuzzleException
|
|
|
+ */
|
|
|
+ private static function pushMessageToUsers($pushTask, $subTasks, $pushApps)
|
|
|
+ {
|
|
|
+ // 获取需要推送的人
|
|
|
+ $taskId = getProp($pushTask, 'id');
|
|
|
+ $taskUsers = QappPushTaskUsers::getTaskUsers($taskId);
|
|
|
+ if (!$taskUsers) {
|
|
|
+ Utils::throwError(ErrorConst::PUSH_TASK_NO_USERS);
|
|
|
+ }
|
|
|
+
|
|
|
+ $pushResult = true;
|
|
|
+
|
|
|
+ // 推送
|
|
|
+ foreach ($subTasks as $subTask) {
|
|
|
+ $subTaskId = getProp($subTask, 'id');
|
|
|
+ $appId = getProp($subTask, 'app_id');
|
|
|
+ $pushApp = collect($pushApps)->firstWhere('app_id', $appId);
|
|
|
+ $uids = collect($taskUsers)->where('app_id', $appId)->pluck('uid');
|
|
|
+ $users = QappPushUser::getPushUserByUids($uids);
|
|
|
+ $regIds = array_column($users, 'reg_id');
|
|
|
+
|
|
|
+ // push app相关
|
|
|
+ $provider = strtolower(getProp($pushApp, 'provider'));
|
|
|
+ $package = getProp($pushApp, 'package');
|
|
|
+ $appId = getProp($pushApp, 'app_id');
|
|
|
+ $appSecret = getProp($pushApp, 'app_secret');
|
|
|
+ $appKey = getProp($pushApp, 'app_key');
|
|
|
+ $masterSecret = getProp($pushApp, 'master_secret');
|
|
|
+ $title = getProp($pushTask, 'title');
|
|
|
+ $content = getProp($pushTask, 'content');
|
|
|
+ $url = getProp($pushTask, 'url');
|
|
|
+
|
|
|
+ // 更新开始状态
|
|
|
+ QappPushTaskLogs::updateData(['id' => $subTaskId], [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_DOING,
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 循环批量
|
|
|
+ $regIdArr = array_chunk($regIds, 1000);
|
|
|
+ try {
|
|
|
+ switch ($provider) {
|
|
|
+ // 华为
|
|
|
+ case PushConst::PROVIDER_HW:
|
|
|
+ // 初始化huawei推送
|
|
|
+ $client = new HwPushCommon($appId, $appSecret);
|
|
|
+
|
|
|
+ // 循环推送
|
|
|
+ foreach ($regIdArr as $regIdList) {
|
|
|
+ $client->setToken($regIdList);
|
|
|
+ $result = $client->sendPushMessage($title, $content, $url);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ // 小米
|
|
|
+ case PushConst::PROVIDER_MI:
|
|
|
+ // 初始化小米推送
|
|
|
+ $client = new MiPushCommon($package, $appSecret);
|
|
|
+
|
|
|
+ // 循环推送
|
|
|
+ foreach ($regIdArr as $regIdList) {
|
|
|
+ $client->setRegArr($regIdList);
|
|
|
+ $result = $client->sendMessage($title, $content, $url);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ // OPPO
|
|
|
+ case PushConst::PROVIDER_OPPO:
|
|
|
+ // 初始化oppo推送
|
|
|
+ $client = new OPPOPushCommon($appKey, $masterSecret);
|
|
|
+ $messageId = $client->getMessageId($title, $content, $url);
|
|
|
+
|
|
|
+ // 循环推送
|
|
|
+ foreach ($regIdArr as $regIdList) {
|
|
|
+ $client->setRegArr($regIdList);
|
|
|
+ $result = $client->broadCastRegIds($messageId);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (Exception $e) {
|
|
|
+ $pushResult = 0 && $pushResult;
|
|
|
+
|
|
|
+ // 更新子任务失败状态
|
|
|
+ QappPushTaskLogs::updateData(['id' => $subTaskId], [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_FAIL,
|
|
|
+ 'push_result' => json_encode($result, JSON_UNESCAPED_UNICODE),
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新成功状态
|
|
|
+ QappPushTaskLogs::updateData(['id' => $subTaskId], [
|
|
|
+ 'status' => PushConst::PUSH_STATUS_SUCCESS,
|
|
|
+ 'push_result' => json_encode($result, JSON_UNESCAPED_UNICODE),
|
|
|
+ 'updated_at' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $pushResult;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|