hyperf-chat/app/Controller/WebSocketController.php

145 lines
4.2 KiB
PHP
Raw Normal View History

2020-11-02 22:45:37 +08:00
<?php
declare(strict_types=1);
2020-12-26 21:33:40 +08:00
/**
* This is my open source code, please do not use it for commercial applications.
* For the full copyright and license information,
* please view the LICENSE file that was distributed with this source code
*
* @author Yuandong<837215079@qq.com>
* @link https://github.com/gzydong/hyperf-chat
*/
2020-11-02 22:45:37 +08:00
namespace App\Controller;
2021-05-21 22:56:42 +08:00
use App\Cache\SocketRoom;
2020-11-07 22:57:10 +08:00
use Hyperf\Di\Annotation\Inject;
2020-12-01 17:47:25 +08:00
use App\Constants\SocketConstants;
2020-11-02 22:45:37 +08:00
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnMessageInterface;
use Hyperf\Contract\OnOpenInterface;
use Swoole\Http\Request;
use Swoole\Websocket\Frame;
2020-11-07 22:57:10 +08:00
use Swoole\Http\Response;
use Swoole\WebSocket\Server;
2020-11-29 14:44:11 +08:00
use App\Service\SocketClientService;
2020-11-22 23:10:00 +08:00
use App\Service\MessageHandleService;
use App\Model\Group\GroupMember;
2020-11-22 23:10:00 +08:00
use App\Amqp\Producer\ChatMessageProducer;
2020-11-03 14:07:54 +08:00
2020-11-07 22:57:10 +08:00
/**
* Class WebSocketController
2021-04-20 16:30:57 +08:00
*
2020-11-07 22:57:10 +08:00
* @package App\Controller
*/
2020-11-02 22:45:37 +08:00
class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
{
2020-11-07 22:57:10 +08:00
/**
* @inject
2020-11-29 14:44:11 +08:00
* @var SocketClientService
2020-11-07 22:57:10 +08:00
*/
2020-11-29 14:44:11 +08:00
private $socketClientService;
2020-11-07 22:57:10 +08:00
2020-11-22 23:10:00 +08:00
/**
* @inject
* @var MessageHandleService
*/
private $messageHandleService;
2020-12-26 21:33:40 +08:00
/**
* 消息事件绑定
*/
2020-11-22 23:10:00 +08:00
const EVENTS = [
2021-04-20 16:30:57 +08:00
SocketConstants::EVENT_TALK => 'onTalk',
2020-12-01 17:47:25 +08:00
SocketConstants::EVENT_KEYBOARD => 'onKeyboard',
2020-11-22 23:10:00 +08:00
];
2020-11-07 22:57:10 +08:00
/**
* 连接创建成功回调事件
*
* @param Response|Server $server
2021-04-20 16:30:57 +08:00
* @param Request $request
2020-11-07 22:57:10 +08:00
*/
public function onOpen($server, Request $request): void
2020-11-02 22:45:37 +08:00
{
2021-05-23 16:52:01 +08:00
// 当前连接的用户
$user_id = auth('jwt')->user()->getId();
2021-05-22 20:54:30 +08:00
2021-05-23 16:52:01 +08:00
stdout_log()->notice("用户连接信息 : user_id:{$user_id} | fd:{$request->fd} 时间:" . date('Y-m-d H:i:s'));
2020-11-07 22:57:10 +08:00
2020-11-22 23:10:00 +08:00
// 判断是否存在异地登录
2021-05-23 16:52:01 +08:00
$isOnline = $this->socketClientService->isOnlineAll($user_id);
2020-11-22 23:10:00 +08:00
2020-12-26 21:33:40 +08:00
// 若开启单点登录,则主动关闭之前登录的连接
2020-12-02 15:14:29 +08:00
if ($isOnline) {
2021-05-13 18:01:34 +08:00
// TODO 预留
2020-12-02 15:14:29 +08:00
}
2020-11-07 22:57:10 +08:00
// 绑定fd与用户关系
2021-05-23 16:52:01 +08:00
$this->socketClientService->bindRelation($request->fd, $user_id);
2020-11-03 14:07:54 +08:00
2020-11-21 19:53:01 +08:00
// 加入群聊
2021-05-23 16:52:01 +08:00
$groupIds = GroupMember::getUserGroupIds($user_id);
2020-11-21 19:53:01 +08:00
foreach ($groupIds as $group_id) {
2021-05-23 16:52:01 +08:00
SocketRoom::getInstance()->addRoomMember(strval($group_id), strval($user_id));
2020-11-21 19:53:01 +08:00
}
2020-11-22 23:10:00 +08:00
if (!$isOnline) {
// 推送消息至队列
2021-05-13 18:01:34 +08:00
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_ONLINE_STATUS, [
2021-05-23 16:52:01 +08:00
'user_id' => $user_id,
2021-05-13 18:01:34 +08:00
'status' => 1,
'notify' => '好友上线通知...'
]));
2020-11-22 23:10:00 +08:00
}
2020-11-02 22:45:37 +08:00
}
2020-11-07 22:57:10 +08:00
/**
* 消息接收回调事件
*
* @param Response|Server $server
2021-04-20 16:30:57 +08:00
* @param Frame $frame
2020-11-07 22:57:10 +08:00
*/
public function onMessage($server, Frame $frame): void
2020-11-02 22:45:37 +08:00
{
2020-11-08 22:58:17 +08:00
// 判断是否为心跳检测
if ($frame->data == 'PING') return;
2020-12-26 21:33:40 +08:00
$result = json_decode($frame->data, true);
2021-05-13 18:01:34 +08:00
if (!isset(self::EVENTS[$result['event']])) return;
2020-12-02 15:14:29 +08:00
// 回调事件处理函数
call_user_func_array([
$this->messageHandleService,
self::EVENTS[$result['event']]
2021-05-13 18:01:34 +08:00
], [$server, $frame, $result['data']]);
2020-11-02 22:45:37 +08:00
}
2020-11-07 22:57:10 +08:00
/**
* 连接创建成功回调事件
*
* @param Response|\Swoole\Server $server
2021-04-20 16:30:57 +08:00
* @param int $fd
* @param int $reactorId
2020-11-07 22:57:10 +08:00
*/
public function onClose($server, int $fd, int $reactorId): void
2020-11-02 22:45:37 +08:00
{
2021-05-22 20:54:30 +08:00
$user_id = $this->socketClientService->findFdUserId($fd);
2020-11-08 22:58:17 +08:00
2020-11-22 23:31:21 +08:00
stdout_log()->notice("客户端FD:{$fd} 已关闭连接 用户ID为【{$user_id}】,关闭时间:" . date('Y-m-d H:i:s'));
2020-11-08 22:58:17 +08:00
2021-04-22 16:54:01 +08:00
// 删除 fd 绑定关系
2020-11-29 14:44:11 +08:00
$this->socketClientService->removeRelation($fd);
2020-11-08 22:58:17 +08:00
2020-11-09 17:41:22 +08:00
// 判断是否存在异地登录
2021-05-13 18:01:34 +08:00
$isOnline = $this->socketClientService->isOnlineAll($user_id);
2020-11-09 17:41:22 +08:00
if (!$isOnline) {
2020-11-22 23:10:00 +08:00
// 推送消息至队列
2021-05-13 18:01:34 +08:00
push_amqp(new ChatMessageProducer(SocketConstants::EVENT_ONLINE_STATUS, [
'user_id' => $user_id,
'status' => 0,
'notify' => '好友离线通知通知...'
]));
2020-11-09 17:41:22 +08:00
}
2020-11-02 22:45:37 +08:00
}
}