├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── src ├── App │ ├── Application.php │ ├── Bootstrap │ │ ├── LoadConfig.php │ │ └── ServerPrivoder.php │ └── README.md ├── Config │ ├── Config.php │ └── README.md ├── Consul │ ├── Agent.php │ ├── Consul.php │ ├── ConsulServerPriovder.php │ ├── KeyValue.php │ └── README.md ├── Container │ ├── Container.php │ └── README.md ├── Database │ ├── DB.php │ ├── DatabaseServerPriovder.php │ ├── Driver │ │ ├── MysqlDriverPdo.php │ │ ├── MysqlDriverPool.php │ │ └── MysqlPoolManager.php │ └── README.md ├── Event │ ├── Event.php │ ├── EventServerPriovder.php │ ├── Listener.php │ └── README.md ├── Help │ ├── ColorString.php │ ├── Debug.php │ └── Function.php ├── Priovder │ ├── PriovderInterface.php │ └── README.md ├── README.md ├── Routes │ ├── README.php │ ├── Route.php │ └── RouteServerPriovder.php ├── Rpc │ ├── Proxy.php │ ├── README.md │ ├── RpcClient.php │ ├── RpcServer.php │ └── RpcServerPriovder.php └── SwooleServer │ ├── Http │ ├── HttpRequest.php │ └── HttpServer.php │ ├── README.md │ ├── Reponse.php │ └── ServerBase.php └── tests └── ApplicationTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | composer.lock 4 | vendor -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 libin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Darts Library 2 | 3 | ## 概述 4 | 5 | Library 类库 6 | 7 | ## Label 8 | 9 | [](https://github.com/jefferyjob/dartswoole/issues) 10 | [](https://github.com/jefferyjob/dartswoole) 11 | [](https://github.com/jefferyjob/dartswoole) 12 | [](https://github.com/jefferyjob/dartswoole/blob/master/LICENSE) 13 | 14 | 15 | ## Framework 16 | 17 | https://github.com/jefferyjob/darts 18 | 19 | ## 提供支持 20 | 21 | - 路由的解析与处理 22 | - event事件的绑定与处理 23 | - Swoole的http服务的实现 24 | - 基于consule实现独立的RPC服务 25 | - 基于Swoole实现RPC客户端和服务端 26 | - 数据库的Pool连接池的操作支持 27 | 28 | ## 目录简介 29 | 30 | ```text 31 | src 32 | -----App-----------------核心服务 33 | -----Container-----------容器服务 34 | -----Priovder------------服务提供者抽象类定义 35 | -----Config--------------配置解析处理 36 | -----Help----------------类库的调试帮助函数 37 | -----Event---------------事件绑定的解析与处理 38 | -----Database------------数据库支持 39 | -----Routes--------------路由解析与处理 40 | -----Consul--------------consul实现RPC服务 41 | -----Rpc-----------------RPC服务实现 42 | -----SwooleServer--------swoole实现http等服务 43 | test 44 | -----xxxxxx--------------测试文件 45 | ``` 46 | 47 | ## License 48 | 49 | 遵循 MIT 许可证,有关详细,请参阅 LICENSE。 50 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jefferyjob/dartswoole", 3 | "description": "Darts Framework Libary", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "libin", 9 | "email": "libinjob@163.com" 10 | } 11 | ], 12 | "autoload": { 13 | "psr-4": { 14 | "Dartswoole\\": "src" 15 | }, 16 | "files": [ 17 | "src/Help/Debug.php", 18 | "src/Help/Function.php" 19 | ] 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Dartswoole\\Test\\": "tests" 24 | } 25 | }, 26 | "minimum-stability": "dev", 27 | "repositories": { 28 | "packagist": { 29 | "type": "composer", 30 | "url": "https://mirrors.aliyun.com/composer/" 31 | } 32 | }, 33 | "require": { 34 | "php": ">=7.0" 35 | }, 36 | "require-dev": { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/App/Application.php: -------------------------------------------------------------------------------- 1 | setBasePath($path); 37 | } 38 | 39 | // logo 展示 40 | Debug::info("========================\n====== DartSwoole ======\n========================"); 41 | 42 | // 将当前类创建单例 43 | self::setInstance($this); 44 | // 加载框架驱动 45 | $this->bootstrap(); 46 | 47 | // 启动成功的文本输出 48 | echo ColorString::getColoredString("Dartswoole Library 启动成功", 'yellow').PHP_EOL.PHP_EOL; 49 | } 50 | 51 | /** 52 | * 服务器启动处理php-cli命令 53 | * 54 | * @param $argv string php-cli传递的参数 55 | */ 56 | public function run($argv){ 57 | $cli = $argv[1] ?? null; 58 | switch (strtolower($cli)) { 59 | // http 服务 60 | case 'http:start': 61 | $server = new \Dartswoole\SwooleServer\Http\HttpServer($this); 62 | break; 63 | 64 | // 错误的服务名称 65 | default: 66 | Debug::error("Command input error"); 67 | } 68 | 69 | // 判断是否启动 RPC 70 | if($this->make('config')->get('rpc_server.flag')) 71 | { 72 | new RpcServer($this, $server); 73 | } 74 | 75 | // 服务启动 76 | $server->start(); 77 | } 78 | 79 | /** 80 | * 加载框架的核心启动类 81 | */ 82 | public function bootstrap(){ 83 | foreach ($this->bootstraps as $key => $bootstrap) { 84 | (new $bootstrap())->bootstrap($this); 85 | } 86 | } 87 | 88 | public function getConfigPath() 89 | { 90 | return $this->getBasePath()."/config"; 91 | } 92 | 93 | public function setBasePath($path) 94 | { 95 | $this->basePath = rtrim($path, '\/'); 96 | } 97 | public function getBasePath() 98 | { 99 | return $this->basePath; 100 | } 101 | } -------------------------------------------------------------------------------- /src/App/Bootstrap/LoadConfig.php: -------------------------------------------------------------------------------- 1 | getConfigPath()); 22 | //Debug::dd($config); 23 | 24 | // 将darts得到的配置服务,与处理配置文件的类绑定 25 | $app->bind('config', new Config($app->getConfigPath())); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/App/Bootstrap/ServerPrivoder.php: -------------------------------------------------------------------------------- 1 | make('config')->get('dartswoole.priovders'); 16 | 17 | // 服务注册 register 18 | foreach ($priovders as $key => $priovder) { 19 | (new $priovder($app))->register(); 20 | } 21 | // 服务启动 boot 22 | foreach ($priovders as $key => $priovder) { 23 | (new $priovder($app))->boot(); 24 | } 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/App/README.md: -------------------------------------------------------------------------------- 1 | # Application.php 2 | 3 | 框架核心启动类 -------------------------------------------------------------------------------- /src/Config/Config.php: -------------------------------------------------------------------------------- 1 | itmes = $this->phpParser($dir); 22 | } 23 | 24 | /** 25 | * 读取路径下所有的php文件 26 | * 27 | * @param $dir string 配置文件的文件夹路径 28 | * @return array 文件信息 29 | */ 30 | protected function phpParser($dir) 31 | { 32 | // 判断文件夹是否存在 33 | if(!is_dir($dir)) { 34 | return; 35 | //throw new Exception("Not Found Dir Of Config Dic ({$dir})", 500); 36 | } 37 | // 读取文件夹下的文件 38 | $files = scandir($dir); 39 | 40 | $data = array(); 41 | foreach ($files as $key => $file) { 42 | if ($file === '.' || $file === '..') { 43 | continue; 44 | } 45 | // 获取文件名 46 | $filename = stristr($file, ".php", true); 47 | 48 | // 读取文件内容信息 49 | $data[$filename] = include $dir."/".$file; 50 | } 51 | return $data; 52 | } 53 | 54 | /** 55 | * 返回配置文件的定义值 56 | * 57 | * @param $keys string demo:key1.key2.key3 58 | * @return array|mixed 定义值 59 | */ 60 | public function get($keys) 61 | { 62 | $data = $this->itmes; 63 | foreach (explode('.', $keys) as $key => $value) { 64 | if(!isset($data[$value])) { 65 | Debug::error($keys." Not Found"); 66 | } 67 | $data = $data[$value]; 68 | } 69 | return $data; 70 | } 71 | } -------------------------------------------------------------------------------- /src/Config/README.md: -------------------------------------------------------------------------------- 1 | # 配置文件处理类 -------------------------------------------------------------------------------- /src/Consul/Agent.php: -------------------------------------------------------------------------------- 1 | consul = $consul; 19 | } 20 | 21 | /** 22 | * 获取所有的服务 23 | * 24 | * @return mixed 25 | */ 26 | public function services() { 27 | return $this->consul->get('/v1/agent/services'); 28 | } 29 | 30 | /** 31 | * 获取健康的服务 32 | * 33 | * @param $consul_name string 服务名称 34 | */ 35 | public function health($consul_name) { 36 | return $this->consul->get("/v1/health/service/{$consul_name}?passing=true"); 37 | } 38 | 39 | /** 40 | * 注册服务 41 | * 42 | * @param array $service 43 | * @return mixed 44 | */ 45 | public function registerService(array $service) 46 | { 47 | return $this->consul->put('/v1/agent/service/register', array( 48 | 'body' => $service 49 | )); 50 | } 51 | 52 | /** 53 | * 注销服务 54 | * 55 | * @param string $service_id 56 | * @return mixed 57 | */ 58 | public function deregisterService(string $service_id) 59 | { 60 | return $this->consul->put('/v1/agent/service/deregister/' . $service_id); 61 | } 62 | } -------------------------------------------------------------------------------- /src/Consul/Consul.php: -------------------------------------------------------------------------------- 1 | host = $host; 26 | $this->port = $port; 27 | } 28 | 29 | /** 30 | * request 请求 31 | * 32 | * @param $method string 请求方法 33 | * @param $uri string 请求地址 34 | * @param null|array $options 请求参数 35 | * 36 | * wiki:https://wiki.swoole.com/#/coroutine_client/http_client 37 | */ 38 | private function request($method, $uri, $options = null) 39 | { 40 | $client = new Client($this->host, $this->port); 41 | $client->set(['timeout' => 1]); 42 | $client->setMethod($method); 43 | if($options) { 44 | $client->setData(json_encode($options['body'])); 45 | } 46 | $client->execute($uri); 47 | 48 | // 获取返回 49 | $headers = $client->headers; 50 | $statusCode = $client->statusCode; 51 | $body = $client->body; 52 | 53 | $client->close(); 54 | 55 | if($statusCode != 200) { 56 | throw new \Exception("Consul bind faild. ".json_encode(array( 57 | 'host' => $this->host, 58 | 'port' => $this->port, 59 | 'statusCode' => $statusCode, 60 | )), 500); 61 | } 62 | 63 | return self::response($headers, $body, $statusCode); 64 | } 65 | 66 | /** 67 | * 返回数据处理 68 | * 69 | * @param array $header header头 70 | * @param string $body 返回内容 71 | * @param int $statuc 状态 72 | */ 73 | public function response(array $header, string $body, int $status = 200) 74 | { 75 | if (empty($body)) { 76 | return $body; 77 | } 78 | return json_decode($body, true); 79 | } 80 | 81 | public function get(string $url = null, array $options = []) 82 | { 83 | return $this->request('GET', $url, $options); 84 | } 85 | 86 | public function delete(string $url, array $options = []) 87 | { 88 | return $this->request('DELETE', $url, $options); 89 | } 90 | 91 | public function put(string $url, array $options = []) 92 | { 93 | return $this->request('PUT', $url, $options); 94 | } 95 | 96 | public function patch(string $url, array $options = []) 97 | { 98 | return $this->request('PATCH', $url, $options); 99 | } 100 | 101 | public function post(string $url, array $options = []) 102 | { 103 | return $this->request('POST', $url, $options); 104 | } 105 | 106 | public function options(string $url, array $options = []) 107 | { 108 | return $this->request('OPTIONS', $url, $options); 109 | } 110 | } -------------------------------------------------------------------------------- /src/Consul/ConsulServerPriovder.php: -------------------------------------------------------------------------------- 1 | app->make('config'); 11 | 12 | // 注册 consule 的 Services 服务 13 | $this->app->bind('consul-agent', new Agent( 14 | new Consul($config->get('consul.app.host'), $config->get('consul.app.port')) 15 | )); 16 | 17 | // 注册 consule 的 Key/Value 服务 18 | $this->app->bind('consul-kv', new KeyValue( 19 | new Consul($config->get('consul.app.host'), $config->get('consul.app.port')) 20 | )); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Consul/KeyValue.php: -------------------------------------------------------------------------------- 1 | consul = $consul; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Consul/README.md: -------------------------------------------------------------------------------- 1 | # Consul 2 | 3 | consul 主要提供两大服务,分别是: 4 | 5 | - Service 6 | - Key/Value 7 | 8 | ## ConsulServerPriovder.php 9 | 10 | - 注册 consule 服务 11 | 12 | ## Consul.php 13 | 14 | - 用于定义 consul 的服务 15 | - 定义各种请求的方法实现 16 | 17 | ## Agent.php 18 | 19 | - 实现 consul 的 Service 服务 20 | 21 | ## KeyValue.php 22 | 23 | - 实现 consul 的 Key/Value 服务 24 | 25 | -------------------------------------------------------------------------------- /src/Container/Container.php: -------------------------------------------------------------------------------- 1 | bindings[$abstract] = $object; 33 | } 34 | 35 | /** 36 | * 从bind容器中解析服务 37 | * 38 | * @param $abstract {abstract} 抽象类的类名 39 | * @param array $parameters 服务名称 40 | */ 41 | public function make($abstract, $parameters = []) { 42 | // 通过抽象类的名称返回实体对象object 43 | if (isset($this->instances[$abstract])) { 44 | return $this->instances[$abstract]; 45 | } 46 | 47 | // 判断object不存在容器中 48 | if (!$this->has($abstract)) { 49 | throw new Exception("Not Found Container Object ({$abstract})", 500); 50 | } 51 | 52 | // 取出object 53 | $object = $this->bindings[$abstract]; 54 | 55 | // 判断是否为闭包 56 | if ($object instanceof \Closure) { 57 | return $object; 58 | } 59 | 60 | return $this->instances[$abstract] = (is_object($object)) ? $object : new $object(...$parameters) ; 61 | } 62 | 63 | /** 64 | * 判断object是否存在于容器中 65 | * 66 | * @param $abstract 67 | * @return bool 68 | */ 69 | public function has($abstract) 70 | { 71 | return isset($this->bindings[$abstract]); 72 | } 73 | 74 | /** 75 | * 创建单例模式 76 | * 77 | * @param null $container 78 | * @return mixed|null 79 | */ 80 | public static function setInstance($container = null) 81 | { 82 | return static::$instance = $container; 83 | } 84 | 85 | /** 86 | * 获取单例模式 87 | * 88 | * @return mixed 89 | */ 90 | public static function getInstance() 91 | { 92 | if (is_null(static::$instance)) { 93 | static::$instance = new static; 94 | } 95 | return static::$instance; 96 | } 97 | } -------------------------------------------------------------------------------- /src/Container/README.md: -------------------------------------------------------------------------------- 1 | # 容器服务 2 | 3 | -------------------------------------------------------------------------------- /src/Database/DB.php: -------------------------------------------------------------------------------- 1 | mysql 27 | $driver = app("config")->get("database.driver"); 28 | 29 | // 使用DB驱动必须是mysql 30 | if($driver != 'mysql') { 31 | throw new \Exception("Database driver must be 'mysql'", 500); 32 | } 33 | 34 | // 从容器中获取 mysql 35 | return app($driver); 36 | } 37 | 38 | /** 39 | * DB 调用数据库 40 | * 41 | * @param $method string 请求方法 42 | * @param $args mixed 请求参数 43 | * @return mixed 44 | */ 45 | static public function __callStatic($method, $args) 46 | { 47 | // 一键协程化 48 | Runtime::enableCoroutine(); 49 | 50 | // 定义管道 51 | $channel = new Channel(1); 52 | 53 | // 协程调用 54 | Coroutine::create(function () use ($channel, $method, $args) { 55 | 56 | // pdo 方式 57 | //$pdo = new MysqlDriverPdo; 58 | 59 | // pool 连接池方式 60 | $pdo = self::getDriver(); 61 | 62 | $return = $pdo->{$method}(...$args); 63 | $channel->push($return); 64 | 65 | }); 66 | 67 | // 获取sql结果 68 | return $channel->pop(); 69 | } 70 | } -------------------------------------------------------------------------------- /src/Database/DatabaseServerPriovder.php: -------------------------------------------------------------------------------- 1 | app->bind('mysql',new MysqlDriverPdo()); 38 | 39 | // mysql-pool-服务绑定 40 | $this->app->bind('mysql',new MysqlDriverPool(new MysqlPoolManager($this->app))); 41 | 42 | // redis 服务绑定 ... 43 | //$this->app->bind('redis', ...); 44 | } 45 | } -------------------------------------------------------------------------------- /src/Database/Driver/MysqlDriverPdo.php: -------------------------------------------------------------------------------- 1 | get("database.mysql"); 26 | 27 | try { 28 | // 初始化执行数据库类 29 | $this->pdo = new PDO("mysql:host={$config['host']};dbname={$config['database']}", $config['username'], $config['password']); 30 | $this->pdo->query('SET NAMES UTF8'); 31 | $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 32 | } catch (PDOException $e) { 33 | // throw new \Exception($e->getMessage(), 500); 34 | return $e->getMessage(); 35 | } 36 | } 37 | 38 | /** 39 | * 读操作 40 | * 41 | * @param $sql string sql语句 42 | * @return string|array 43 | */ 44 | public function query($sql) 45 | { 46 | try { 47 | $result = $this->pdo->query($sql); 48 | $data = []; 49 | foreach($result as $key => $value){ 50 | $data[] = $value; 51 | } 52 | return $data; 53 | } catch (PDOException $e) { 54 | return $e->getMessage(); 55 | } 56 | } 57 | 58 | public function call($sql, $select_param = null) 59 | { 60 | $stmt = $this->pdo->prepare($sql); 61 | if ($stmt->execute()) { 62 | if (isset($select_param)) { 63 | return $this->pdo->query($select_param)->fetchAll(); 64 | } 65 | return true; 66 | } else { 67 | return false; 68 | } 69 | } 70 | 71 | /** 72 | * 写操作 73 | * 74 | * @param $sql string sql语句 75 | * @return string 76 | */ 77 | public function execute($sql) 78 | { 79 | try { 80 | return $this->pdo->exec($sql); 81 | } catch (PDOException $e) { 82 | return $e->getMessage(); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/Database/Driver/MysqlDriverPool.php: -------------------------------------------------------------------------------- 1 | pool = $pool; 22 | } 23 | 24 | /** 25 | * 获取连接池中的某一个连接 26 | * 27 | * @return mixed 28 | */ 29 | public function connection() 30 | { 31 | return $this->pool->get(); 32 | } 33 | 34 | /** 35 | * 回收连接 36 | * 37 | * @param $pdo 38 | */ 39 | public function put($pdo) 40 | { 41 | $this->pool->put($pdo); 42 | } 43 | 44 | /** 45 | * 读操作 46 | * 47 | * @param $sql string sql语句 48 | * @return string|array 49 | */ 50 | public function query($sql) 51 | { 52 | try { 53 | // 获取连接 54 | $pdo = $this->connection(); 55 | 56 | // 执行查询 57 | $return = $pdo->query($sql)->fetchAll();// fetch 或 fetchAll() 58 | 59 | // 回收连接 60 | $this->put($pdo); 61 | 62 | return $return; 63 | } catch (PDOException $e) { 64 | // 程序异常 连接池重置 65 | $this->put(null); 66 | return $e->getMessage(); 67 | } 68 | } 69 | 70 | public function call($sql, $select_param = null) 71 | { 72 | $stmt = $this->pdo->prepare($sql); 73 | if ($stmt->execute()) { 74 | if (isset($select_param)) { 75 | return $this->pdo->query($select_param)->fetchAll(); 76 | } 77 | return true; 78 | } else { 79 | return false; 80 | } 81 | } 82 | 83 | /** 84 | * 写操作 85 | * 86 | * @param $sql string sql语句 87 | * @return string 88 | */ 89 | public function execute($sql) 90 | { 91 | try { 92 | return $this->pdo->exec($sql); 93 | } catch (PDOException $e) { 94 | return $e->getMessage(); 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /src/Database/Driver/MysqlPoolManager.php: -------------------------------------------------------------------------------- 1 | app = $app; 36 | $this->config = $app->make("config"); 37 | $this->init(); 38 | } 39 | 40 | /** 41 | * 初始化数据库连接池 42 | * 43 | * 连接池wiki:https://wiki.swoole.com/#/coroutine/conn_pool 44 | */ 45 | private function init() 46 | { 47 | // 连接配置 48 | $config = (new PDOConfig) 49 | ->withHost($this->config->get("database.mysql.host")) 50 | ->withPort($this->config->get("database.mysql.port")) 51 | ->withDbName($this->config->get("database.mysql.database")) 52 | ->withUsername($this->config->get("database.mysql.username")) 53 | ->withPassword($this->config->get("database.mysql.password")); 54 | 55 | // 连接池创建 56 | $this->pool = new PDOPool($config, $this->config->get("database.mysql.pool.size")); 57 | } 58 | 59 | /** 60 | * 获取连接 61 | * 62 | * @return mixed 63 | * 连接池未满时会创建新的连接 64 | */ 65 | public function get() { 66 | return $this->pool->get(); 67 | } 68 | 69 | /** 70 | * 回收连接 71 | * 72 | * @param $pdo 73 | * @return mixed 74 | */ 75 | public function put($pdo) { 76 | return $this->pool->put($pdo); 77 | } 78 | 79 | /** 80 | * 重置连接 81 | * 82 | * @return mixed 83 | * 连接异常,需要重置连接池,归还一个空连接以保证连接池的数量平衡 84 | * 85 | * wiki:https://wiki.swoole.com/#/coroutine/conn_pool?id=database 86 | */ 87 | public function resetPut() { 88 | return $this->pool->put(null); 89 | } 90 | } -------------------------------------------------------------------------------- /src/Database/README.md: -------------------------------------------------------------------------------- 1 | # Databases数据库支持 2 | 3 | ## 目录简介 4 | 5 | ```text 6 | DatabaseServerPriovder.php---------数据库服务注册和启动 7 | DB.php-----------------------------DB调用数据的静态封装 8 | Driver 9 | -----MysqlPoolManager.php----------mysql连接池的创建和管理 10 | -----MysqlDriverPool.php-----------基于连接池操作数据库的类 11 | -----MysqlDriverPdo.php------------基于mysql-pdo原生操作数据库的类 12 | ``` 13 | 14 | ## 为什么真实连接大于配置的数据库连接数量 15 | 16 | 在对数据库压测过程中,我们用 `SHOW PROCESSLIST;` 查看数据库的连接数量,会发现真实的连接远大于在配置文件中对于连接池的配置。 17 | 因为在服务器中,darts 项目启动后,会根据服务器的核心数,启动对应数量的 [Worker](https://wiki.swoole.com/#/server/setting?id=worker_num) 进程,而每个 `Worker` 进程是相互独立的,如果服务器的核心数是 s,数据库进程池中配置的数量是 n,那么查询连接数是 s*n。服务器中查看 Worker 进程的命令是:`pstree -ap | grep darts` 18 | -------------------------------------------------------------------------------- /src/Event/Event.php: -------------------------------------------------------------------------------- 1 | events[$flag] = array( 22 | 'callback' => $callback 23 | ); 24 | } 25 | 26 | /** 27 | * 触发事件 28 | * 29 | * @param $flag 30 | * @param array $params 31 | * @return bool 32 | */ 33 | public function trigger($flag, $params = []) 34 | { 35 | $flag = strtolower($flag); 36 | 37 | if(isset($this->events[$flag])) { 38 | ($this->events[$flag]['callback'])(...$params); 39 | return true; 40 | } 41 | } 42 | 43 | /** 44 | * 获取所有事件 45 | */ 46 | public function getEvents() 47 | { 48 | return $this->events; 49 | } 50 | } -------------------------------------------------------------------------------- /src/Event/EventServerPriovder.php: -------------------------------------------------------------------------------- 1 | app->make('config'); 18 | 19 | // 根据 frame 中 app/config/event.php 20 | // 中 Listeners 的配置加载事件 21 | $this->registerListeners($event, $config); 22 | // 根据 frame 中 app/config/event.php 23 | // 中 event 的配置加载事件 24 | $this->registerEvents($event, $config); 25 | 26 | $this->app->bind('event', $event); 27 | 28 | //Debug::dd($this->app->make('event')->getEvents()); 29 | } 30 | 31 | /** 32 | * 根据 frame 中 app/config/event.php 33 | * 中 Listeners 的配置加载事件 34 | * 35 | * @param Event $event 36 | * @param Config $config 37 | */ 38 | public function registerListeners(Event $event, Config $config) 39 | { 40 | $listeners = $config->get('event.listeners'); 41 | 42 | foreach ($listeners as $key => $listener) 43 | { 44 | $files = scandir($this->app->getBasePath().$listener['path']); 45 | 46 | foreach ($files as $file) { 47 | if ($file === '.' || $file === '..') { 48 | continue; 49 | } 50 | 51 | $class = $listener['namespace'].explode('.',$file)[0]; 52 | 53 | if(class_exists($class)) { 54 | //Debug::dd($class); 55 | $listener = new $class($this->app); 56 | $event->register($listener->getName(),array($listener,'handler')); 57 | } else { 58 | Debug::error($class.' Event Not Found'); 59 | } 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * 根据 frame 中 app/config/event.php 66 | * 中 event 的配置加载事件 67 | * 68 | * @param Event $event 69 | * @param Config $config 70 | */ 71 | public function registerEvents(Event $event, Config $config) 72 | { 73 | $events = $config->get('event.events'); 74 | // var_dump($events); 75 | foreach ($events as $class) { 76 | if (class_exists($class)) { 77 | // Debug::dd($class."添加"); 78 | $listener = new $class($this->app); 79 | $event->register($listener->getName(), [$listener, 'handler']); 80 | } else { 81 | Debug::error($class.' Event Not Found'); 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/Event/Listener.php: -------------------------------------------------------------------------------- 1 | app = $app; 23 | } 24 | 25 | public function getName() 26 | { 27 | return $this->name; 28 | } 29 | } -------------------------------------------------------------------------------- /src/Event/README.md: -------------------------------------------------------------------------------- 1 | # 类库事件处理 -------------------------------------------------------------------------------- /src/Help/ColorString.php: -------------------------------------------------------------------------------- 1 | '0;30', 9 | 'dark_gray' => '1;30', 10 | 'blue' => '0;34', 11 | 'light_blue' => '1;34', 12 | 'green' => '0;32', 13 | 'light_green' => '1;32', 14 | 'cyan' => '0;36', 15 | 'light_cyan' => '1;36', 16 | 'red' => '0;31', 17 | 'light_red' => '1;31', 18 | 'purple' => '0;35', 19 | 'light_purple' => '1;35', 20 | 'brown' => '0;33', 21 | 'yellow' => '1;33', 22 | 'light_gray' => '0;37', 23 | 'white' => '1;37', 24 | ); 25 | private static $backgroundColors = array( 26 | 'black' => '40', 27 | 'red' => '41', 28 | 'green' => '42', 29 | 'yellow' => '43', 30 | 'blue' => '44', 31 | 'magenta' => '45', 32 | 'cyan' => '46', 33 | 'light_gray' => '47', 34 | ); 35 | 36 | public static function getColoredString($string, $foregroundColor = null, $backgroundColor = null) 37 | { 38 | $coloredString = ""; 39 | 40 | if (isset(static::$foregroundColors[$foregroundColor])) { 41 | $coloredString .= "\033[" . static::$foregroundColors[$foregroundColor] . "m"; 42 | } 43 | if (isset(static::$backgroundColors[$backgroundColor])) { 44 | $coloredString .= "\033[" . static::$backgroundColors[$backgroundColor] . "m"; 45 | } 46 | 47 | $coloredString .= $string . "\033[0m"; 48 | 49 | return $coloredString; 50 | } 51 | 52 | public static function getForegroundColors() 53 | { 54 | return array_keys(static::coregroundColors); 55 | } 56 | 57 | public static function getBackgroundColors() 58 | { 59 | return array_keys(static::backgroundColors); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/Help/Debug.php: -------------------------------------------------------------------------------- 1 | make($target); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Priovder/PriovderInterface.php: -------------------------------------------------------------------------------- 1 | app = $app; 22 | } 23 | 24 | public function register() 25 | { 26 | 27 | } 28 | 29 | abstract public function boot(); 30 | } -------------------------------------------------------------------------------- /src/Priovder/README.md: -------------------------------------------------------------------------------- 1 | # 服务提供者 -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jefferyjob/dartswoole/553d205fa02055247a684892a28d1f9da6387700/src/README.md -------------------------------------------------------------------------------- /src/Routes/README.php: -------------------------------------------------------------------------------- 1 | # 框架路由处理服务 2 | 3 | ## Route.php 4 | 5 | 6 | ## RouteServerRriovder.php 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Routes/Route.php: -------------------------------------------------------------------------------- 1 | routes; 57 | } 58 | 59 | /** 60 | * 注册路由 61 | */ 62 | public function registerRoute(array $map) { 63 | foreach ($map as $key => $route) { 64 | $this->flag = $key; 65 | $this->namespace = $route['namespace']; 66 | require_once $route['path']; 67 | } 68 | return $this; 69 | } 70 | 71 | /** 72 | * 添加到路由数组 73 | * 74 | * @param $methods array 请求方法 75 | * @param $uri string 路由地址 76 | * @param $action string 路由方法 77 | * @return $this 78 | */ 79 | protected function addRoute(array $methods, $uri, $action) 80 | { 81 | foreach ($methods as $method ) { 82 | if ($action instanceof \Closure) { 83 | $this->routes[$this->flag][$method][$uri] = $action; 84 | } else { 85 | $this->routes[$this->flag][$method][$uri] = $this->namespace."\\".$action; 86 | } 87 | } 88 | return $this; 89 | } 90 | 91 | /** 92 | * 实际的运行方法 93 | * 94 | * @param $action 95 | */ 96 | public function runAction($action) 97 | { 98 | if ($action instanceof \Closure) { 99 | return $action(); 100 | } else { 101 | $arr = \explode("@", $action); 102 | $class = new $arr[0](); 103 | return $class->{$arr[1]}(); 104 | } 105 | } 106 | 107 | /** 108 | * 路由请求校验的方法 109 | * 110 | * @param $pathinfo string 路径 111 | * @param $flag string 路由类型 112 | * @param $method string 路由方法 113 | * @return mixed|string 114 | */ 115 | public function match($pathinfo, $flag, $method) 116 | { 117 | $action = null; 118 | // 根据传递服务标识,请求类型查找route 119 | foreach ($this->routes[$flag][$method] as $uri => $value) { 120 | // 保持route标识与pathinfo一致性 121 | $uri = ($uri && \substr($uri, 0, 1) != '/') ? "/".$uri : $uri; 122 | 123 | if ($pathinfo === $uri) { 124 | $action = $value; 125 | break; 126 | } 127 | } 128 | // 判断是否查找到route 129 | if (!empty($action)) { 130 | // 执行方法操作 131 | return $this->runAction($action); 132 | } 133 | Debug::dd($action . "# 没有查找到方法"); 134 | return "404"; 135 | } 136 | 137 | /** 138 | * get 请求 139 | * 140 | * @param $uri 141 | * @param $action 142 | * @return $this 143 | */ 144 | public function get($uri, $action) 145 | { 146 | return $this->addRoute(['GET'], $uri, $action); 147 | } 148 | 149 | /** 150 | * post 请求 151 | * 152 | * @param $uri 153 | * @param $action 154 | * @return $this 155 | */ 156 | public function post($uri, $action) 157 | { 158 | return $this->addRoute(['POST'], $uri, $action); 159 | } 160 | 161 | /** 162 | * any 请求 163 | * 164 | * @param $uri 165 | * @param $action 166 | * @return $this 167 | */ 168 | public function any($uri, $action) 169 | { 170 | return $this->addRoute($this->method, $uri, $action); 171 | } 172 | } -------------------------------------------------------------------------------- /src/Routes/RouteServerPriovder.php: -------------------------------------------------------------------------------- 1 | app->bind('route', Route::getInstance()->registerRoute($this->map)); 21 | 22 | // test:获取所有路由信息 23 | //Debug::dd($this->app->make("route")->getRoutes()); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/Rpc/Proxy.php: -------------------------------------------------------------------------------- 1 | services = $services; 24 | } 25 | 26 | /** 27 | * 获取服务信息 28 | * 29 | * @param $consul_name string 服务名称 30 | */ 31 | public function services($consul_name) { 32 | if(is_array($this->services)) { 33 | return $this->services; 34 | } 35 | 36 | if($this->services instanceof \Closure) { 37 | return ($this->services)($consul_name); 38 | } 39 | 40 | if (empty($this->services)) { 41 | throw new \Exception("RPC services function not found", 500); 42 | // return app('config')->get('rpc_client.'.$consul_name); 43 | } 44 | } 45 | 46 | /** 47 | * 获取具体要请求的 rpc 服务 48 | * 49 | * @param string $consul_name 50 | * @return mixed|string 51 | */ 52 | public function getService($consul_name = '') 53 | { 54 | $services = $this->services($consul_name); 55 | if(empty($services)){ 56 | throw new \Exception("RPC Service Not Found", 500); 57 | } 58 | return $services[array_rand($services, 1)]; 59 | } 60 | } -------------------------------------------------------------------------------- /src/Rpc/README.md: -------------------------------------------------------------------------------- 1 | # RPC 2 | 3 | rpc 相关服务的实现 4 | 5 | ## RpcServer.php 6 | 7 | RPC 服务端相关服务处理 8 | 9 | ## RpcClient.php 10 | 11 | RPC 客户端相关服务处理 12 | 13 | ## Proxy.php 14 | 15 | -------------------------------------------------------------------------------- /src/Rpc/RpcClient.php: -------------------------------------------------------------------------------- 1 | $this->class.'::'.$method, 36 | 'params' => $params 37 | ); 38 | 39 | // 1、采用配置文件访问rpc服务 40 | // 获取 frame 中的配置信息 41 | // $config = app('config')->get('rpc_client.'.$this->service); 42 | // return $this->send($config['host'], $config['port'], $data); 43 | 44 | // 2、采用consul注册的服务访问rpc服务 45 | $service = app('rpc-proxy')->getService($this->service); 46 | return $this->send($service['host'], $service['port'], $data); 47 | 48 | //return $this->send('127.0.0.1', 9600, $data); 49 | } 50 | 51 | /** 52 | * 请求 RPC 服务 53 | * 54 | * @param $host 55 | * @param $port 56 | * @param $data 57 | * @return mixed 58 | * @throws \Exception 59 | */ 60 | public function send($host, $port, $data) 61 | { 62 | $client = new Client(SWOOLE_SOCK_TCP); 63 | if (!$client->connect($host, $port, 0.5)) { 64 | throw new \Exception("连接RPC服务端失败".json_encode(array( 65 | 'host' => $host, 66 | 'port' => $port 67 | )), 500); 68 | 69 | } 70 | $client->send(json_encode($data)); 71 | $result = $client->recv(); 72 | $client->close(); 73 | return $result; 74 | } 75 | 76 | /** 77 | * 调用不存在的方法 78 | * 79 | * @param $name 80 | * @param $arguments 81 | */ 82 | public function __call($name, $arguments) 83 | { 84 | return $this->proxy($name, $arguments); 85 | } 86 | 87 | /** 88 | * 调用不存在的静态方法 89 | * 90 | * @param $name 91 | * @param $arguments 92 | */ 93 | static public function __callStatic($name, $arguments) 94 | { 95 | return self::proxy($name, $arguments); 96 | } 97 | } -------------------------------------------------------------------------------- /src/Rpc/RpcServer.php: -------------------------------------------------------------------------------- 1 | app = $app; 52 | $this->server = $serverBase; 53 | $this->config = $this->app->make('config'); 54 | 55 | // swoole 多端口监听 56 | $this->listen = $serverBase->getServer()->listen($this->config->get('rpc_server.host'),$this->config->get('rpc_server.port'),$this->config->get('rpc_server.type')); 57 | 58 | // 事件监听绑定 59 | $this->listen->on('Connect', [$this, 'Connect']); 60 | $this->listen->on('Receive', [$this, 'Receive']); 61 | $this->listen->on('Close', [$this, 'Close']); 62 | 63 | // swoole 配置重置 64 | $this->listen->set($this->config->get('rpc_server.swoole')); 65 | 66 | Debug::info('RPC 服务启动成功'); 67 | Debug::info('tcp://'.$this->config->get('rpc_server.host').':'.$this->config->get('rpc_server.port')); 68 | } 69 | 70 | /** 71 | * 监听连接进入事件 72 | * 73 | * @param $server 74 | * @param $fd 75 | */ 76 | public function Connect($server, $fd) 77 | { 78 | Debug::info('RPC 连接成功'); 79 | } 80 | 81 | /** 82 | * 监听数据接收事件 83 | * 84 | * @param $server 85 | * @param $fd 86 | * @param $reactor_id 87 | * @param $data 88 | * 89 | * RPC 服务端调用思路: 90 | * rpc client 请求过来是一个jsno 91 | * 解析这个json 92 | * 然后实例化类和调用方法 93 | * 得到的结果进行返回 94 | * 95 | * RPC 得到的json示例: 96 | * wiki:https://www.swoft.org/documents/v2/core-components/rpc-server/#-swoft- 97 | * { 98 | * "jsonrpc": "2.0", 99 | * "method": "{class_name}::{method_name}", 100 | * "params": [], 101 | * "id": "", 102 | * "ext": [] 103 | * } 104 | */ 105 | public function Receive($server, $fd, $reactor_id, $data) 106 | { 107 | $rpc = json_decode($data, true); 108 | if($rpc) { 109 | // 得到对象 110 | $class = explode("::", $rpc['method'])[0]; 111 | $class = new $class(); 112 | // 得到方法 113 | $method = explode("::", $rpc['method'])[1]; 114 | // 执行 115 | $return = $class->{$method}(...$rpc['params']); 116 | // 返回 117 | $server->send($fd, Reponse::send($return)); 118 | } 119 | 120 | Debug::info('RPC 收到消息并且处理:::'.Reponse::send($return)); 121 | } 122 | 123 | /** 124 | * 监听连接关闭事件 125 | * 126 | * @param $server 127 | * @param $fd 128 | */ 129 | public function Close($server, $fd) 130 | { 131 | Debug::info('RPC 关闭连接'); 132 | } 133 | } -------------------------------------------------------------------------------- /src/Rpc/RpcServerPriovder.php: -------------------------------------------------------------------------------- 1 | provider(); 14 | 15 | $this->app->bind('rpc-proxy', new Proxy($this->services)); 16 | } 17 | 18 | protected function provider() {} 19 | } -------------------------------------------------------------------------------- /src/SwooleServer/Http/HttpRequest.php: -------------------------------------------------------------------------------- 1 | method; 23 | } 24 | 25 | public function getUriPath() 26 | { 27 | return $this->uriPath; 28 | } 29 | 30 | static public function init(SwooleRequest $request) 31 | { 32 | $self = new static; 33 | 34 | $self->swooleRequest = $request; 35 | $self->server = $request->server; 36 | 37 | $self->method = $request->server['request_method'] ?? ''; 38 | $self->uriPath = $request->server['request_uri'] ?? ''; 39 | 40 | return $self; 41 | } 42 | } -------------------------------------------------------------------------------- /src/SwooleServer/Http/HttpServer.php: -------------------------------------------------------------------------------- 1 | host = $this->app->make('config')->get('http_server.host'); 25 | 26 | $this->port = $this->app->make('config')->get('http_server.port'); 27 | } 28 | 29 | /** 30 | * 创建服务 31 | */ 32 | public function createServer() 33 | { 34 | $this->server = new Server($this->host, $this->port); 35 | 36 | Debug::info("swoole http 服务启动成功:"); 37 | 38 | Debug::info("http://{$this->host}:{$this->port}"); 39 | } 40 | 41 | /** 42 | * 事件绑定 43 | */ 44 | public function initEvent() 45 | { 46 | $this->setEvent('sub', [ 47 | 'request' => 'onRequest' 48 | ]); 49 | } 50 | 51 | /** 52 | * http 响应事件 53 | * 54 | * @param $request 55 | * @param $response 56 | * 57 | * mark 58 | * chrome请求两次问题:https://wiki.swoole.com/#/start/start_http_server?id=chrome-%e8%af%b7%e6%b1%82%e4%b8%a4%e6%ac%a1%e9%97%ae%e9%a2%98 59 | */ 60 | public function onRequest($request, $response) 61 | { 62 | // 处理第一次请求 63 | if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') { 64 | $response->end(); 65 | return; 66 | } 67 | 68 | // 处理第二次请求 69 | $response->header('Content-Type', 'text/html; charset=utf-8'); 70 | 71 | //$response->end("