diff --git a/app/Console/Commands/GatewayWorkerServer.php b/app/Console/Commands/GatewayWorkerServer.php new file mode 100644 index 0000000..340d58c --- /dev/null +++ b/app/Console/Commands/GatewayWorkerServer.php @@ -0,0 +1,113 @@ +argument('action'); + if (!in_array($action, ['start', 'stop', 'restart', 'reload', 'status'])) { + exit('Arguments Error'); + } + + $argv[0] = 'artisan gateway-worker'; + $argv[1] = $action; + $argv[2] = $this->option('d') ? '-d' : ''; //必须是一个-,上面定义命令两个--,后台启动用两个-- + + $this->start(); + } + + private function start() + { + $this->startGateWay(); + $this->startBusinessWorker(); + $this->startRegister(); + Worker::runAll(); + } + + private function startBusinessWorker() + { + $worker = new BusinessWorker(); + $worker->name = 'BusinessWorker'; + $worker->count = 1; + $worker->registerAddress = '127.0.0.1:1236'; + $worker->eventHandler = \App\GatewayWorker\Events::class; //设置使用哪个类来处理业务,业务类至少要实现onMessage静态方法,onConnect和onClose静态方法可以不用实现 + } + + private function startGateWay() + { + $gateway = new Gateway("websocket://0.0.0.0:2346"); + $gateway->name = 'Gateway'; //设置BusinessWorker进程的名称 + $gateway->count = 1; //设置BusinessWorker进程的数量 + $gateway->lanIp = '127.0.0.1'; #内网ip,多服务器分布式部署的时候需要填写真实的内网ip + $gateway->startPort = 2300; //监听本机端口的起始端口 + $gateway->pingInterval = 30; //心跳间隔时间(秒) + $gateway->pingNotResponseLimit = 0; //心跳检测的时间间隔数 + $gateway->pingData = '{"type":"ping"}'; //心跳消息 + $gateway->registerAddress = '127.0.0.1:1236'; //注册服务地址 + } + + private function startRegister() + { + new Register('text://0.0.0.0:1236'); + } + + private function init() + { + + } + + //php artisan gateway-worker start --d之后,打开浏览器F12将内容复制到console里return就行 + /* ws = new WebSocket("ws://127.0.0.1:2346?token=123456"); + ws.onopen = function() { + ws.send('{"name":"one","user_id":"111"}'); + ws.send('{"name":"two","user_id":"222"}'); + //定义一个定时器,每10秒钟发送一个包,包的内容随意,一般发送心跳包的间隔在60秒以内 + setInterval(function () { + ws.send('{"type":"heart","msg":"Heartbeat reply"}'); + }, 10000); + }; + ws.onmessage = function(e) { + console.log("收到服务端的消息:" + e.data); + }; + ws.onclose = function(e) { + console.log("服务已断开" ); + }; */ +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index ceb97c0..031920d 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -6,6 +6,7 @@ use DB; use Log; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use App\Console\Commands\GatewayWorkerServer; class Kernel extends ConsoleKernel { @@ -15,6 +16,7 @@ class Kernel extends ConsoleKernel * @var array */ protected $commands = [ + GatewayWorkerServer::class, Commands\UnpayOrderSetInvalid::class, Commands\SendEmail::class, ]; diff --git a/app/GatewayWorker/Events.php b/app/GatewayWorker/Events.php new file mode 100644 index 0000000..11155c1 --- /dev/null +++ b/app/GatewayWorker/Events.php @@ -0,0 +1,129 @@ + 'onConnect', 'client_id' => $client_id])); + } + + /** + * 当客户端连接上gateway完成websocket握手时触发的回调函数 + * 注意:此回调只有gateway为websocket协议并且gateway没有设置onWebSocketConnect时才有效 + * @param int $client_id + * @param mixed $data websocket握手时的http头数据,包含get、server等变量 + */ + public static function onWebSocketConnect($client_id, $data) + { + Log::info('onWebSocketConnect,client_id:' . $client_id . '-' . json_encode($data)); + echo "onWebSocketConnect\r\n"; + if (!isset($data['get']['token'])) { + echo "closeClient\r\n"; + return Gateway::closeClient($client_id); + } + $access_token = $data['get']['token']; + //通过client_id绑定用户ID + $res = self::bing_client($client_id, ['access_token' => $access_token]); + if ($res['code'] != ReturnData::SUCCESS) { + return Gateway::sendToClient($client_id, json_encode($res)); + } + Gateway::sendToClient($client_id, json_encode(ReturnData::create(ReturnData::SUCCESS))); + } + + /** + * 有消息时 + * @param int $client_id 发消息的client_id + * @param mixed $message 完整的客户端请求数据,数据类型取决于Gateway所使用协议的decode方法返的回值类型 + */ + public static function onMessage($client_id, $data) + { + echo "onMessage\r\n"; + // Debug输出 + echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']} client_id:$client_id session:" . json_encode($_SESSION) . " onMessage:" . $message . "\n"; + + // data = {"type":"login", "uid":"666"} + $data = json_decode($data, true); + Log::info('onMessage,client_id:' . $client_id . '-' . json_encode($data)); + + // 没有传消息类型视为非法请求,关闭连接 + if (!isset($data['type'])) { + return Gateway::closeClient($client_id); + } + + $uid = Gateway::getUidByClientId($client_id); + + // 判断绑定的UID为空,消息类型不是心跳视为非法请求,关闭连接 + if (empty($uid) && $data['type'] !== 'heart') { + return Gateway::closeClient($client_id); + } + + switch ($data['type']) { + case 'heart': //心跳回复 + Gateway::sendToCurrentClient(json_encode(ReturnData::create(ReturnData::SUCCESS))); + break; + default: + Gateway::sendToCurrentClient(json_encode(ReturnData::create(ReturnData::PARAMS_ERROR))); + } + } + + /** + * 当客户端断开连接时 + * @param integer $client_id 断开连接的客户端client_id + * @return void + */ + public static function onClose($client_id) + { + // debug + echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']} client_id:$client_id onClose:''\n"; + + Log::info('Workerman close connection,client_id:' . $client_id); + echo "onClose\r\n"; + } + + /** + * 通过client_id绑定用户ID + * @param int $client_id + * @param mixed $message ['access_token'] + */ + public static function bing_client($client_id, $message) + { + if (!Gateway::isOnline($client_id)) { + return ReturnData::create(ReturnData::PARAMS_ERROR, null, 'client_id错误'); + } + + //client_id绑定用户ID + $token = DB::table('token')->where(['token' => $message['access_token']])->first(); + if (!$token) { + return ReturnData::create(ReturnData::PARAMS_ERROR, null, '鉴权失败'); + } + Gateway::bindUid($client_id, $token->uid); + + return ReturnData::create(ReturnData::SUCCESS); + } + +} diff --git a/app/Http/Controllers/Admin/AdController.php b/app/Http/Controllers/Admin/AdController.php index dbf4aa3..248e17d 100644 --- a/app/Http/Controllers/Admin/AdController.php +++ b/app/Http/Controllers/Admin/AdController.php @@ -1,6 +1,6 @@ =5.6.4", + "intervention/image": "^2.3", + "jpush/jpush": "v3.5.*", "laravel/framework": "5.4.*", "laravel/tinker": "~1.0", - "predis/predis": "^1.1", "maatwebsite/excel": "~2.1.0", - "simplesoftwareio/simple-qrcode": "~1", - "intervention/image": "^2.3", - "yansongda/pay": "^1.0", "overtrue/laravel-wechat": "~3.1", - "jpush/jpush": "v3.5.*" + "predis/predis": "^1.1", + "simplesoftwareio/simple-qrcode": "~1", + "workerman/gateway-worker": "^3.0", + "yansongda/pay": "^1.0" }, "require-dev": { "fzaninotto/faker": "~1.4",