hyperf-chat/app/Service/Message/SubscribeHandleService.php

371 lines
12 KiB
PHP
Raw Normal View History

2020-11-02 22:45:37 +08:00
<?php
2021-07-08 19:09:06 +08:00
namespace App\Service\Message;
use App\Cache\SocketRoom;
2021-07-08 19:30:03 +08:00
use App\Constants\TalkMessageEvent;
use App\Constants\TalkMessageType;
use App\Constants\TalkMode;
2021-07-09 22:57:19 +08:00
use App\Model\Talk\TalkRecords;
use App\Model\Talk\TalkRecordsCode;
use App\Model\Talk\TalkRecordsFile;
use App\Model\Talk\TalkRecordsForward;
use App\Model\Talk\TalkRecordsInvite;
2021-05-20 22:56:55 +08:00
use App\Model\Group\Group;
2021-07-08 19:09:06 +08:00
use App\Model\User;
2021-07-12 22:00:48 +08:00
use App\Model\UsersFriendApply;
2020-11-29 14:44:11 +08:00
use App\Service\SocketClientService;
2021-07-08 19:09:06 +08:00
use App\Service\UserService;
2020-11-02 22:45:37 +08:00
2021-07-08 19:09:06 +08:00
class SubscribeHandleService
2020-11-02 22:45:37 +08:00
{
2020-11-27 19:48:41 +08:00
/**
2020-12-01 17:47:25 +08:00
* 消息事件与回调事件绑定
*
* @var array
2020-11-27 19:48:41 +08:00
*/
2020-11-22 23:10:00 +08:00
const EVENTS = [
2020-11-27 19:48:41 +08:00
// 聊天消息事件
2021-07-08 19:30:03 +08:00
TalkMessageEvent::EVENT_TALK => 'onConsumeTalk',
2020-11-27 19:48:41 +08:00
// 键盘输入事件
2021-07-08 19:30:03 +08:00
TalkMessageEvent::EVENT_KEYBOARD => 'onConsumeKeyboard',
2020-11-27 19:48:41 +08:00
// 用户在线状态事件
2021-07-08 19:30:03 +08:00
TalkMessageEvent::EVENT_ONLINE_STATUS => 'onConsumeOnlineStatus',
2020-11-27 19:48:41 +08:00
// 聊天消息推送事件
2021-07-08 19:30:03 +08:00
TalkMessageEvent::EVENT_REVOKE_TALK => 'onConsumeRevokeTalk',
2020-11-27 19:48:41 +08:00
// 好友申请相关事件
2021-07-08 19:30:03 +08:00
TalkMessageEvent::EVENT_FRIEND_APPLY => 'onConsumeFriendApply'
2020-11-22 23:10:00 +08:00
];
2020-11-21 19:53:01 +08:00
/**
2021-07-08 19:09:06 +08:00
* @var SocketClientService
2020-11-02 22:45:37 +08:00
*/
2021-07-08 19:09:06 +08:00
private $clientService;
2020-11-02 22:45:37 +08:00
2021-07-08 19:09:06 +08:00
public function __construct(SocketClientService $clientService)
2020-11-22 23:10:00 +08:00
{
2021-07-08 19:09:06 +08:00
$this->clientService = $clientService;
2020-11-22 23:10:00 +08:00
}
2021-07-09 22:57:19 +08:00
/**
* @param array $data
* <pre>
* [
* 'uuid' => '',
* 'event' => '',
* 'data' => '',
* 'options' => ''
* ];
* </pre>
*/
public function handle(array $data)
{
2021-07-10 10:55:25 +08:00
if (!isset($data['uuid'], $data['event'], $data['data'], $data['options'])) {
return false;
}
2021-07-09 22:57:19 +08:00
if (isset(self::EVENTS[$data['event']])) {
call_user_func([$this, self::EVENTS[$data['event']]], $data);
}
}
2020-11-22 23:10:00 +08:00
/**
* 对话聊天消息
*
2021-07-08 19:09:06 +08:00
* @param array $data 队列消息
2020-11-22 23:10:00 +08:00
* @return string
*/
2021-07-08 19:09:06 +08:00
public function onConsumeTalk(array $data): string
2020-11-02 22:45:37 +08:00
{
2021-07-05 21:52:44 +08:00
$talk_type = $data['data']['talk_type'];
$sender_id = $data['data']['sender_id'];
$receiver_id = $data['data']['receiver_id'];
$record_id = $data['data']['record_id'];
2021-06-29 17:30:43 +08:00
$fds = [];
2021-04-08 09:20:51 +08:00
$groupInfo = null;
2020-11-21 19:53:01 +08:00
2021-07-08 19:30:03 +08:00
if ($talk_type == TalkMode::PRIVATE_CHAT) {
2021-06-29 17:30:43 +08:00
$fds = array_merge(
2021-07-08 19:09:06 +08:00
$this->clientService->findUserFds($sender_id),
$this->clientService->findUserFds($receiver_id)
2021-06-29 17:30:43 +08:00
);
2021-07-08 19:30:03 +08:00
} else if ($talk_type == TalkMode::GROUP_CHAT) {
2021-07-05 21:52:44 +08:00
foreach (SocketRoom::getInstance()->getRoomMembers(strval($receiver_id)) as $uid) {
2021-07-08 19:09:06 +08:00
$fds = array_merge($fds, $this->clientService->findUserFds(intval($uid)));
2020-11-03 14:07:54 +08:00
}
2021-07-05 21:52:44 +08:00
$groupInfo = Group::where('id', $receiver_id)->first(['group_name', 'avatar']);
2020-11-21 19:53:01 +08:00
}
2020-12-01 13:54:40 +08:00
// 客户端ID去重
2021-07-05 21:52:44 +08:00
if (!$fds = array_unique($fds)) {
2021-07-08 19:09:06 +08:00
return true;
2021-07-05 21:52:44 +08:00
}
2020-11-21 19:53:01 +08:00
2021-07-05 21:52:44 +08:00
$result = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
->where('talk_records.id', $record_id)
2020-11-21 19:53:01 +08:00
->first([
2021-07-05 21:52:44 +08:00
'talk_records.id',
'talk_records.talk_type',
'talk_records.msg_type',
'talk_records.user_id',
'talk_records.receiver_id',
'talk_records.content',
'talk_records.is_revoke',
'talk_records.created_at',
2020-11-21 19:53:01 +08:00
'users.nickname',
'users.avatar',
2020-11-21 19:53:01 +08:00
]);
2021-07-08 19:09:06 +08:00
if (!$result) return true;
2020-11-22 23:10:00 +08:00
$file = $code_block = $forward = $invite = [];
2020-11-21 22:47:21 +08:00
switch ($result->msg_type) {
2021-07-08 19:30:03 +08:00
case TalkMessageType::FILE_MESSAGE:
2021-07-05 21:52:44 +08:00
$file = TalkRecordsFile::where('record_id', $result->id)->first([
'id', 'record_id', 'user_id', 'file_source', 'file_type',
'save_type', 'original_name', 'file_suffix', 'file_size', 'save_dir'
]);
2020-11-21 22:47:21 +08:00
$file = $file ? $file->toArray() : [];
2020-12-01 13:54:40 +08:00
$file && $file['file_url'] = get_media_url($file['save_dir']);
2021-07-05 21:52:44 +08:00
break;
2021-07-08 19:30:03 +08:00
case TalkMessageType::FORWARD_MESSAGE:
2021-07-05 21:52:44 +08:00
$forward = ['num' => 0, 'list' => []];
$forwardInfo = TalkRecordsForward::where('record_id', $result->id)->first(['records_id', 'text']);
if ($forwardInfo) {
$forward = [
'num' => count(parse_ids($forwardInfo->records_id)),
'list' => json_decode($forwardInfo->text, true) ?? []
];
}
break;
2020-12-01 13:54:40 +08:00
2021-07-08 19:30:03 +08:00
case TalkMessageType::CODE_MESSAGE:
2021-07-05 21:52:44 +08:00
$code_block = TalkRecordsCode::where('record_id', $result->id)->first(['record_id', 'code_lang', 'code']);
$code_block = $code_block ? $code_block->toArray() : [];
2020-11-21 22:47:21 +08:00
break;
2021-07-05 21:52:44 +08:00
2021-07-08 19:30:03 +08:00
case TalkMessageType::GROUP_INVITE_MESSAGE:
2021-07-05 21:52:44 +08:00
$notifyInfo = TalkRecordsInvite::where('record_id', $result->id)->first([
2020-11-21 22:47:21 +08:00
'record_id', 'type', 'operate_user_id', 'user_ids'
]);
$userInfo = User::where('id', $notifyInfo->operate_user_id)->first(['nickname', 'id']);
$invite = [
'type' => $notifyInfo->type,
2020-11-21 22:47:21 +08:00
'operate_user' => ['id' => $userInfo->id, 'nickname' => $userInfo->nickname],
'users' => User::whereIn('id', parse_ids($notifyInfo->user_ids))->get(['id', 'nickname'])->toArray()
2020-11-21 22:47:21 +08:00
];
2020-12-01 13:54:40 +08:00
unset($notifyInfo, $userInfo);
2020-11-21 22:47:21 +08:00
break;
2020-11-21 19:53:01 +08:00
}
2020-12-01 13:54:40 +08:00
$notify = [
2021-07-05 21:52:44 +08:00
'sender_id' => $sender_id,
'receiver_id' => $receiver_id,
'talk_type' => $talk_type,
'data' => $this->formatTalkMessage([
2021-04-08 09:20:51 +08:00
'id' => $result->id,
2021-07-05 21:52:44 +08:00
'talk_type' => $result->talk_type,
2021-04-08 09:20:51 +08:00
'msg_type' => $result->msg_type,
2021-07-05 21:52:44 +08:00
"user_id" => $result->user_id,
"receiver_id" => $result->receiver_id,
2021-04-08 09:20:51 +08:00
'avatar' => $result->avatar,
'nickname' => $result->nickname,
'group_name' => $groupInfo ? $groupInfo->group_name : '',
'group_avatar' => $groupInfo ? $groupInfo->avatar : '',
"created_at" => $result->created_at,
"content" => $result->content,
"file" => $file,
"code_block" => $code_block,
'forward' => $forward,
'invite' => $invite
2020-11-21 19:53:01 +08:00
])
];
2020-11-20 19:17:11 +08:00
2021-07-08 19:30:03 +08:00
$this->socketPushNotify($fds, json_encode([TalkMessageEvent::EVENT_TALK, $notify]));
2020-11-22 23:10:00 +08:00
2021-07-08 19:09:06 +08:00
return true;
2020-11-22 23:10:00 +08:00
}
/**
* 键盘输入事件消息
*
2021-07-08 19:09:06 +08:00
* @param array $data 队列消息
2020-11-22 23:10:00 +08:00
* @return string
*/
2021-07-08 19:09:06 +08:00
public function onConsumeKeyboard(array $data): string
2020-11-22 23:10:00 +08:00
{
2021-07-08 19:09:06 +08:00
$fds = $this->clientService->findUserFds($data['data']['receiver_id']);
2020-12-01 13:54:40 +08:00
2021-07-08 19:30:03 +08:00
$this->socketPushNotify($fds, json_encode([TalkMessageEvent::EVENT_KEYBOARD, $data['data']]));
2020-11-22 23:10:00 +08:00
2021-07-08 19:09:06 +08:00
return true;
2020-11-22 23:10:00 +08:00
}
/**
* 用户上线或下线消息
*
2021-07-08 19:09:06 +08:00
* @param array $data 队列消息
2020-11-22 23:10:00 +08:00
* @return string
*/
2021-07-08 19:09:06 +08:00
public function onConsumeOnlineStatus(array $data): string
2020-11-22 23:10:00 +08:00
{
2021-07-05 21:52:44 +08:00
$user_id = (int)$data['data']['user_id'];
$status = (int)$data['data']['status'];
2020-11-22 23:10:00 +08:00
$fds = [];
2021-07-07 19:43:09 +08:00
$ids = container()->get(UserService::class)->getFriendIds($user_id);
foreach ($ids as $friend_id) {
2021-07-08 19:09:06 +08:00
$fds = array_merge($fds, $this->clientService->findUserFds(intval($friend_id)));
2020-11-22 23:10:00 +08:00
}
2021-07-05 21:52:44 +08:00
$this->socketPushNotify(array_unique($fds), json_encode([
2021-07-08 19:30:03 +08:00
TalkMessageEvent::EVENT_ONLINE_STATUS, [
2021-07-05 21:52:44 +08:00
'user_id' => $user_id,
'status' => $status
]
]));
2020-11-22 23:10:00 +08:00
2021-07-08 19:09:06 +08:00
return true;
2020-11-22 23:10:00 +08:00
}
/**
* 撤销聊天消息
*
2021-07-08 19:09:06 +08:00
* @param array $data 队列消息
2020-11-22 23:10:00 +08:00
* @return string
*/
2021-07-08 19:09:06 +08:00
public function onConsumeRevokeTalk(array $data): string
2020-11-22 23:10:00 +08:00
{
2021-07-05 21:52:44 +08:00
$record = TalkRecords::where('id', $data['data']['record_id'])->first(['id', 'talk_type', 'user_id', 'receiver_id']);
2020-11-22 23:10:00 +08:00
$fds = [];
2021-07-08 19:30:03 +08:00
if ($record->talk_type == TalkMode::PRIVATE_CHAT) {
2021-07-08 19:09:06 +08:00
$fds = array_merge($fds, $this->clientService->findUserFds($record->user_id));
$fds = array_merge($fds, $this->clientService->findUserFds($record->receiver_id));
2021-07-08 19:30:03 +08:00
} else if ($record->talk_type == TalkMode::GROUP_CHAT) {
2021-07-05 21:52:44 +08:00
$userIds = SocketRoom::getInstance()->getRoomMembers(strval($record->receiver_id));
2020-11-22 23:10:00 +08:00
foreach ($userIds as $uid) {
2021-07-08 19:09:06 +08:00
$fds = array_merge($fds, $this->clientService->findUserFds((int)$uid));
2020-11-22 23:10:00 +08:00
}
}
2021-07-05 21:52:44 +08:00
$fds = array_unique($fds);
2021-07-08 19:30:03 +08:00
$this->socketPushNotify($fds, json_encode([TalkMessageEvent::EVENT_REVOKE_TALK, [
2021-07-05 21:52:44 +08:00
'talk_type' => $record->talk_type,
'sender_id' => $record->user_id,
'receiver_id' => $record->receiver_id,
'record_id' => $record->id,
]]));
2020-11-03 14:07:54 +08:00
2021-07-08 19:09:06 +08:00
return true;
2020-11-02 22:45:37 +08:00
}
2020-11-27 19:48:41 +08:00
/**
* 好友申请消息
*
2021-07-08 19:09:06 +08:00
* @param array $data 队列消息
2020-11-29 14:44:11 +08:00
* @return string
2020-11-27 19:48:41 +08:00
*/
2021-07-08 19:09:06 +08:00
public function onConsumeFriendApply(array $data): string
2020-11-27 19:48:41 +08:00
{
2021-07-07 19:43:09 +08:00
$data = $data['data'];
2021-07-12 22:00:48 +08:00
$applyInfo = UsersFriendApply::where('id', $data['apply_id'])->first();
2021-07-08 19:09:06 +08:00
if (!$applyInfo) return true;
2021-07-07 19:43:09 +08:00
2021-07-08 19:09:06 +08:00
$fds = $this->clientService->findUserFds($data['type'] == 1 ? $applyInfo->friend_id : $applyInfo->user_id);
2021-07-07 19:43:09 +08:00
if ($data['type'] == 1) {
$msg = [
'sender_id' => $applyInfo->user_id,
'receiver_id' => $applyInfo->friend_id,
'remark' => $applyInfo->remark,
];
} else {
$msg = [
'sender_id' => $applyInfo->friend_id,
'receiver_id' => $applyInfo->user_id,
'status' => $applyInfo->status,
'remark' => $applyInfo->remark,
];
}
2020-11-29 14:44:11 +08:00
2021-07-07 19:43:09 +08:00
$friendInfo = User::select(['id', 'avatar', 'nickname', 'mobile', 'motto'])->find($data['type'] == 1 ? $applyInfo->user_id : $applyInfo->friend_id);
$msg['friend'] = [
'user_id' => $friendInfo->id,
'avatar' => $friendInfo->avatar,
'nickname' => $friendInfo->nickname,
'mobile' => $friendInfo->mobile,
];
2021-07-08 19:30:03 +08:00
$this->socketPushNotify(array_unique($fds), json_encode([TalkMessageEvent::EVENT_FRIEND_APPLY, $msg]));
2020-12-01 13:54:40 +08:00
2021-07-08 19:09:06 +08:00
return true;
2020-12-01 13:54:40 +08:00
}
/**
* WebSocket 消息推送
*
* @param $fds
* @param $message
*/
private function socketPushNotify($fds, $message)
{
2020-11-30 22:59:49 +08:00
$server = server();
2020-11-27 19:48:41 +08:00
foreach ($fds as $fd) {
2021-05-22 14:47:46 +08:00
$server->exist(intval($fd)) && $server->push(intval($fd), $message);
2020-11-27 19:48:41 +08:00
}
2020-12-01 13:54:40 +08:00
}
2020-11-27 19:48:41 +08:00
2020-12-01 13:54:40 +08:00
/**
* 格式化对话的消息体
*
* @param array $data 对话的消息
* @return array
*/
2020-12-01 22:50:43 +08:00
private function formatTalkMessage(array $data): array
2020-12-01 13:54:40 +08:00
{
$message = [
2021-04-20 19:59:39 +08:00
"id" => 0, // 消息记录ID
2021-07-05 21:52:44 +08:00
"talk_type" => 1, // 消息来源[1:好友私信;2:群聊]
2021-04-20 19:59:39 +08:00
"msg_type" => 1, // 消息类型
2021-04-20 16:30:57 +08:00
"user_id" => 0, // 发送者用户ID
2021-07-05 21:52:44 +08:00
"receiver_id" => 0, // 接收者ID[好友ID或群ID]
2020-12-01 13:54:40 +08:00
// 发送消息人的信息
"nickname" => "",// 用户昵称
"avatar" => "",// 用户头像
"group_name" => "",// 群组名称
"group_avatar" => "",// 群组头像
2020-12-01 13:54:40 +08:00
// 不同的消息类型
2021-04-08 09:20:51 +08:00
"file" => [],
"code_block" => [],
"forward" => [],
"invite" => [],
2020-12-01 13:54:40 +08:00
// 消息创建时间
2021-07-05 21:52:44 +08:00
"content" => '',// 文本消息
2021-04-08 09:20:51 +08:00
"created_at" => "",
2021-07-05 21:52:44 +08:00
// 消息属性
"is_revoke" => 0, // 消息是否撤销
2020-12-01 13:54:40 +08:00
];
return array_merge($message, array_intersect_key($data, $message));
2020-11-27 19:48:41 +08:00
}
2020-11-02 22:45:37 +08:00
}