123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- <?php
- namespace addons\shopro\library\chat;
- use addons\shopro\exception\ShoproException;
- use addons\shopro\library\chat\traits\DebugEvent;
- use addons\shopro\library\chat\traits\Helper;
- use addons\shopro\library\chat\traits\Session;
- use addons\shopro\library\chat\traits\NspData;
- use addons\shopro\library\chat\traits\BindUId;
- use PHPSocketIO\SocketIO;
- use PHPSocketIO\Socket;
- use PHPSocketIO\Nsp;
- class Chat
- {
- /**
- * session 存储助手
- */
- use Session;
- /**
- * 绑定 UID 助手
- */
- use BindUId;
- /**
- * 绑定数据到 nsp 作为全局数据
- */
- use NspData;
- /**
- * 助手方法
- */
- use Helper;
- /**
- * debug 方式注册事件
- */
- use DebugEvent;
- /**
- * 当前 phpsocket.io 实例
- *
- * @var SocketIO
- */
- public $io;
- /**
- * 当前连接实例
- *
- * @var Socket
- */
- public $socket;
- /**
- * 当前 namespace 实例
- *
- * @var Nsp
- */
- public $nsp;
- /**
- * 当前发送实例
- *
- * @var Sender
- */
- public $sender;
- /**
- * 当前获取数据
- *
- * @var Getter
- */
- public $getter;
- /**
- * chat 操作类
- *
- * @var ChatService
- */
- public $chatService;
- protected $auth = [
- 'user',
- 'admin',
- ];
- /**
- * 初始化 chat 系统
- *
- * @param SocketIo $io
- * @param Socket $socket
- * @param Nsp $nsp
- */
- public function __construct(SocketIo $io, Nsp $nsp, Socket $socket = null)
- {
- $this->io = $io;
- $this->socket = $socket;
- $this->nsp = $nsp;
- // 初始化获取更改数据实例
- $this->getter = new Getter($socket, $io, $nsp);
- // 初始化发送实例
- $this->sender = new Sender($socket, $io, $nsp, $this->getter);
- // 初始化 客服公共方法实例
- $this->chatService = new ChatService($socket, $io, $nsp, $this->getter);
- }
- public function on()
- {
- // on 方法只有在连接的时候走一次
- $this->register('test', function ($data, $callback) {
- // $class = "\\app\\chat\\library\\provider\\auth\\User";
- // $provider = new $class($this);
- // $this->socket->removeAllListeners('message');
- // 注册相关身份事件
- // $provider->customerEvent();
- $customer_service_room = $this->getRoomName('customer_service_room', ['room_id' => 'admin']);
- $customerServices = $this->getter('socket')->getSessionsByRoom($customer_service_room, 'customer_service');
- $this->sender->successSocket($callback, '连接成功', [
- 'msg' => '恭喜鏈接成功',
- 'bind' => $this->nsp->bind ?? [],
- 'nsp_room_ids' => $this->nspData('room_ids'),
- 'customer_service' => $customerServices,
- 'nsp_data' => $this->nsp->nspData ?? [],
- 'rooms' => isset($this->nsp->adapter->rooms) ? $this->nsp->adapter->rooms : [],
- 'current_rooms' => $this->socket->rooms,
- 'session' => $this->session(),
- 'client_id' => $this->socket->id,
- 'session_ids' => $this->nspData('session_ids')
- ]);
-
- $this->sender->successUId('new message', '消息桶送', ['aaa' => 'bbb'], [
- 'id' => $this->session('session_id'),
- 'type' => $this->session('auth'),
- ]);
- // foreach ($clientIds as $client_id) {
- // $this->sender->successSocket('new message', ['aaa' => 'bbb']);
- // }
- $this->socket->on('test-child', function ($data, $callback) {
- echo "子集消息来了";
- $this->session('text:child', 'aaa');
- $this->sender->successSocket($callback, '连接成功', [
- 'msg' => '子事件夜之星成功了'
- ]);
- });
- });
- // socket 连接初始化,socket.io-client 连接后的第一步
- $this->register('connection', function ($data, $callback) {
- // 初始化连接
- $auth = $data['auth'] ?? '';
- if (!in_array($auth, $this->auth)) {
- throw new ShoproException('身份错误');
- }
- // 存储当前 auth 驱动
- $this->session('auth', $auth);
- // 加入对应身份组
- $this->socket->join($this->getRoomName('auth', ['auth' => $auth]));
- // 加入在线连接组
- $this->socket->join('online');
- // 检测并自动登录
- $result = $this->chatService->authLogin($data);
- // 注册各自身份的事件
- $this->authEvent($auth);
- // 连接成功,发送给自己
- $this->sender->authSuccess($callback);
- });
- // auth 身份登录,管理员或者用户
- $this->register('login', function ($data, $callback) {
- // 登录,和系统中的用户或者管理员绑定
- $result = $this->chatService->authLogin($data);
- if ($result) {
- // 登录成功
- $this->sender->authSuccess($callback);
- return true;
- }
- // 登录失败
- throw new ShoproException('登录失败');
- });
- /**
- * 断开连接
- */
- $this->register('disconnect', function ($data, $callback) {
- $customer_service_id = $this->session('customer_service_id');
- $session_id = $this->session('session_id');
- $identify = $this->session('identify') ?: '';
- // $auth = $this->session('auth');
- // $authUser = $this->session('auth_user');
- // 断开连接,解绑 bind 的身份
- $this->chatService->disconnectUnbindAll();
- // 如果登录了,并且所有客户端都下线了, 删除相关 auth 的 ids
- // if ($this->chatService->isLogin() && !$this->getter('socket')->isOnlineAuthBySessionId($session_id, $auth)) {
- // $this->nspSessionIdDel($session_id, $auth);
- // }
- // 如果是顾客
- if ($identify == 'customer') {
- // 顾客所在房间
- $room_id = $this->session('room_id');
- // 顾客断开连接
- if (!$this->getter('socket')->isOnLineCustomerById($session_id)) {
- // 当前所遇用户端都断开了
- $waiting_room_name = $this->getRoomName('customer_service_room_waiting', ['room_id' => $room_id]);
- $rooms = $this->socket->rooms;
- // 判断是否在排队中
- if (in_array($waiting_room_name, $rooms)) {
- // 这里顾客的所有客户端都断开了,在排队排名中移除
- $this->nspWaitingDel($room_id, $session_id);
-
- // 排队发生变化,通知房间中所有排队用户
- $this->sender->allWaitingQueue($room_id);
- // 离开排队中房间(将离线的用户从等待中移除)
- $this->socket->leave($waiting_room_name);
- // 通知更新排队中列表,把当前下线用户移除
- $this->sender->waiting();
- }
- // 通知所有客服,顾客下线
- $this->sender->customerOffline();
- }
- }
- // 如果是客服
- if ($identify == 'customer_service') {
- // 客服断开连接
- if (!$this->getter('socket')->isOnLineCustomerServiceById($customer_service_id)) {
- // 当前客服的所有客户端都下线了
- // 更新客服状态为离线
- $this->getter()->updateCustomerServiceStatus($customer_service_id, 'offline');
- // 通知连接的用户(在当前客服服务的房间里面的用户),客服下线了
- $this->sender->customerServiceOffline();
- // 通知当前房间的在线客服,更新当前在线客服列表
- $this->sender->customerServiceUpdate();
- }
- }
- });
- }
- /**
- * 注册相关身份事件
- *
- * @param string $auth
- * @return void
- */
- private function authEvent($auth)
- {
- // 实例化相关身份事件
- $class = "\\addons\\shopro\\library\\chat\\provider\\auth\\" . ucfirst($auth);
- $provider = new $class($this);
- // 注册相关身份事件
- $provider->on();
- }
- /**
- * 站内信通知
- *
- * @param object $http_connection
- * @param string $uri
- * @param array $data
- * @return void
- */
- public function innerWorker($httpConnection, $uri, $data)
- {
- if ($uri == '/notification') {
- $this->exec($httpConnection, function () use ($data) {
- $receiver = $data['receiver'] ?? [];
- $sendData = $data['data'] ?? [];
- $receiver_type = $receiver['type'] ?? 'user';
- $receiverIds = $receiver['ids'] ?? '';
- $receiverIds = is_array($receiverIds) ? $receiverIds : explode(',', $receiverIds);
-
- // 循环给接收者发送消息
- foreach ($receiverIds as $id) {
- // 获取接收人的 session_id
- $session_id = $this->getter()->getSessionIdByAuth($id, $receiver_type);
- if ($session_id) {
- $this->sender->successUId('notification', '收到通知', $sendData, [
- 'id' => $session_id, 'type' => $receiver_type
- ]);
- }
- }
- });
- }
- // 这句话必须有,否则会提示超时
- $httpConnection->send('ok');
- }
- }
|