class Events { /** * Controller实例 * @var \app\http\Controller */ public static $control ; /** * 当businessWorker进程启动时触发。每个进程生命周期内都只会触发一次。可以在这里为每一个businessWorker进程做一些全局初始化工作,例如设置定时器,初始化redis等连接等。 * 注意:$businessworker->onWorkerStart和Event::onWorkerStart不会互相覆盖,如果两个回调都设置则都会运行。 * 不要在onWorkerStart内执行长时间阻塞或者耗时的操作,这样会导致BusinessWorker无法及时与Gateway建立连接,造成应用异常(SendBufferToWorker fail. * The connections between Gateway and BusinessWorker are not ready错误)。 * @param BusinessWorker $businessWorker */ public static function onWorkerStart(BusinessWorker $businessWorker) { Events::$control = new Controller(); echo "WorkerStart\n"; } /** * $client_id是服务端自动生成的并且无法自定义。 * 可以用过Gateway::bindUid($client_id, $uid)把自己系统的id与client_id绑定,绑定后就可以通过Gateway::sendToUid($uid)发送数据,通过Gateway::isUidOnline($uid)用户是否在线了。 * onConnect事件仅仅代表客户端与gateway完成了TCP三次握手,这时客户端还没有发来任何数据,此时除了通过$_SERVER['REMOTE_ADDR']获得对方ip,没有其他可以鉴别客户端的数据或者信息,所以在onConnect事件里无法确认对方是谁。要想知道对方是谁,需要客户端发送鉴权数据,例如某个token或者用户名密码之类,在onMesssge里做鉴权。 * * @param string $client_id */ public static function onConnect($client_id) { Gateway::sendToCurrentClient("Your client_id is $client_id"); } /** * 当客户端连接上gateway完成websocket握手时触发的回调函数。 * 注意:此回调只有gateway为websocket协议并且gateway没有设置onWebSocketConnect时才有效。 * var ws = new WebSocket('ws://127.0.0.1:7272/?token=kjxdvjkasfh'); * @param string $client_id client_id固定为20个字符的字符串,用来全局标记一个socket连接,每个客户端连接都会被分配一个全局唯一的client_id。 * @param string $data websocket握手时的http头数据,包含get、server等变量 */ public static function onWebSocketConnect($client_id, $data) { if (isset($data['get']) && isset($data['get']['token'])) { $token = $data['get']['token']; // 自己的账号ID $userInfo = Users::where('token', $token)->find(); if ($userInfo) { if ($userInfo['frozen'] != 1) { Gateway::sendToCurrentClient(json_encode([ 'code' => ReturnCode::ERROR_CODE, 'action' => 'onError', 'msg' => '用户已冻结' ])); Gateway::closeClient($client_id); } } else { Gateway::sendToCurrentClient(json_encode([ 'code' => ReturnCode::ERROR_CODE, 'action' => 'onError', 'msg' => '用户已不存在' ])); Gateway::closeClient($client_id); } // $id = decrypt($token, $key); // 解密好的ID Gateway::bindUid($client_id, $userInfo['user_id']); // 机器ID与用户ID绑定 if (! isset($_SESSION['uid'])) { // 消息类型不是登录视为非法请求,关闭连接 // if($data['type'] !== 'login') // { // return Gateway::closeClient($client_id); // } // 设置session,标记该客户端已经登录 $_SESSION['uid'] = $userInfo; } Gateway::sendToCurrentClient(json_encode([ 'code' => ReturnCode::SUCCESS_CODE, 'action' => 'onLogin', 'msg' => '登陆成功', 'data' => $client_id ])); } else { Gateway::closeClient($client_id); } } /** * 有消息时触发该方法 * @param int $client_id 发消息的client_id * @param mixed $message 消息 * @return void */ public static function onMessage($client_id, $data) { $data = json_decode($data, true); $uid = Gateway::getUidByClientId($client_id); if (empty($uid)) { return Gateway::sendToCurrentClient(json_encode([ 'data' => [], 'code' => ReturnCode::ERROR_CODE, 'msg' => '用户未登录', 'event' => 'onError' ])); } $a = $data['event']; if (empty($a) || ! method_exists(Events::$control, $a)) { return Gateway::sendToCurrentClient(json_encode([ 'data' => '', 'code' => ReturnCode::ERROR_CODE, 'msg' => '事件不存在', 'event' => 'onError' ])); } return Events::$control->$a($client_id, $data['data']); } /** * 客户端与Gateway进程的连接断开时触发。不管是客户端主动断开还是服务端主动断开,都会触发这个回调。一般在这里做一些数据清理工作。 * 注意:onClose回调里无法使用Gateway::getSession()来获得当前用户的session数据,但是仍然可以使用$_SESSION变量获得。 * 注意:onClose回调里无法使用Gateway::getUidByClientId()接口来获得uid,解决办法是在Gateway::bindUid()时记录一个$_SESSION['uid'],onClose的时候用$_SESSION['uid']来获得uid。 * 注意:断网断电等极端情况可能无法及时触发onClose回调,因为这种情况客户端来不及给服务端发送断开连接的包(fin包),服务端就无法得知连接已经断开。检测这种极端情况需要心跳检测,并且必须设置$gateway->pingNotResponseLimit>0。这种断网断电的极端情况onClose将被延迟触发,延迟时间为小于$gateway->pingInterval*$gateway->pingNotResponseLimit秒,如果$gateway->pingInterval 和 $gateway->pingNotResponseLimit 中任何一个为0,则可能会无限延迟。 * @param string $client_id */ public static function onClose($client_id) { } /** * 当businessWorker进程退出时触发。每个进程生命周期内都只会触发一次 * 可以在这里为每一个businessWorker进程做一些清理工作,例如保存一些重要数据等。 * 注意:某些情况将不会触发onWorkerStop,例如业务出现致命错误FatalError,或者进程被强行杀死等情况。 * @param BusinessWorker $businessWorker businessWorker进程实例 */ public static function onWorkerStop(BusinessWorker $businessWorker) { echo "WorkerStop\n"; } } class Controller { public function onLogin($client_id, $data) { if (! isset($_SESSION['uid'])) { return Gateway::sendToCurrentClient(json_encode([ 'data' => [ 'code' => ReturnCode::ERROR_CODE, 'msg' => '事件不能为空' ], 'event' => 'onError' ])); } return Gateway::sendToCurrentClient(json_encode([ 'data' => $_SESSION['uid'], 'code' => ReturnCode::ERROR_CODE, 'msg' => '登陆成功', 'event' => 'onLogin' ])); } }