From f99da99405a52383babc523d642bc63874e764e9 Mon Sep 17 00:00:00 2001 From: sa0ChunLuyu Date: Sun, 13 Aug 2023 14:50:42 +0800 Subject: [PATCH] feat:gateway --- app/Http/Controllers/GatewayController.php | 21 +++ composer.json | 3 +- composer.lock | 23 ++- gateway/.gitignore | 5 + gateway/Applications/Lib/Db.php | 139 ++++++++++++++++++ gateway/Applications/Lib/Db2.php | 42 ++++++ gateway/Applications/Lib/Tool.php | 88 +++++++++++ gateway/Applications/YourApp/Events.php | 98 ++++++++++++ .../YourApp/start_businessworker.php | 34 +++++ .../Applications/YourApp/start_gateway.php | 63 ++++++++ .../Applications/YourApp/start_register.php | 28 ++++ gateway/MIT-LICENSE.txt | 21 +++ gateway/README.md | 37 +++++ gateway/composer.json | 15 ++ gateway/start.bat | 2 + gateway/start.php | 37 +++++ routes/web.php | 1 + 17 files changed, 655 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/GatewayController.php create mode 100644 gateway/.gitignore create mode 100644 gateway/Applications/Lib/Db.php create mode 100644 gateway/Applications/Lib/Db2.php create mode 100644 gateway/Applications/Lib/Tool.php create mode 100644 gateway/Applications/YourApp/Events.php create mode 100644 gateway/Applications/YourApp/start_businessworker.php create mode 100644 gateway/Applications/YourApp/start_gateway.php create mode 100644 gateway/Applications/YourApp/start_register.php create mode 100644 gateway/MIT-LICENSE.txt create mode 100644 gateway/README.md create mode 100644 gateway/composer.json create mode 100644 gateway/start.bat create mode 100644 gateway/start.php diff --git a/app/Http/Controllers/GatewayController.php b/app/Http/Controllers/GatewayController.php new file mode 100644 index 0000000..046bcee --- /dev/null +++ b/app/Http/Controllers/GatewayController.php @@ -0,0 +1,21 @@ +post('client'); + return Yo::echo([ + 'client_id' => $client_id + ]); + } +} diff --git a/composer.json b/composer.json index af3759d..240db80 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "guzzlehttp/guzzle": "^7.2", "laravel/framework": "^10.10", "laravel/sanctum": "^3.2", - "laravel/tinker": "^2.8" + "laravel/tinker": "^2.8", + "workerman/gatewayclient": "^3.0" }, "require-dev": { "fakerphp/faker": "^1.9.1", diff --git a/composer.lock b/composer.lock index fe3a15c..b7c793b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aa322c53454393ed775cfe4807d54a50", + "content-hash": "bf594492c6a4c951789cc15ff31c1a5a", "packages": [ { "name": "brick/math", @@ -4146,6 +4146,27 @@ "validate" ], "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "workerman/gatewayclient", + "version": "v3.0.14", + "dist": { + "type": "zip", + "url": "https://mirrors.cloud.tencent.com/repository/composer/workerman/gatewayclient/v3.0.14/workerman-gatewayclient-v3.0.14.zip", + "reference": "4362468d68251015b2b385c310252afb4d6648ed", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "GatewayClient\\": "./" + } + }, + "license": [ + "MIT" + ], + "homepage": "http://www.workerman.net", + "time": "2021-11-29T07:03:50+00:00" } ], "packages-dev": [ diff --git a/gateway/.gitignore b/gateway/.gitignore new file mode 100644 index 0000000..1ec1a85 --- /dev/null +++ b/gateway/.gitignore @@ -0,0 +1,5 @@ +/vendor +composer.lock +/.idea +/.vscode + diff --git a/gateway/Applications/Lib/Db.php b/gateway/Applications/Lib/Db.php new file mode 100644 index 0000000..54f7213 --- /dev/null +++ b/gateway/Applications/Lib/Db.php @@ -0,0 +1,139 @@ +db = new \PDO($dsn, $data['dbuser'], $data['dbpassword']); + $this->db->query('set character set utf8mb4;'); + $this->db->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); + } + + public static function get($key = ''): Db + { + $database['dbname'] = Tool::ini($key . 'DB_DATABASE'); + $database['dbuser'] = Tool::ini($key . 'DB_USERNAME'); + $database['dbpassword'] = Tool::ini($key . 'DB_PASSWORD'); + $database['dbhost'] = Tool::ini($key . 'DB_HOST'); + if (!isset(self::$instance[$database['dbname']]) || !self::$instance[$database['dbname']] instanceof self) { + self::$instance[$database['dbname']] = new Db($database); + } else { + try { + //断线重连 + self::$instance[$database['dbname']]->db->getAttribute(\PDO::ATTR_SERVER_INFO); + } catch (\PDOException $e) { + if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) { + self::$instance[$database['dbname']] = new Db($database); + } + } + } + + return self::$instance[$database['dbname']]; + } + + + /*********PDO**********/ + public function count($sql, $parameters = null): int + { + return $this->exeupdate($sql, $parameters); + } + + public function querysql($sql, $parameters = null) + { + return $this->exeupdate($sql, $parameters); + } + + + public function querysqlinsertid($sql, $parameters = null) + { + if ($this->exeupdate($sql, $parameters)) { + return $this->db->lastInsertId(); + } else { + return 0; + } + } + + + public function getRow($sql, $parameters = null) + { + $res = $this->exequery($sql, $parameters); + if (count($res) > 0) { + + return $res[0]; + } else { + return array(); + } + } + + public function getAll($sql, $parameters = null) + { + $res = $this->exequery($sql, $parameters); + if (count($res) > 0) { + return $res; + } else { + return array(); + } + } + + public function beginTransaction() + { + $this->db->beginTransaction(); + } + + public function rollback() + { + $this->db->rollback(); + } + + public function commit() + { + $this->db->commit(); + } + + public function exequery($sql, $parameters = null) + { + $conn = $this->db; + $stmt = $conn->prepare($sql); + $stmt->execute($parameters); + $rs = $stmt->fetchall(\PDO::FETCH_ASSOC); + $stmt = null; + $conn = null; + return $rs; + } + + public function exeupdate($sql, $parameters = null) + { + $stmt = $this->db->prepare($sql); + $stmt->execute($parameters); + $affectedrows = $stmt->rowcount(); + $stmt = null; + $conn = null; + return $affectedrows; + } + + public function checklink() + { + $res = $this->db->getAttribute(\PDO::ATTR_SERVER_INFO); + if (strpos($res, 'server has gone away') !== false) { + $this->db = null; + return false; + } else { + return true; + } + } + + public function getinsertid() + { + return $this->db->lastInsertId(); + } + + public function close() + { + return $this->db = null; + } +} diff --git a/gateway/Applications/Lib/Db2.php b/gateway/Applications/Lib/Db2.php new file mode 100644 index 0000000..29890a6 --- /dev/null +++ b/gateway/Applications/Lib/Db2.php @@ -0,0 +1,42 @@ + $value) { + $sql .= "`{$key}`,"; + $sql1 .= "?,"; + $insertArr[] = $value; + } + $sql = trim($sql, ','); + $sql1 = trim($sql1, ','); + $sql .= ")" . $sql1 . ")"; + $db->querysql($sql, $insertArr); + return $db->getinsertid(); + } + + public static function u($db, $table, $array, $where, $where_a = []) + { + $updateArr = array(); + $sql = "update `{$table}` set "; + foreach ($array as $key => $value) { + $sql .= "`{$key}`=?,"; + $updateArr[] = $value; + } + $sql = trim($sql, ','); + $where = ' ' . $where; + $sql .= $where; + $updateArr = array_merge($updateArr, $where_a); + return $db->querysql($sql, $updateArr); + } + + public static function d($db, $table, $where, $where_a = []) + { + $sql = "delete from `{$table}` " . $where; + $db->querysql($sql, $where_a); + } +} diff --git a/gateway/Applications/Lib/Tool.php b/gateway/Applications/Lib/Tool.php new file mode 100644 index 0000000..ff12cc9 --- /dev/null +++ b/gateway/Applications/Lib/Tool.php @@ -0,0 +1,88 @@ + + * @copyright walkor + * @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); +require_once __DIR__ . '/../../Applications/Lib/Tool.php'; +require_once __DIR__ . '/../../Applications/Lib/Db.php'; +require_once __DIR__ . '/../../Applications/Lib/Db2.php'; +date_default_timezone_set(Tool::ini('TIMEZONE')); + +use \GatewayWorker\Lib\Gateway; + +/** + * 主逻辑 + * 主要是处理 onConnect onMessage onClose 三个方法 + * onConnect 和 onClose 如果不需要可以不用实现并删除 + */ +class Events +{ + /** + * 当客户端连接时触发 + * 如果业务不需此回调可以删除onConnect + * + * @param int $client_id 连接id + */ + public static function onConnect($client_id) + { + echo json_encode(['CONNECT', date('Y-m-d H:i:s'), $client_id], JSON_UNESCAPED_UNICODE) . "\n"; + Gateway::sendToClient($client_id, json_encode([ + 'action' => 'init', + 'client_id' => $client_id + ], JSON_UNESCAPED_UNICODE)); + } + + /** + * 当客户端发来消息时触发 + * @param int $client_id 连接id + * @param mixed $message 具体消息 + */ + public static function onMessage($client_id, $message) + { + // $db = Db::get(); + if ($message == Tool::ini('GATEWAY_PING')) { + echo json_encode(['PING', date('Y-m-d H:i:s'), $client_id], JSON_UNESCAPED_UNICODE) . "\n"; + Gateway::sendToClient($client_id, Tool::ini('GATEWAY_PANG')); + } + } + + /** + * 当用户断开连接时触发 + * @param int $client_id 连接id + */ + public static function onClose($client_id) + { + echo json_encode(['CLOSE', date('Y-m-d H:i:s'), $client_id], JSON_UNESCAPED_UNICODE) . "\n"; + if (!!Tool::ini('GATEWAY_CLOSE')) self::post(Tool::ini('APP_URL') . Tool::ini('GATEWAY_CLOSE'), ['client' => $client_id]); + } + + public static function post($url, $data, $type = 'json') + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_POST, true); + if ($type === 'data') { + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + } + if ($type === 'json') { + $data_string = json_encode($data, JSON_UNESCAPED_UNICODE); + curl_setopt($curl, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json; charset=utf-8', + 'Content-Length: ' . strlen($data_string) + ]); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); + } + $r = curl_exec($curl); + curl_close($curl); + return $r; + } +} diff --git a/gateway/Applications/YourApp/start_businessworker.php b/gateway/Applications/YourApp/start_businessworker.php new file mode 100644 index 0000000..9f16911 --- /dev/null +++ b/gateway/Applications/YourApp/start_businessworker.php @@ -0,0 +1,34 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use \Workerman\Worker; +use \GatewayWorker\BusinessWorker; + +// 自动加载类 +require_once __DIR__ . '/../../vendor/autoload.php'; +require_once __DIR__ . '/../../Applications/Lib/Tool.php'; +// bussinessWorker 进程 +$worker = new BusinessWorker(); +// worker名称 +$worker->name = Tool::ini("APP_NAME") . 'Business'; +// bussinessWorker进程数量 +$worker->count = 1; +// 服务注册地址 +$worker->registerAddress = '127.0.0.1:' . Tool::ini("GATEWAY_REGISTER"); + +// 如果不是在根目录启动,则运行runAll方法 +if (!defined('GLOBAL_START')) { + Worker::runAll(); +} + diff --git a/gateway/Applications/YourApp/start_gateway.php b/gateway/Applications/YourApp/start_gateway.php new file mode 100644 index 0000000..7b1cb78 --- /dev/null +++ b/gateway/Applications/YourApp/start_gateway.php @@ -0,0 +1,63 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use \Workerman\Worker; +use \GatewayWorker\Gateway; + +// 自动加载类 +require_once __DIR__ . '/../../vendor/autoload.php'; +require_once __DIR__ . '/../../Applications/Lib/Tool.php'; +// gateway 进程,这里使用Text协议,可以用telnet测试 +$url = 'websocket://0.0.0.0:' . Tool::ini('GATEWAY_PORT'); +$gateway = new Gateway($url); +// gateway名称,status方便查看 +$gateway->name = Tool::ini('APP_NAME'); +// gateway进程数 +$gateway->count = 1; +// 本机ip,分布式部署时使用内网ip +$gateway->lanIp = '127.0.0.1'; +// 内部通讯起始端口,假如$gateway->count=4,起始端口为4000 +// 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口 +$gateway->startPort = Tool::ini('GATEWAY_START'); +// 服务注册地址 +$gateway->registerAddress = '127.0.0.1:' . Tool::ini('GATEWAY_REGISTER'); + +// 心跳间隔 +$gateway->pingInterval = 60; +// 心跳数据 +$gateway->pingData = Tool::ini('GATEWAY_PING'); + +/* +// 当客户端连接上来时,设置连接的onWebSocketConnect,即在websocket握手时的回调 +$gateway->onConnect = function($connection) +{ + $connection->onWebSocketConnect = function($connection , $http_header) + { + // 可以在这里判断连接来源是否合法,不合法就关掉连接 + // $_SERVER['HTTP_ORIGIN']标识来自哪个站点的页面发起的websocket链接 + if($_SERVER['HTTP_ORIGIN'] != 'http://kedou.workerman.net') + { + $connection->close(); + } + // onWebSocketConnect 里面$_GET $_SERVER是可用的 + // var_dump($_GET, $_SERVER); + }; +}; +*/ + +// 如果不是在根目录启动,则运行runAll方法 +if (!defined('GLOBAL_START')) { + Worker::runAll(); +} + diff --git a/gateway/Applications/YourApp/start_register.php b/gateway/Applications/YourApp/start_register.php new file mode 100644 index 0000000..bb760dd --- /dev/null +++ b/gateway/Applications/YourApp/start_register.php @@ -0,0 +1,28 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use \Workerman\Worker; +use \GatewayWorker\Register; + +// 自动加载类 +require_once __DIR__ . '/../../vendor/autoload.php'; +require_once __DIR__ . '/../../Applications/Lib/Tool.php'; +// register 必须是text协议 +$register = new Register('text://0.0.0.0:' . Tool::ini('GATEWAY_REGISTER')); + +// 如果不是在根目录启动,则运行runAll方法 +if (!defined('GLOBAL_START')) { + Worker::runAll(); +} + diff --git a/gateway/MIT-LICENSE.txt b/gateway/MIT-LICENSE.txt new file mode 100644 index 0000000..fd6b1c8 --- /dev/null +++ b/gateway/MIT-LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2009-2015 walkor and contributors (see https://github.com/walkor/workerman/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/gateway/README.md b/gateway/README.md new file mode 100644 index 0000000..b6a43a5 --- /dev/null +++ b/gateway/README.md @@ -0,0 +1,37 @@ +GatewayClient +================= +`composer install` + +`composer require workerman/gatewayclient` + +```php +use GatewayClient\Gateway; + +Gateway::$registerAddress = '127.0.0.1:3238'; + +Gateway::bindUid($client_id, $uid); +Gateway::joinGroup($client_id, $group_id); + +Gateway::sendToUid($uid, $message); +Gateway::sendToGroup($group, $message); + +Gateway::sendToAll($data); +Gateway::sendToClient($client_id, $data); +Gateway::closeClient($client_id); +Gateway::isOnline($client_id); +Gateway::bindUid($client_id, $uid); +Gateway::isUidOnline($uid); +Gateway::getClientIdByUid($uid); +Gateway::unbindUid($client_id, $uid); +Gateway::sendToUid($uid, $data); +Gateway::joinGroup($client_id, $group); +Gateway::sendToGroup($group, $data); +Gateway::leaveGroup($client_id, $group); +Gateway::getClientCountByGroup($group); +Gateway::getClientSessionsByGroup($group); +Gateway::getAllClientCount(); +Gateway::getAllClientSessions(); +Gateway::setSession($client_id, $session); +Gateway::updateSession($client_id, $session); +Gateway::getSession($client_id); +``` \ No newline at end of file diff --git a/gateway/composer.json b/gateway/composer.json new file mode 100644 index 0000000..4e90c94 --- /dev/null +++ b/gateway/composer.json @@ -0,0 +1,15 @@ +{ + "name" : "workerman/gateway-worker-demo", + "keywords": ["distributed","communication"], + "homepage": "http://www.workerman.net", + "license" : "MIT", + "require": { + "workerman/gateway-worker" : ">=3.0.0" + }, + "autoload": { + "psr-4": { + "" : "./", + "" : "./Applications/YourApp/" + } + } +} diff --git a/gateway/start.bat b/gateway/start.bat new file mode 100644 index 0000000..14bd09f --- /dev/null +++ b/gateway/start.bat @@ -0,0 +1,2 @@ +php Applications\YourApp\start_register.php Applications\YourApp\start_gateway.php Applications\YourApp\start_businessworker.php +pause \ No newline at end of file diff --git a/gateway/start.php b/gateway/start.php new file mode 100644 index 0000000..410c580 --- /dev/null +++ b/gateway/start.php @@ -0,0 +1,37 @@ +