<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @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;
//defined('IN_WEB') or define('IN_WEB', true);
define('WORKERNAME', 'Service');

//define('WWWROOT', dirname(__FILE__).'/../../');
//require_once WWWROOT  . 'core.php';
//define( 'PATH_CFG', WWWROOT . 'config/'.$config['sidlist'][1].$isTset.'/');
//require_once PATH_CFG . 'config.inc.php';
//oo::setConfig( $config); //设置全局变量
//oo::functions()->header();
/**
 * 主逻辑
 * 主要是处理 onConnect onMessage onClose 三个方法
 * onConnect 和 onClose 如果不需要可以不用实现并删除
 */
class Events
{
    public static function onWorkerStart($worker){
        global $dbs;
        global $rediss;
        $dbs = oo::commonOprDb('common');
        $dbs->connect();
        $redisArr =['common','statistics'];
        foreach ($redisArr as $v){
            $rediss[$v] = oo::commonOprRedis($v);
        }
        $time_id = Timer::add(5, function () use (&$time_id,$redisArr) {
            global $dbs;
            global $rediss;
            if(!$dbs->ping()){//失败释放内存，重连
                echo date('Y-m-d H:i:s').'close-mysql'."\r\n";
                $dbs->close();
                oo::$objDb =[];
                $dbs = oo::commonOprDb('common');
            }
            foreach ($redisArr as $v){
                if(!$rediss[$v]->ping()){//失败释放内存，重连
                    echo date('Y-m-d H:i:s').'close-redis'."\r\n";
                    $rediss[$v]->close();
                    oo::$objRedis =[];
                    $rediss[$v] = oo::commonOprRedis('common');
                }
            }
        });

        //保存各自节点所有在线玩家信息
        $recordTimer = Timer::add(30, function () { //每30秒存储一次all uid到redis
            if(!oo::commonOprModel('workerman')->checkNeedSave()){
                return;
            }
            oo::commonOprModel('workerman')->saveAllUids(Gateway::getAllUidList());
        });

        //订阅各自节点的消息
        Timer::add(2, function () {
            $lastSubPush = time();
            oo::commonOprModel('workerman')->pushMsgSubscribe();
        });
    }
    /**
     * 当客户端连接时触发
     * 如果业务不需此回调可以删除onConnect
     *
     * @param int $client_id 连接id
     */
    public static function onConnect($client_id){
        $time_id = Timer::add(5, function () use ($client_id , &$time_id) {
            if(empty(Gateway::getSession($client_id))){
                Gateway::closeClient($client_id);
            }
            Timer::del($time_id);
        });
    }

    /**
     * 当客户端发来消息时触发
     * @param int $client_id 连接id
     * @param mixed $message 具体消息
     */
    public static function onMessage($client_id, $message){
        json_decode($message);
        if(json_last_error() == JSON_ERROR_NONE){
            $res =json_decode($message,true);
            $res['encryp'] = 0;
        }else{
            $res = ProtocolsEvent::wsDecode($message);
            $res['encryp'] = 1;
        }
      	
      	if($res['cmd'] == 0x2008){
            list($t1, $t2) = explode(' ', microtime());
            $mSeconds = (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
            $str = json_encode(['cmd'=>0x600d,'code'=>1,"ts"=>time(), 'm_ts' => $mSeconds]);
            if($res['encryp']){
                $str = ProtocolsEvent::encode($str);
            }
            Gateway::sendToClient($client_id, $str);
            $uid = Gateway::getUidByClientId($client_id);
            $uid && oo::commonOprModel('workerman')->online($uid);
            return;
        }

        if(in_array($res['cmd'],array_keys(ocmd::$Cmd))){
            $res['cmd'] = ocmd::$Cmd[$res['cmd']];
            $session = Gateway::getSession($client_id);
            if(!isset($res['uid'])){
                if(isset($session[$client_id]['uid'])){
                    $res['uid'] = intval($session[$client_id]['uid']);
                }
            }

            //每10次请求更新一次在线标记
            if(!empty($res['uid'])){
                $incrRet = oo::commonOprRedis('user')->incr(okeys::userWsReq($res['uid']));
                if($incrRet && $incrRet == 1){ //60秒过期
                    oo::commonOprRedis('user')->expire(okeys::userWsReq($res['uid']), 60);
                }
                if($incrRet && $incrRet % 11 == 0){ //更新在线标记
                    oo::commonOprRedis('user')->delete(okeys::userWsReq($res['uid']));
                    oo::commonOprModel('workerman')->online($res['uid']);
                }
            }

            $action = explode('_',$res['cmd']);
            self::CrazyGodEvents(ucfirst($action[0]),ucfirst($action[1]),$client_id,$res);
        }
    }

    /**
     * 当用户断开连接时触发
     * @param int $client_id 连接id
     */
    public static function onClose($client_id){
        self::CrazyGodEvents('User','Offline',$client_id);
    }

    /**
     * 选择业务类
     * @param $mod
     * @param $func
     * @param $client_id
     * @param mixed $data
     */
    public static function CrazyGodEvents($mod,$func, $client_id, $data = ''){
        require_once  __DIR__ . '/../Function/' .$mod.'.php';
        $mod = $mod.'CrazyWorker';
        $obj = new $mod(isset($data['sid'])?$data['sid']:1,$client_id);
        $obj->$func($client_id,$data);
    }

}
