server=$server; $this->fd=$frame->fd; $this->message_data = json_decode($frame->data,true); if ($this->message_data['type']!='ping') { Log::info('收到消息数据:'.$frame->data); } } public function deal() { switch ($this->message_data['type']) { case 'ping' ://心跳检测 $message_type='ping'; $push_data='心跳检测'; $this->server->push($this->fd,myResult($message_type,$push_data)); //保持会话 $push_data=[]; $session_id=''; $need_check=false; $fd_store=RedisCache::hget('CHAT_CS_FD_MAP',$this->fd); if ($fd_store) { $cs_info_data = json_decode(RedisCache::hget('CHAT_CS_INFO',$fd_store),true); $session_id=$cs_info_data['session_id']; $need_check=true; $check_field='admin_user_id'; } else { $fd_store=RedisCache::hget('CHAT_USER_FD_MAP',$this->fd); if ($fd_store) { $user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$fd_store),true); $session_id=$user_info_data['session_id']; if (!checkGuestFlag($fd_store)) { $need_check=true; $check_field='user_id'; } } else { $fd_store=RedisCache::hget('CHAT_ADMIN_FD_MAP',$this->fd); if ($fd_store) { $admin_info_data = json_decode(RedisCache::hget('CHAT_ADMIN_INFO',$fd_store),true); $session_id=$admin_info_data['session_id']; $need_check=true; $check_field='admin_user_id'; } } } if ($session_id!='' && $need_check) { //查看会话是否存在 $session_redis=RedisCache::store('session_store'); //Log::info('ping当前会话ID'.$session_id); $session_data=$this->unserializePhp($session_redis->get($session_id)); //Log::info('ping当前会话信息'.json_encode($session_data)); if ($session_data) { if (isset($session_data[$check_field])) { $session_redis->expire($session_id,Config::get('session.expire')); } else { $message_type='initError'; $push_data['content']='您已退出登录'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } else { $message_type='initError'; $push_data['content']='您已退出登录'; $this->server->push($this->fd,myResult($message_type,$push_data)); } //切换缓存 RedisCache::store('default'); } break; case 'openService' ://客服专有,打开对外服务(进入在线客服队列) if ($this->csInit()) { $this->openService(); } break; case 'getUserChat' ://客服专有,从用户等待队列中获得一个用户对话 if ($this->csInit()) { $this->getUserChat(); } break; case 'closeService' ://客服专有,关闭对外服务(离开在线客服队列,但目前正在对话中的,仍保持通讯) if ($this->csInit()) { $this->closeService(); } break; case 'closeUserChat' ://客服专有,关闭和指定用户的对话 if ($this->csInit()) { $this->closeUserChat(); } break; case 'chatCSMessage' ://客服专有 if ($this->csInit()) { $this->chatCSMessage(); } break; case 'getChatCSMessage' ://客服专有 if ($this->csInit()) { $this->getChatCSMessage(); } break; case 'switchToOther' ://客服专有 //转接给其他客服 if ($this->csInit()) { $this->switchToOther(); } break; case 'chatMessage' ://用户专有 if ($this->userInit()) { $this->chatMessage(); } break; case 'getChatMessage' ://用户专有 if ($this->userInit()) { $this->getChatMessage(); } break; case 'reConnect' ://用户专有 //重新进入分配和等待客服队列 if ($this->userInit()) { $this->reConnect(); } break; default: break; /*$result['message_type']='error'; $result['data']=['错误消息类型'];*/ } } protected function csInit() { //客服初始化 //读出fd所对应的客服 $fd_store=RedisCache::hget('CHAT_CS_FD_MAP',$this->fd); if ($fd_store) { $this->fd_store=$fd_store; return true; } else { $message_type='initError'; $push_data['content']='没有对应工作台信息'; $this->server->push($this->fd,myResult($message_type,$push_data)); return false; } } protected function userInit() { //用户初始化 //读出fd所对应的用户 $fd_store=RedisCache::hget('CHAT_USER_FD_MAP',$this->fd); if ($fd_store) { $this->fd_store=$fd_store; return true; } else { $message_type='initError'; $push_data['content']='没有建立通话'; $this->server->push($this->fd,myResult($message_type,$push_data)); return false; } } protected function openService() { //打开服务,增加到在线客服队列 //查看队列中是否已经存在 $online_cs_list = RedisCache::lrange("CUSTOMER_ONLINE_QUEUE"); if (!in_array($this->fd_store,$online_cs_list)) { RedisCache::lpush("CUSTOMER_ONLINE_QUEUE",$this->fd_store); } /*$message_type='openService'; $push_data['content']='打开对外服务成功'; $this->server->push($this->fd,myResult($message_type,$push_data));*/ //不再自动分配 } protected function closeService() { //关闭对外服务,从在线客服队列中移除 RedisCache::lrem('CUSTOMER_ONLINE_QUEUE',$this->fd_store,0); /*$result['message_type']='closeService'; $result['data']=['关闭对外服务成功'];*/ } protected function chatCSMessage() { //客服消息 $offline_flag=true; //先看双方有没有建立连接 $user_store_id=$this->message_data['data']['to_id']; $link_check = RedisCache::llen('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store); if ($link_check>0) { //双方在对话中 //读出用户对应的fd $fd_store=RedisCache::hget('CHAT_USER_FD',$user_store_id); if ($fd_store) { $now_time=date('Y-m-d H:i:s'); $message_type='chatMessage'; $cs_info_data = json_decode(RedisCache::hget('CHAT_CS_INFO',$this->fd_store),true); $push_data=["cs_info"=>$cs_info_data,"time"=>$now_time,"content"=>$this->message_data['data']['content']]; $this->server->push($fd_store,myResult($message_type,$push_data)); //增加到对话记录中 RedisCache::lpush('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store,json_encode(['time'=>$now_time,"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$user_store_id])); $offline_flag=false; } /*else { $message_type='error'; $push_data['content']='消息发送失败,用户已离线'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } else { $message_type='error'; $push_data['content']='消息发送失败,双方未建立连接'; $this->server->push($this->fd,myResult($message_type,$push_data));*/ } //离线消息 if ($offline_flag) { if (!checkGuestFlag($user_store_id)) { //离线留言 //创建离线留言 RedisCache::lpush('OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store,json_encode(['time'=>date('m-d H:i:s'),"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$user_store_id])); } else { $message_type='error'; $push_data['content']='不能对游客进行离线留言'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } } protected function getChatCSMessage() { //Log::info('客服获取聊天记录'.$this->fd); //获得历史聊天记录 $push_data['to_id']=$user_store_id=$this->message_data['data']['to_id']; $push_data['from_times']=$from_times=$this->message_data['data']['from_times']; $push_data['times']=$times=$this->message_data['data']['times']; //user_id或user_session=$user_store_id if (checkGuestFlag($user_store_id)) { $user_where['user_session']=$user_store_id; } else { $user_where['user_id'] = $user_store_id; } $cs_where['admin_user_id']=[$this->fd_store,0]; $order['id']='desc'; //$chat_cs_message_count=Db::name('chat_message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->count(); $chat_cs_message_count=Db::name('chat_message')->where($user_where)->where($cs_where)->count(); //$chat_cs_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->order($order)->limit($from_times,$times)->select(); $chat_cs_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where($user_where)->where($cs_where)->order($order)->limit($from_times,$times)->select(); foreach ($chat_cs_message as $k=>$v) { $chat_cs_message_list=json_decode($v['message'],true); $chat_cs_message_result=[]; foreach ($chat_cs_message_list as $value) { $chat_cs_message_result[]=json_decode($value,true); } //$chat_cs_message[$k]['message']=array_reverse($chat_cs_message_result); $chat_cs_message[$k]['message']=$chat_cs_message_result; } $message_type='getChatCSMessage'; $push_data['message_count']=$chat_cs_message_count; $push_data['chat_message']=$chat_cs_message; //Log::info('客服获取聊天记录结果'.myResult($message_type,$push_data)); $this->server->push($this->fd,myResult($message_type,$push_data)); } protected function closeUserChat($message_type='disconnect') { //客服关闭和对方对话 $user_store_id=$this->message_data['data']['to_id']; //先看双方有没有建立连接 $link_check = RedisCache::llen('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store); if ($link_check>0) { $this->noticeCSLeave($this->server,$user_store_id,$this->fd_store,$message_type); //存储并删除对话 $add_data['create_time']=date('Y-m-d H:i:s'); $add_data['admin_user_id']=$this->fd_store; if (checkGuestFlag($user_store_id)) { $add_data['user_id']=0; $add_data['user_session']=$user_store_id; } else { $add_data['user_id']=$user_store_id; $add_data['user_session']=''; } $add_data['message']=json_encode(RedisCache::lrange('CHAT_DATA_'.$user_store_id.'_'.$this->fd_store)); $add_data['offline_flag']=0; Db::name('chat_message')->insert($add_data); RedisCache::batch_del(['CHAT_DATA_'.$user_store_id.'_'.$this->fd_store]); } //看看有没有离线消息 $link_check = RedisCache::llen('OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store); if ($link_check>0) { //存储并删除对话 $add_data['create_time']=date('Y-m-d H:i:s'); $add_data['admin_user_id']=$this->fd_store; if (checkGuestFlag($user_store_id)) { $add_data['user_id']=0; $add_data['user_session']=$user_store_id; } else { $add_data['user_id']=$user_store_id; $add_data['user_session']=''; } $add_data['message']=json_encode(RedisCache::lrange('OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store)); $add_data['offline_flag']=1; $add_data['read_flag']=0; Db::name('chat_message')->insert($add_data); RedisCache::batch_del(['OFFLINE_CHAT_DATA_'.$user_store_id.'_'.$this->fd_store]); } } protected function switchToOther() { //转接其他客服 //先看双方有没有建立连接 Log::info('CHAT_DATA_'.$this->message_data['data']['to_id'].'_'.$this->fd_store); $link_check = RedisCache::llen('CHAT_DATA_'.$this->message_data['data']['to_id'].'_'.$this->fd_store); if ($link_check>0) { //双方在对话中 //读出用户对应的fd $fd_store=RedisCache::hget('CHAT_USER_FD',$this->message_data['data']['to_id']); if ($fd_store) { //看看转向的客服有没有建立连接 Log::info('转接的目标客服id:'.$this->message_data['data']['to_cs_id']); $to_cs_fd=RedisCache::hget('CHAT_CS_FD',$this->message_data['data']['to_cs_id']); Log::info('转接的目标客服fd:'.$to_cs_fd); if ($to_cs_fd) { $this->closeUserChat('switchToOther'); $this->createChatRelation($this->server,$fd_store,$this->message_data['data']['to_id'],$to_cs_fd,$this->message_data['data']['to_cs_id']); $message_type='switchToOther'; $push_data['content']='转接成功'; $push_data['user_id']=$this->message_data['data']['to_id']; $this->server->push($this->fd,myResult($message_type,$push_data)); } else { $message_type='error'; $push_data['content']='转接失败,目标客服未开启工作台'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } else { $message_type='error'; $push_data['content']='转接失败,用户已离线'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } else { $message_type='error'; $push_data['content']='转接失败,双方未建立连接'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } protected function chatMessage() { //用户消息 //先看双方有没有建立连接 //Log::info('CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id']); //增加留言功能 if ($this->message_data['data']['to_id']>0) { $offline_flag=true; $link_check = RedisCache::llen('CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id']); if ($link_check>0) { //双方在对话中 //读出用户对应的fd $fd_store=RedisCache::hget('CHAT_CS_FD',$this->message_data['data']['to_id']); if ($fd_store) { $now_time=date('Y-m-d H:i:s'); $message_type='chatMessage'; $user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$this->fd_store),true); $push_data=["user_info"=>$user_info_data,"time"=>$now_time,"content"=>$this->message_data['data']['content']]; $this->server->push($fd_store,myResult($message_type,$push_data)); //增加到对话记录中 RedisCache::lpush('CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id'],json_encode(['time'=>$now_time,"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$this->message_data['data']['to_id']])); $offline_flag=false; } /*else { $message_type='error'; $push_data['content']='消息发送失败,客服已离线'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } else { $message_type='error'; $push_data['content']='消息发送失败,双方未建立连接'; $this->server->push($this->fd,myResult($message_type,$push_data));*/ } //离线消息 if ($offline_flag) { if (!checkGuestFlag($this->fd_store)) { //离线留言 //创建离线留言 RedisCache::lpush('OFFLINE_CHAT_DATA_'.$this->fd_store.'_'.$this->message_data['data']['to_id'],json_encode(['time'=>date('Y-m-d H:i:s'),"content"=>$this->message_data['data']['content'],"from_id"=>$this->fd_store,"to_id"=>$this->message_data['data']['to_id']])); } else { $message_type='error'; $push_data['content']='游客不能进行留言,请先登录'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } } else { if (!checkGuestFlag($this->fd_store)) { //离线留言 //创建离线留言 RedisCache::lpush('OFFLINE_CHAT_DATA_' . $this->fd_store . '_0', json_encode(['time' => date('Y-m-d H:i:s'), "content" => $this->message_data['data']['content'], "from_id" => $this->fd_store, "to_id" => 0])); } else { $message_type='error'; $push_data['content']='游客不能进行留言,请先登录'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } } protected function getChatMessage() { //获得历史聊天记录 $push_data['to_id']=$cs_store_id=$this->message_data['data']['to_id']; $push_data['from_times']=$from_times=$this->message_data['data']['from_times']; $push_data['times']=$times=$this->message_data['data']['times']; if (checkGuestFlag($this->fd_store)) { $user_where['user_session']=$this->fd_store; } else { $user_where['user_id'] = $this->fd_store; } $user_where['read_flag'] = 1; //$user_where['user_id']=$this->fd_store; //$user_where['user_session']=$this->fd_store; $cs_where['admin_user_id']=[$cs_store_id,0]; $order['id']='desc'; //$chat_message_count=Db::name('chat_message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->count(); //$chat_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where(function ($query) use($user_where) { $query->whereOr($user_where); })->where($cs_where)->order($order)->limit($from_times,$times)->select(); $chat_message_count=Db::name('chat_message')->where($user_where)->where($cs_where)->count(); $chat_message=Db::name('chat_message')->field('admin_user_id,offline_flag,create_time,message')->where($user_where)->where($cs_where)->order($order)->limit($from_times,$times)->select(); foreach ($chat_message as $k=>$v) { $chat_message_list=json_decode($v['message'],true); $chat_message_result=[]; foreach ($chat_message_list as $value) { $chat_message_result[]=json_decode($value,true); } //$chat_message[$k]['message']=array_reverse($chat_message_result); $chat_message[$k]['message']=$chat_message_result; } $message_type='getChatMessage'; $push_data['message_count']=$chat_message_count; $push_data['chat_message']=$chat_message; $this->server->push($this->fd,myResult($message_type,$push_data)); } protected function reConnect() { $user_info_data = json_decode(RedisCache::hget('CHAT_USER_INFO',$this->fd_store),true); $this->assignCS($this->server, $this->fd, $this->fd_store,$user_info_data['guest_flag']); } protected function getUserChat() { $assign_flag=false; //从等待队列中获得一个用户对话,应优先客服专属的用户 $online_user_list = RedisCache::lrange("CHAT_USER_QUEUE"); if (count($online_user_list)>0) { //查询有没有专属用户 $sp_user_list=Db::name('users')->where(['user_id'=>$online_user_list,'custom_service_id'=>$this->fd_store])->column('user_id'); if ($sp_user_list!=null) { //取第一个专属用户 foreach ($online_user_list as $v) { if (in_array($v,$sp_user_list)) { //从队列删除 RedisCache::lrem('CHAT_USER_QUEUE',$v,0); //广播通知 $this->pushUserQueueNum($this->server); //可建立通话关系 $user_id=$v; $assign_flag=true; break; } } } else { //从队列中取一个用户 $user_id=RedisCache::rpop("CHAT_USER_QUEUE"); //广播通知 $this->pushUserQueueNum($this->server); $assign_flag=true; } } if ($assign_flag) { //获得用户的fd $user_fd=RedisCache::hget('CHAT_USER_FD',$user_id);; //建立对话关系 $this->createChatRelation($this->server,$user_fd,$user_id,$this->fd,$this->fd_store); } else { $message_type='error'; $push_data['content']='暂无用户需要服务'; $this->server->push($this->fd,myResult($message_type,$push_data)); } } }