<?php
/**
 * 即时通讯模块
 * @Copyright (C) 2016 汉潮 All rights reserved.
 * @License http://www.hanchao9999.com
 * @Author xiaoq <570035208@qq.com>
 */
namespace Wxsmall\Model;
use Think\Model;
class ChatModel extends Model{
    protected $tableName = 'LiveAnchor';
    function __construct(){
        // $this->live = new \Common\Vendor\Gateway;//gateway 实例
        // $result = checkliveroom();//获取房间信息
        // if($result['status']!=1){
        //     return $result;
        // }
        // $this->roominfo = $result['roominfo'];
        // $this->roomnumber = $result['roominfo']['roomnumber'];
        // //通讯配置信息
        // $this->sensitive_words = $result['sensitive_words'];//敏感词
    }
    /**
    * type init 握手成功（XX进入直播间）say 发言
    * say (say_type) 1=>握手成功 2=>xxx发言 3=>xxx在去买的路上 4=>xxx关注了主播 5 xxx被禁言 6 点赞操作 7 主播推荐商品 8=>xxx送礼物
    * return array('status'=>状态,'msg'=>返回值)
    */
    public function index($param,$user_info=''){//及时通讯入口
        switch($param['type']){
            case 'init'://websocket握手成功,绑定uid
                $memberinfo = checkuserauthtype();//获取网站会员信息
                if($memberinfo){
                    //返回true绑定成功
                    $result = $this->bindUid($memberinfo,$param);
                    if($result)$this->runLogin('uid',$param,$memberinfo);
                }else{
                     //游客身份观看
                    $this->runLogin('tourist',$param);
                }
                $return['status'] = 1;
                $return['msg'] = '连接成功';
                return $return;
                break;
            case 'say'://发言相关操作
                $memberinfo = $user_info;
                if($param['say_type']==3){//游客购买商品不进行消息提示
                    $result = $this->runCheck($memberinfo,$param);
                    return $result;
                }
                if(empty($memberinfo)){
                    $return = array('status'=>'login','msg'=>'请先登录','url'=>getjumpurl('JUMP_1'));
                    return $return;
                }
                $result = $this->runCheck($memberinfo,$param);
                return $result;
                break;
            case 'start_play'://开始直播
                $result = $this->runHistory('start','',$param['room_id'],0,$param,$user_info);
                return $result;
                break;
            case 'stop_play'://关闭直播
                $result = $this->runHistory('end');
                return $result;
                break;
            default:
                break; 
        }    
    }
    public function getnickname($user){
        if($user['nickname']){
            return $user['nickname'];
        }elseif($user['username']){
            return $user['username'];
        }elseif($user['mobile']){
            return str_cutmobile($user['mobile']);
        }else{
            return $user['id']<10?'hc0'.$user['id']:'hc'.$user['id'];
        }
    }
    //gateway私有方法绑定会员与client_id
    private function bindUid($user,$client){
        if(empty($user['id'])||$client['type']!='init'||empty($client['client_id']))return false;
        return $this->live->bindUid($client['client_id'],$user['id']);
    }
    private function runCollect($user){
        $message = array(
            'type'=>'Collect',
            'status'=>1,
            'time'=>time_format(NOW_TIME)
        );
        $this->live->sendToUid($user['id'],json_encode($message));//向uid绑定的所有client_id发提示
    }
    private function runPraise($user,$room_id='',$param=''){
        $return = array('status'=>1,'praise_number'=>1);
        $live_history_info = $this->runHistory('query','',$room_id,0,$param,$user,'');//查询主播直播记录
        if($live_history_info){
            $where['id'] = $live_history_info['id'];//当前直播信息
            M('LiveHistory')->where($where)->setInc('praise_number');
            $return['praise_number'] = $live_history_info['praise_number']+1;
        }
        return $return;  
    }
    //登录 更新用户列表
    private function runLogin($type,$data,$user=array()){
        $client_id = $data['client_id'];
        if($type=="uid"){
            $client_name = $this->getnickname($user);
            $header_img=idtoname($user['id'],'Member','header_img','id',false);
            if(empty($header_img)){
                $header_img=C('HEAD_DEFAULT_IMG');
            }
            $client_header_img = thumb($header_img,55,55);
            $client_type = $type;
        }else{
            $client_name = '游客';
            $client_type = $type;//tourist 游客标识
        }
        // 获取房间内所有用户列表 
        // 1116新加
        if(empty($this->roomnumber)) $this->roomnumber = $data['room_id'];
        //end
        $clients_list = $this->live->getClientSessionsByGroup($this->roomnumber);
        foreach($clients_list as $tmp_client_id=>$item){
            $this_client_info = $this->live->getSession($tmp_client_id);
            $tmp_clients_list[$tmp_client_id] = $this_client_info['client_header_img']?$this_client_info['client_header_img']:'';
            if(count($tmp_clients_list)>6)break;
        }
        //设置当前用户缓存
        $client_arr['client_name'] = $client_name;
        $client_arr['client_header_img'] = $client_header_img;
        $this->live->setSession($client_id,$client_arr);
        //将当前$client_id加入到房间
        $this->live->joinGroup($client_id, $this->roomnumber);
        //获取这个房间在线连接数
        // $onlinecount = $this->getClientCount($this->roomnumber);
        //存储当前直播间观看人数
        $data = array('liveonlinecount'=>$onlinecount);
        $this->runHistory('update',$data,$this->roomnumber,0,'',$user);
        // 转播给当前房间的所有客户端，xx进入聊天室 message {type:login, client_id:xx, name:xx} 
        $new_message = array(
            'say_type'=>1,
            'type'=>'login',
            'onlinecount'=>$onlinecount,
            'client_type'=>$client_type,
            'client_id'=>$client_id, 
            'clients_list'=>$tmp_clients_list,
            'client_name'=>h($client_name), 
            'time'=>time_format(NOW_TIME)
        );
        $this->live->sendToGroup($this->roomnumber, json_encode($new_message));
    }
    /**安全验证
     * @return array
     */
    private function runCheck($user,$data){
        $return = array('status'=>0,'msg'=>'发送失败');
        $roominfo = idtoname($data['room_id'],'LiveAnchor','*','roomnumber',false);
        if($data['say_type']==2){
            //敏感词过滤
            if(empty($data['content'])){
                $return['msg'] = '发送的内容不能为空';
                return $return;
            }
            if(!$this->transgress_keyword($data['content'])){
                $return['msg'] = '发送的内容中包含敏感词';
                return $return;
            }
            //1108新加
            //end
            if($roominfo['gag_uid']&&in_array($user['id'],explode(',',$roominfo['gag_uid']))){
                $return['msg'] = '禁言状态中';
                return $return;
            }
        }elseif($data['say_type']==3){//购买商品链接跳转
            if(empty($user)){
                $user['nickname'] = '游客';
            }
        }elseif($data['say_type']==4){//主播关注设置
            $result=D("Live/LiveAnchor")->follow_live($this->roomnumber);
            if($result['status']!=1){
                $return['msg'] = $result['msg'];
                return $return;
            }
            $this->runCollect($user);
        }elseif($data['say_type']==5){//禁言设置
        }elseif($data['say_type']==6){
            //点赞操作
            $result = $this->runPraise($user,$data['room_id'],$data);
            if($result['status']==1) $data['praise_number'] = $result['praise_number'];
        }elseif($data['say_type']==7){//主播推荐商品
            $res = $this->checkAnchor($user);//检测是否为主播
            if($res['status']!=1){
                $return['msg'] = $res['msg'];
                return $return;
            }
            //获取并更新商品信息
            $result = D('LiveAnchor')->formatgoods($data,$user);
            if($result['status']!=1){
                $return['msg'] = $result['msg'];
                return $return;
            }
            $data['goods_list'] = $result['goods_list'];
            $data['total_count'] = $result['total_count'];
            //end
        }elseif($data['say_type']==8){//送礼物操作验证
            //检测存储礼物信息
            $result = D('Live/LiveGift')->checkusergift($user,$this->roominfo['user_id'],$data['id'],$data['num']);
            if($result['status']!=1){
                $return['msg'] = $result['msg'];
                $return['jumpcode'] = $result['jumpcode'];//需充值跳转标识
                return $return;
            }
            $data['content'] = $result['content'];
            $data['num'] = $result['num'];
            $data['img'] = $result['img'];
        }
        return $this->runSay($user,$data);
    }
    /**用户发言
     * @return array
     */
    private function runSay($user,$data){
        $exclude_client_id = array();
        $return = array('status'=>1,'msg'=>'发送成功');
        $new_message = array(
            'type'=>'say',
            'say_type'=>$data['say_type'],  
            'from_client_name' =>$this->getnickname($user),
            'content'=>h($data['content']),
            'time'=>date('Y-m-d H:i:s'),
        );
        if($data['say_type']==5){
            $new_message['prohibit_client_id'] = isset($data['prohibit'])?$data['prohibit']:'';//禁言client_id列表
        }
        if($data['say_type']==6){//返回点赞数
            $return['praise_number'] = $new_message['praise_number'] = $data['praise_number'];
            // $exclude_client_id = $this->live->getClientIdByUid($user['id']);//不给自己发信息 
        }
        if($data['say_type']==7){//实时推荐商品
            $new_message['goods_list'] = $data['goods_list'];
            $new_message['total_count'] = $data['total_count'];
        }
        if($data['say_type']==8){//打赏主播
            $new_message['num'] = $data['num'];
            $new_message['img'] = $data['img'];
        }
        // $this->live->sendToGroup($this->roomnumber ,json_encode($new_message),$exclude_client_id);
        return $return;
    }
    /**主播直播记录
     * @param $type 开始直播[start] 查询直播状态[query] 关闭直播[end] 更新直播[update]
     * @return int
     */
    public function runHistory($type,$data=array(),$roomnumber='',$is_admin=0,$params='',$user='',$goods_list=''){
        if(empty($type))return false;
        $return = array('status'=>0,'msg'=>'操作失败');
        $model = M('LiveHistory');
        if($roomnumber){
            $this->roomnumber=$roomnumber;
            $this->roominfo = idtoname($roomnumber,'LiveAnchor','*','roomnumber',false);
        }
        // $return['roominfo'] = $this->roominfo;
        $where['roomnumber'] = $this->roomnumber;
        if(in_array($type,array('query','end','update'))){
            $where['begin_time'] = array('egt',strtotime(date('Y-m-d'.'00:00:00',NOW_TIME)));//直播有效时间是今日开始
            // $where['begin_time'] = array('egt',strtotime(date('Y-m-d'.'00:00:00',NOW_TIME)));//直播有效时间是今日开始
            $where['end_time'] = 0;
            $order['id'] = 'desc';
        }
        if(in_array($type,array('start','end')) && $is_admin==0){
            $result = $this->checkAnchor($user);//检查当前会员是否有主播操作权限
            if($result['status']!=1){
                $return['msg'] = $result['msg'];
                return $return;
            }
        }
        if($type=='query'){
            if($params['map']==1){
                // $go_offline_time = idtoname('go_offline_time','LiveSet','value','name');
                $go_offline_time = getconfig('GO_OFFLINE_TIME');
                unset($where['begin_time']);
                $where['begin_time'][] = array('elt',NOW_TIME);//主播掉线重连判断
                $where['begin_time'][] = array('egt',NOW_TIME-($go_offline_time*3600));//主播掉线重连判断
                $model->where($where)->field(true)->order($order)->find();
            }
            return $model->where($where)->field(true)->order($order)->find();
        }elseif($type=='start'){
            $go_offline_time = idtoname('go_offline_time','LiveSet','value','name');
            $where['begin_time'][] = array('elt',NOW_TIME);//主播掉线重连判断
            $where['begin_time'][] = array('egt',NOW_TIME-($go_offline_time*3600));//主播掉线重连判断
            $where['end_time'] = 0;
            $count = $model->where($where)->field(true)->count();
            // echo $model->getLastSql(); echo '***';
            if($count>0){
                $return['status'] = 1;
                $return['msg'] = '12直播成功';
                $anchor_arr=array();
                $anchor_arr['roomnumber'] = $this->roomnumber;
                $saves['is_live'] = 1;
                M('LiveAnchor')->where($anchor_arr)->save($saves);
            }else{
                //修改状态上次直播状态为无效
                unset($where['begin_time']);
                $save_ids = $model->where($where)->getField('id',true);//查询上次未结束的记录
                if($save_ids){
                    $save['end_time'] = NOW_TIME;
                    $save['goods_info'] = $goods_list;
                    $map['id'] = array('in',$save_ids);
                    $model->where($where)->save($save);
                    //保存回放视频
                    $start_time = $model->where($where)->getField('begin_time',true);
                    $awhere=array();
                    $awhere['stream'] = $this->roomnumber;
                    $awhere['stop_time'] = array('eq',0);
                    $is_live = $this->save_liveurl($this->roomnumber,'',$start_time,$save['end_time'],$awhere);
                //end
                }
                //当天首次开播或者超出断线重连时间
                $data['begin_time'] = NOW_TIME;
                $data['roomnumber'] = $this->roomnumber;
                $data['goods_info'] = $goods_list;
                //添加开播信息
                if($params['brief']) $data['livebrief'] = $params['brief'];
                else $data['livebrief'] = $this->roominfo['brief'];
                if($params['index_img']) $data['liveimg'] = $params['index_img'];
                else $data['liveimg'] = $this->roominfo['index_img'];
                //1102新加
                $is_off = C('SHOW_LIVE_MODEL');
                if($is_off==1) $data['is_effect'] = 1;
                //end
                $info = $model->add($data);
                //1203
                if($info){
                    $streamKey=$this->roomnumber;
                    $data=array();
                    $data['domain'] = idtoname('live_vhost_name','LiveSet','value','name');
                    $data['stream'] = $streamKey;
                    $data['start_time'] = NOW_TIME;
                    $res = M('LiveHistoryLink')->add($data);
                }
                //1109
                $checkinfo = D('LiveAnchor')->chat_room_id($info,$this->roomnumber);
                if($checkinfo['status'] !=1){
                    $is_del = M('LiveHistory')->where('id='.$info)->delete();
                    $return['msg'] = '直播间数量已达上限，请联系系统管理员';
                    return $return;exit();
                }
                $return['checkinfo'] = $checkinfo;
                if($info){
                    $return['group_id'] = $checkinfo['group_id'];//返回直播群组聊天id（web端用）
                    $return['livehistoryid'] = $info;//返回直播记录id
                    $return['status'] = 1;
                    $return['msg'] = '13直播成功';
                }
            }
        }elseif($type=='end'){
            $info = $model->where($where)->field(true)->order($order)->find();
            if($info){
                $map['id'] = $info['id'];
                $save['end_time'] =strtotime(date("Y-m-d H:i:s",NOW_TIME)."+ 30 second") ;
                $save['is_effect'] = 1;
                $saveinfo = $model->where($map)->save($save);
                if($saveinfo){
                    $return['status'] = 1;
                    $return['msg'] = '直播关闭成功';
                }else{
                    $return['msg'] = '直播关闭失败';
                }
            }else{
                $return['msg'] = '当前没有可关闭的直播';
            }
        }elseif($type=='update'){
            //修改直播记录信息
            $model->where($where)->save($data);
        }
        return $return;
    }
    /**用户禁言 $uid被禁言人id 管理员操作
     * @return array
     */
    public function stopSay($uid=0){
        $return = array('status'=>0,'msg'=>'禁言失败');
        if(empty($uid))return $return;
        $memberinfo = checkuserauthtype();//获取当前登录会员信息
        if(empty($memberinfo)){
            $return = array('status'=>'login','msg'=>'请先登录','url'=>getjumpurl('JUMP_1'));
            return $return;
        }
        $checkinfo = $this->checkAnchor();
        if($checkinfo['status']!=1){
            $return['msg'] = $checkinfo['msg'];
            return $return;
        }
        // $client_id_list = $this->live->getClientIdByUid($uid);//禁言会员对应的client_id列表
        if(count($client_id_list)>0)$data['prohibit_client_id'] = $client_id_list;
        $data['say_type'] = 5;
        $user = idtoname($uid,'Member','*','id',false);
        $result = $this->runSay($user,$data);
        if($result['status']==1){
            $return = array('status'=>1,'msg'=>'禁言成功');
        }
        return $return;
    }
    /**全站广播
     * @return array
     */
    public function allSay($message){
        $message = array(
            'type'=>'say',
            'say_type'=>$message['say_type'],//对应前台类型  
            'from_client_id'=>'',
            'from_client_name' =>$message['say_type'],
            'to_client_id'=>'all',
            'content'=>h($data['message']),
            'time'=>date('Y-m-d H:i:s'),
        );
        $this->live->sendToAll(json_encode($message));//后台向所有房间广播信息
        $return = array('status'=>1,'msg'=>'广播成功');
        return $return;
    }
    /**敏感词检测方法
     * @return boolean
     */
    public function transgress_keyword($content){
         if($this->sensitive_words){
            $keyword = explode(',',$this->sensitive_words);
        }else{
            return true;
        }
        $m = 0;
        for($i = 0; $i < count ( $keyword ); $i ++) {//根据数组元素数量执行for循环
            //应用substr_count检测内容中是否包含敏感词
            if (substr_count ( $content, $keyword [$i] ) > 0) {
                $m ++;
            }
        }
        //判断返回值大于0说明包含敏感词
        if($m>0)return false;
        return true;              
    }
    /**表情符号 $type = 1时返回完整的表情url（app使用）
     * @return array
     */
    public function emoticon($type=0){
        $dir = new \Common\Vendor\Dir;
        $modname='Live';
        $pathdir='common/images/face';
        $dirurl = APP_PATH.$modname.'/View/'.get_default_theme($modname).'/'.$pathdir;
        $filelist=$dir->getList($dirurl);
        if(empty($filelist))return false;
        $dirlist=array_slice($filelist,2);
        foreach($dirlist as $k => $v){
            if(str_exists($v, 'gif')){//获取gif表情
                $v=str_replace('.gif','',$v);
                if($type==1){
                    $datalist[$v] = 'http://'.$_SERVER['HTTP_HOST'].$dirurl.'/'.$v.'.gif';
                }else{
                    $datalist[$v]= $v;
                }
            }
        }
        return $datalist;           
    }
    /**礼物列表
     * @return array
     */
    public function gift(){
        $where['status'] = 1;
        $where['is_delete'] = 0;
        $field = array('id','gift_name','money_type','needcoin','gift_icon');
        $order['money_type'] = 'asc';
        $list = M('LiveGift')->where($where)->field($field)->order($order)->select();
        $listfmt = array();
        foreach($list as $k=>$v){
            $list[$k]['img'] = 'http://'.$_SERVER['HTTP_HOST'].$v['gift_icon']; 
            unset($list[$k]['gift_icon']);
            $listfmt[$v['id']]['money_type'] = $v['money_type'];
            $listfmt[$v['id']]['needcoin'] = $v['needcoin'];
        }
        $return['data']['list'] = $list;
        $return['data']['listfmt'] = $listfmt;
        return $return;           
    }
    /**获取某个房间在线人数
     * @return int
     */
    public function getClientCount($group=0){
        if(!$group)return $group;
        // $online_people_rate = idtoname('online_people_rate','LiveSet','value','name');//在线人数基数
        $online_people_rate = getconfig('ONLINE_PEOPLE_RATE');
        return $online_people_rate+($this->live->getClientCountByGroup($group));//房间实际在线人数          
    }
    /**检测当前会员是否为主播
     * @return array
     * =array()
     * =array()
     */
    public function checkAnchor($user=array(),$roominfo=array()){
        $return = array('status'=>0,'msg'=>'您不是主播,或已被禁用，请联系系统管理员');
        if(empty($user)){
            return $return; //获取网站会员信息
            exit();
        }
        if(empty($roominfo)){
            $map=array();
            $map['user_id'] = $user['id'];
            $map['status'] = 1;
            $roominfo = M('LiveAnchor')->where($map)->field(true)->find();
        }
        if($roominfo['user_id']==$user['id']){
            $return['status'] = 1; 
            $return['msg'] = '成功';
        }
        return $return;     
    }
    /**直播鉴权 （链接加权加密）
     * timestamp 失效时间，整形正数，固定长度 10，1970 年 1 月 1 日以来的秒数。用来控制失效时间，10 位整数，有效时间 1800s
     * rand 随机数，一般设成 0
     * uid 	暂未使用（设置成 0 即可)
     * md5hash 	ͨ通过 md5 算法计算出的验证串，数字和小写英文字母混合 0-9a-z，固定长度 32
     */
    public function encrypurl($url,$auth_key,$time='1800',$rand=0,$uid=0){
        $timestamp=NOW_TIME+ $time;
        $urlarr=parse_url($url);
        $md5str=$urlarr['path'].'-'.$timestamp.'-'.$rand.'-'.$uid.'-'.$auth_key;
        $md5hash=md5($md5str);    
        $urlparam=empty($urlarr['query'])?'?':'&';
        return $url.$urlparam.'auth_key='.$timestamp.'-'.$rand.'-'.$uid.'-'.$md5hash;    
    }
    /**获取推流和拉流链接
     * urltype 直播流格式 1=>RTMP格式 2=>FLV格式 3=>M3U8格式
     * livetype 1=>推流 2=>拉流
     */
    public function getliveurl($StreamName='',$livetype=1,$urltype=1){
        $return = array('status'=>0,'msg'=>'获取数据失败');
        if(empty($StreamName)){
            $return['msg'] = '请输入房间编号!';
            return $return;
        }
        $live_app_name = idtoname('live_app_name','LiveSet','value','name',false);
        $live_vhost_name = idtoname('live_vhost_name','LiveSet','value','name',false);
        $live_auth_key = idtoname('live_auth_key','LiveSet','value','name',false);
        if(empty($live_app_name)||empty($live_vhost_name)||empty($live_auth_key)){
            $return['msg'] = '服务器配置有误!';
            return $return;
        }
        $livecode = array(1=>'',2=>'.flv',3=>'.m3u8');
        if($livetype==1){
            $url = 'rtmp://video-center.alivecdn.com/'.$live_app_name.'/'.$StreamName.'?vhost='.$live_vhost_name;
        }elseif($livetype==2){
            if($urltype==1){$firstcode = 'rtmp';}else{$firstcode = 'http';}
            $url = $firstcode.'://'.$live_vhost_name.'/'.$live_app_name.'/'.$StreamName.$livecode[$urltype];
        }
        return $this->encrypurl($url,$live_auth_key);
    }
    //存储回拨地址
    public function get_notify($where,$room_id,$memberinfo){
        $return = array('status'=>0,'msg'=>'获取数据失败');
        if(empty($where)||empty($room_id)||empty($memberinfo)) return $return;
        $start_time = M('LiveHistoryLink')->where($where)->getField('start_time');
        $end_time = NOW_TIME;
        return $this->save_liveurl($room_id,'',$start_time,$end_time,$where);
    }
    //1212存储回放地址
    public function save_liveurl($streamKey,$fname='',$start,$end,$where){
        if(empty($streamKey)) return false;
        $live= new \Common\Vendor\QiniuLive;
        // $live_config_hub = idtoname('live_config_hub','LiveSet','value','name');
        $live_config_hub = getconfig('LIVE_CONFIG_HUB');
        $start=intval($start);
        $end=intval($end);
        $fname=$streamKey.'_'.$start.'_'.$end.'.mp4';
        $m3u8_uri = $streamKey.'_'.$start.'_'.$end.'.m3u8';
        $notify=U('Home/LiveAnchor/notify','',true,true);
        // $live_video_format = idtoname('live_video_format','LiveSet','value','name');
        $live_video_format = getconfig('LIVE_VIDEO_FORMAT');
        $pipeline = $live_video_format?$live_video_format:'hanchao_xinlingshou';
        //mp4
        $result= $live->liveSaveas($streamKey,$fname,$start,$end,'m3u8',$notify,$pipeline);
        if($result['fname']){
          $data = array('mp4_uri'=>$result['fname'],'m3u8_uri'=>$m3u8_uri,'stop_time'=>$end);
          $res = M('LiveHistoryLink')->where($where)->save($data);
          if($res) $return['status'] = 1;
        }
        return $return;
    }
    //end
}