* @copyright walkor * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ /** * 用于检测业务代码死循环或者长时间阻塞等问题 * 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload * 然后观察一段时间workerman.log看是否有process_timeout异常 */ //declare(ticks=1); use GatewayWorker\Lib\Gateway; use Workerman\Lib\Timer; /** * 主逻辑 * 主要是处理 onConnect onMessage onClose 三个方法 * onConnect 和 onClose 如果不需要可以不用实现并删除 */ class Events { public static function onWorkerStart($businessWorker) { // 5 秒同步一下 客服当前接待客户数,计算客服忙碌度 Timer::add(5, function () { // 获取当前连接的客服 $clientIds = Gateway::getClientIdListByGroup(Online::getGrouponName('online_customer_service')); foreach ($clientIds as $client_id) { $session = Gateway::getSession($client_id); $customerService = $session['user']; $customer_service_id = $session['uid'] ?? 0; // 客服 id if ($customer_service_id) { // 当前客服分组名 $customerServiceGroupName = Online::getGrouponName('customer_service_user', ['customer_service_id' => $customer_service_id]); // 获取并设置当前客服正在服务的用户 $customerService['current_num'] = Gateway::getClientIdCountByGroup($customerServiceGroupName); $max_num = $customerService['max_num'] > 0 ? $customerService['max_num'] : 1; // 避免除数为 0 $customerService['busy_percent'] = $customerService['current_num'] / $max_num; // 繁忙程度,越大越繁忙 Gateway::updateSession($client_id, ['user' => $customerService]); } } }); // 初始化上传配置 Online::uploadConfigInit(); } public static function onWebSocketConnect($client_id, $data) { // 存储当前请求信息 $_SESSION['server'] = $data['server'] ?? []; $request = $data['get']; $linkerData = []; $linkerData['identify'] = $request['identify'] ?? ''; $linkerData['session_id'] = $request['session_id'] ?? ''; $linkerData['token'] = $request['token'] ?? ''; $linkerData['expire_time'] = $request['expire_time'] ?? ''; $linkerData['customer_service_id'] = $request['customer_service_id'] ?? 0; if (empty($linkerData['identify'])) { // 缺少参数 Sender::error($client_id, [ 'type' => 'connect_error', 'msg' => '连接错误' ]); Gateway::closeClient($client_id); return false; } // 连接者 $linker = new Linker($client_id, $linkerData); if ($linker->checkAndBind()) { // init $linker->init(); } } /** * 当客户端发来消息时触发 * @param int $client_id 连接id * @param mixed $message 具体消息 */ public static function onMessage($client_id, $requestData) { $requestData = json_decode($requestData, true); $identify = $_SESSION['identify'] ?? ''; $type = $requestData['type'] ?? ''; // 消息类型 $data = $requestData['data'] ?? []; // 要做的事件,参数 $message = $requestData['message'] ?? []; // 发送的消息 if (empty($type) || empty($identify)) { // 缺少参数 Sender::error($client_id, [ 'type' => 'params_error', 'msg' => '参数错误' ]); Gateway::closeClient($client_id); return false; } if ($type == 'ping') { // 心跳检测,直接返回 return true; } if ($identify == 'customer_service') { $session_id = $requestData['session_id'] ?? ''; // 如果是客服,接受传入的 session_id } else { $session_id = $_SESSION['uid'] ?? ''; } $linkerData = [ 'identify' => $identify, ]; // 连接者 $linker = new Linker($client_id, $linkerData); $linker->message($session_id, $type, $message, $data); } /** * 当用户断开连接时触发 * @param int $client_id 连接id */ public static function onClose($client_id) { $identify = $_SESSION['identify'] ?? ''; if (empty($identify)) { // 缺少参数 Sender::error($client_id, [ 'type' => 'params_error', 'msg' => '参数错误' ]); Gateway::closeClient($client_id); return false; } // 只能通过 $identify 获取 session $linkerData = [ 'identify' => $identify, ]; // 连接者 $linker = new Linker($client_id, $linkerData); $linker->close($client_id); } }