* @copyright walkor * * @see 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; /** * 主逻辑 * 主要是处理 onConnect onMessage onClose 三个方法 * onConnect 和 onClose 如果不需要可以不用实现并删除. */ class Events { use \App\Handlers\ExceptionTrait, \App\Models\WarningLogTraitModel, \App\Models\BikeTraitModel, \App\Handlers\Crc16Handler; public static $db = null; public static $redis = null; public static $mongo = null; private static $db_config = [ 'host' => '192.168.10.10', 'port' => 3306, 'user' => 'homestead', 'password' => 'secret', 'db_name' => 'weilaibike' ]; private static $redis_config = [ 'host' => '192.168.10.10', 'port' => 6379, 'database' => 0 ]; private static $mongodb_config = [ 'url' => 'mongodb://114.116.38.6', 'database' => 'weilaibike' ]; public static function onWorkerStart($businessWorker) { self::$db_config = Config['db']; self::$redis_config = Config['redis']; self::$mongodb_config = Config['mongodb']; self::$db = new \Workerman\MySQL\Connection(self::$db_config['host'], self::$db_config['port'], self::$db_config['user'], self::$db_config['password'], self::$db_config['db_name']); self::$redis = new Redis(); self::$redis->pconnect(self::$redis_config['host'], self::$redis_config['port']); self::$redis->select(self::$redis_config['database']); self::$mongo = (new MongoDB\Client(self::$mongodb_config['url']))->selectDatabase(self::$mongodb_config['database']); } /** * 当客户端连接时触发 * 如果业务不需此回调可以删除onConnect. * * @param int $client_id 连接id */ public static function onConnect($client_id) { } /** * 当客户端发来消息时触发. * * @param int $client_id 连接id * @param mixed $message 具体消息 */ public static function onMessage($client_id, $message) { $message = bin2hex($message); print_r($message); $data = str_split(str_replace(' ', '', trim($message)), 2); if (($data[0] . $data[1]) !== 'aaaa') return ''; self::log($message, 'EVENT_message', self::$LOG_MAJOR); // 传送头 $header = array_slice($data, 0, 10); $dataLength = hexdec($header[2] . $header[3]); // 检验包是否完整 if ($dataLength !== count($data)) return 'error:data length'; // 过滤加密 if ($header[4] == '05') { self::log($message, '**jiami**', self::$LOG_COMMON); Gateway::closeCurrentClient(); return ''; }; // 流水码 $num_code = $header[6]; // 装载数据 $body = array_slice($data, 10, -2); // 校检尾 $checkEnd = implode('', array_slice($data, -2, 2)); if ($checkEnd !== self::crc16(array_slice($data, 2, -2))) { self::log("CRC_ERROR", "CRC16", self::$LOG_MAJOR); } $cmd = strtoupper($data[5]); $cmd_in_box_no = [ \App\Maps\CmdMap::CMD_LOGIN, \App\Maps\CmdMap::CMD_LOCATION, \App\Maps\CmdMap::CMD_BATTERY_STATUS, \App\Maps\CmdMap::CMD_WARNING, \App\Maps\CmdMap::CMD_HEARTBEAT, \App\Maps\CmdMap::CMD_STATUS_SYNC, \App\Maps\CmdMap::CMD_MSG_UP, \App\Maps\CmdMap::CMD_ADMIN_MSG_FORWARD, \App\Maps\CmdMap::CMD_BOX_UPGRADE, \App\Maps\CmdMap::CMD_BOX_ACTIVE_REPORTING, \App\Maps\CmdMap::CMD_BOX_STATUS_CHANGE_UP ]; if (in_array($cmd, $cmd_in_box_no)) { // 响应包含box_no $box_no = substr(implode('', array_slice($body, 0, 5)), 0, 9); $_SESSION['box_no'] = $box_no; Gateway::bindUid($client_id, $box_no); if (!isset($_SESSION['bike_no'])) { $_SESSION['bike_no'] = self::byBoxNoGetBikeNoStatic($box_no); } //离线检查 if (self::$redis->exists('bike:offline:' . $box_no)) { self::log($box_no, 'EVENT_ONLINE', self::$LOG_MAJOR); $cols['is_link'] = \App\Maps\BikeMap::LINK_ONLINE; self::$db->update('bikes')->where('box_no = ' . $box_no)->cols($cols)->query(); self::$redis->del('bike:offline:' . $box_no); } } $response_body = ''; $response_cmd = false; $param = [ 'db' => self::$db, 'mongo' => self::$mongo, 'redis' => self::$redis ]; switch ($cmd) { case \App\Maps\CmdMap::CMD_LOGIN: echo 'CMD_LOGIN' . PHP_EOL; // 登录数据包 $response_body = (new \App\Servers\LoginServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_LOGIN; break; case \App\Maps\CmdMap::CMD_LOCATION: echo 'location' . PHP_EOL; // 位置数据包 $response_body = (new \App\Servers\LocationServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_LOCATION; break; case \App\Maps\CmdMap::CMD_HEARTBEAT: echo 'CMD_HEARTBEAT' . PHP_EOL; // 心跳数据包 $response_body = (new \App\Servers\HeartBeatServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_HEARTBEAT; break; case \App\Maps\CmdMap::CMD_BATTERY_STATUS: echo 'CMD_BATTERY_STATUS' . PHP_EOL; //电池数据包 $response_body = (new \App\Servers\BatteryServer($param))->main($body); break; case \App\Maps\CmdMap::CMD_WARNING: echo 'CMD_WARNING' . PHP_EOL; //告警数据包 $response_body = (new \App\Servers\WarningServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_WARNING; break; case \App\Maps\CmdMap::CMD_REMOTE_CONTROLLER_RESPONSE: echo 'CMD_REMOTE_CONTROLLER_RESPONSE' . PHP_EOL; // 服务器下发控制命令时,应答终端 $response_body = (new \App\Servers\RemoteCmdServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_REMOTE_CMD; break; case \App\Maps\CmdMap::CMD_STATUS_SYNC: echo 'CMD_STATUS_SYNC' . PHP_EOL; // 终端状态同步 $response_body = (new \App\Servers\BoxSyncServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_STATUS_SYNC; break; case \App\Maps\CmdMap::CMD_MSG_UP: echo 'CMD_MSG_UP' . PHP_EOL; // 短信上报 $response_body = (new \App\Servers\MsgUpServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_MSG_UP; break; case \App\Maps\CmdMap::CMD_ADMIN_MSG_FORWARD: echo 'CMD_MSG_FORWARD' . PHP_EOL; // 后台短信转发响应 (new \App\Servers\MsgForwardServer($param))->main($body); break; case \App\Maps\CmdMap::CMD_BOX_UPGRADE: echo 'CMD_BOX_UPGRADE' . PHP_EOL; //终端请求固件升级 $response_body = (new \App\Servers\BoxUpgradeServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_BOX_UPGRADE; break; case \App\Maps\CmdMap::CMD_BOX_ACTIVE_REPORTING: echo 'CMD_BOX_ACTIVE_REPORTING' . PHP_EOL; // 终端主动上报 $response_body = (new \App\Servers\BoxActiveReportingServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_BOX_ACTIVE_REPORTING; break; case \App\Maps\CmdMap::CMD_BOX_REPORTING_NEW_BIKE: echo 'CMD_BOX_REPORTING_NEW_BIKE' . PHP_EOL; //终端最新车辆信息上报事件 $response_body = (new \App\Servers\NewBikeReportingServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_BOX_UP_NEW_BIKE_DATA; break; case \App\Maps\CmdMap::CMD_BOX_STATUS_CHANGE_UP: echo 'CMD_BOX_STATUS_CHANGE_UP' . PHP_EOL; // 终端状态类型变更上报 $response_body = (new \App\Servers\BoxStatusChangeServer($param))->main($body); $response_cmd = \App\Maps\CmdMap::CMD_RESPONSE_BOX_STATUS_CHANGE_UP; break; case \App\Maps\CmdMap::CMD_REMOTE_SELECT_CMD_BOX_UP_DATA: echo 'CMD_REMOTE_SELECT_CMD_BOX_UP_DATA' . PHP_EOL; // 远程查询命令,终端上传 (new \App\Servers\BoxSelectCmdServer($param))->main($body); break; case \App\Maps\CmdMap::CMD_REMOTE_SETTING_CMD_BOX_UP_DATA: echo 'CMD_REMOTE_SETTING_CMD_BOX_UP_DATA' . PHP_EOL; // 远程设置参数,终端上报 (new \App\Servers\BoxSettingServer($param))->main($body); break; case \App\Maps\CmdMap::CMD_REMOTE_VOICE_DATA: echo 'CMD_REMOTE_VOICE_DATA' . PHP_EOL; //远程语音数据包,终端上传状态 (new \App\Servers\BoxPlayVoiceServer($param))->main($body); break; } // 发送数据 if (is_array($response_body)) { $response = (new \App\Servers\ResponseServer())->send($response_body, $response_cmd, $num_code); self::log($response, 'response', self::$LOG_DEV); Gateway::sendToCurrentClient(hex2bin(str_replace(' ', '', $response))); } } /** * 当用户断开连接时触发. * * @param int $client_id 连接id */ public static function onClose($client_id) { $box_no = $_SESSION['box_no']; $bike_no = $_SESSION['bike_no']; // 离线检查 if ($box_no && $bike_no && !Gateway::isUidOnline($box_no)) { self::log($box_no, 'EVENT_LINK_OFFLINE_ONCLOSE', self::$LOG_COMMON); self::$db->update('bikes')->where('box_no = ' . $box_no)->cols([ 'is_link' => \App\Maps\BikeMap::LINK_OFFLINE ])->query(); // 发出警告 self::warningLogBikeOffLineStatic($bike_no, $box_no, 'onClose'); self::$redis->set('bike:offline:' . $box_no, '1', 3600); } } }