[
  {
    "path": ".gitignore",
    "content": "*/.buildpath\n*/.settings/\n*/.project\n*/*.patch\n*/.idea/\n.idea/\n*/.git/\n.git/\n*/runtime/\n*/vendor/\n*/.phpintel/\n*/.env\n*/.DS_Store\n*/.phpunit*\n*/*.cache\n*/watch\n*/composer.lock\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 Double-Jin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README-CN.md",
    "content": "[English](./README.md) | [中文]\n\n# 介绍\n\nJin-microservices是基于 php 语言 + hyperf 微服务 框架的完整微服务demo。\n\ngithub：https://github.com/Double-Jin/jin-microservices\n\ngitee：https://gitee.com/ljj96/jin-microservices\n\n# 关于 JM\n\n作为php、go双修的开发者， go 语言的微服务体系已经基本掌握，go 语言相关的微服务的文章、开源项目在网上搜索一搜一大堆，这让会 go 语言的开发者能容易地上手并实现微服务，毕竟go语言是除java外最合适做微服务的语言这一。\n\nphp语言的优势在于web生态，开发的应用绝大多数为单体应用架构。近年来随着基于 swoole 扩展的 hyperf框架的出现，让php也能开发微服务架构，这里要感谢开源工作者。但用 \"php + 微服务 \"作为关键词时，搜索出来的文章、开源项目都是一些简单的案例，开发者并不能通过这些简单的案例来了解微服务，这让我有了想写本项目的原始动力。\n\n# 前言\n\nJM 是一款基于 php 语言 + hyperf 微服务 框架编写的完整微服务demo，与网上能找到的单一功能点简单实现的文章不同，JM从实际项目需求出发，力求做到git clone 项目下来后对着文件就能帮你构建微服务完整的知识体系，让你实际用hyperf开发微服务项目时能粘贴复制本项目的代码。\n\n微服务架构并不是比单体架构先进的架构，只是在项目体量、项目开发者人数达到一定量级后的一种选择。切勿盲目鼓吹微服务，在团队开发、运维能力不足的情况下强行推进微服务架构恐怕会适得其反。\n\n下面提到的组件并不是微服务架构才能使用，如elk、nacos、dtm这些，在单体应用里面也有合适的场景用到，取其精华来满足业务上的需要。如在生产上用到这些组件最好选择编译安装或购买云服务\n\n## 功能亮点\n\n* 完整微服务架构\n* JsonRpc调用\n* JWT认证\n* 文件上传\n* 统一异常处理\n* 服务注册与服务发现\n* 消息队列\n* 链接追踪\n* 配置中心\n* 服务限流\n* 服务降级\n* 分布式日志\n* 分布式事务\n\n# 准备\n微服务是把单体应用进行分拆后的架构，通过引用第三方组件来解决分拆后带来的问题，安装部署这些组件的时候你将会遇到很多奇奇怪怪的问题。为减低难度，本项目大部分组件采用docker来安装，整体流程我已在不同的电脑上验证数遍，即便如此还是会存在如composer、github、http/tcp访问、端口、内存、docker版本等问题，同样的操作换了台电脑就可能出问题，这需要你跟据报错内容查找相关资料自行解决。\n\n- 8核16G电脑\n- 熟悉docker\n- 了解网络协议\n- 基本的运维能力\n\n# 安装\n\n- docker安装\n  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_ONE.md)\n  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_ONE.md)\n- docker-compose安装\n  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_TWO.md)\n  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_TWO.md)\n\n# 使用\n\n* 目录结构\n  ```\n    |-- api-gateway //网关服务项目代码 \n    |-- order-srv //订单服务项目代码\n    |-- fIle-srv //文件服务项目代码\n    |-- user-srv // 用户服务项目代码\n    |-- task-srv // 定时任务、队列消费服务项目代码\n    |-- doc // 文档目录\n    |-- README.md //英文说明\n    |-- README-CN.md //中文说明\n  ```\n\n* 完整微服务架构\n  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/zfxnraiUJx.png!large)\n\n* JsonRpc调用\n  - `GET http://127.0.0.1:9501/User/UserInfo` 通讯单一服务\n  - `GET http://127.0.0.1:9501/User/UserBonusList` 通讯单一服务\n  - `GET http://127.0.0.1:9501/User/UserStoredList` 通讯单一服务\n  - `GET http://127.0.0.1:9501/Order/OrderList` 通讯多个服务\n\n* JWT认证\n  - `GET http://127.0.0.1:9501/Auth/Login` 用户登录\n  - `GET http://127.0.0.1:9501/Auth/Logout\n    Authorization : \tBearer {{token}}` 用户退出登录\n\n\n* 文件上传\n  - 微服务中rpc是轻量级通信框架，擅长传输字符串。对于文本文件传输不太友好，\n  而对于文件如果强行都成String，就会是一堆乱码。因此，大致的解决思路是，不管文件类型，统统转化成二进制，再将二进制进行Base64编码成String，传输编码后的String到RPC服务，RPC服务按照Base64解码还原成二进制，通过二进制构造File对象即可。\n  - `POST http://127.0.0.1:9501/File/UploadFile` 文件转为base64字符串通过json-rpc传输\n  - `file-srv.app.JsonRpc.FileRpcService.uploadFile` 通过json-rpc接收base64字符串生成文件\n\n\n* 统一异常处理\n  - 封装AppServiceExceptionHandler.php 统一处理http请求异常\n  - 封装RateLimitExceptionHandler.php 统一处理限流异常\n  - 封装JsonRpcExceptionHandler.php 统一处理JsonPrc通讯异常\n  - 封装DtmExceptionHandler.php 统一处理DTM事务中间件异常\n\n* 服务注册与服务发现\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/03VknWhiB6.png!large)\n\n* 消息队列\n  - `GET http://127.0.0.1:9501/User/UserRabbitMQ` 调用投递用户消息队列接口\n  - `GET http://127.0.0.1:9501/Order/OrderRabbitMQ` 调用投递订单消息队列接口\n  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/0BU5P5RHTL.jpeg!large)\n  \n* 链接追踪\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/PaiIwXUVrr.png!large)\n\n* 配置中心\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/SfiKibJ55r.png!large)\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/K4Zf5zlBhq.png!large)\n\n* 服务限流\n  `GET http://127.0.0.1:9501/RateLimit/Test`\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/QpZmGG31WD.png!large)\n\n* 服务降级\n  `GET http://127.0.0.1:9501/CircuitBreaker/Test`\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/bpVBwAgOKl.png!large)\n\n* 分布式日志\n  \n  当系统变为集群后，应用日志在数十台甚至是上百台不同的服务器上，能实现日志的统一查找、分析和归档等功能便可称为分布式日志系统。\n  \n  生产上方案会有很多，如将日志直接输出来Elasticsearch，如使用云服务商提供的日志收集。本案例采用的是通过filebeat将日志同步到ELK中。\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/qFqXMfcYu2.png!large)\n\n\n* 分布式事务\n  \n  数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。但对分布式系统来说，数据的操作来自多个不同的数据库，单个数据库事务的成功或失败不代表整个系统的数据一致性是对的，只能够通过分布式事务来解决。\n  \n  分布式事务就是指事务的发起者、资源及资源管理器和事务协调者分别位于分布式系统的不同节点之上。行业上常用的有二阶段提交、SAGA、TCC等方案，当了解原理后，你自行用http/tcp也能实现二阶段提交、SAGA、TCC。\n  \n  下面的接口通过DTM调度实现在一个SAGA案例。\n  `POST http://127.0.0.1:9501/Order/CreateOrder` 分布式事务\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/7tiJcnKiXi.png!large)\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/a5v6AdYVT2.png!large)\n  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/txAseIwfVr.png!large)\n  \n# 不足\n* 不支持gRpc的服务注册与服务发现\n* 配置中心组件只支持config调用，无法做到env的动态写入与框架重启，但可通过k8s实现\n\n\n# 感谢\n- hyperf：https://hyperf.wiki/2.2/#/README\n- dtm：https://en.dtm.pub/\n- nacos：https://nacos.io/zh-cn/docs/what-is-nacos.html\n- elk：https://www.elastic.co/cn/what-is/elk-stack "
  },
  {
    "path": "README.md",
    "content": "English | [中文](./README-CN.md)\n\n# Introduction\n\nJin microservices is a complete microservice demo based on PHP language + hyperf microservices framework\n\ngithub：https://github.com/Double-Jin/jin-microservices\n\ngitee：https://gitee.com/ljj96/jin-microservices\n\n# About JM\n\nAs a developer of both php and go, the microservice system of the go language has been basically mastered. There are a lot of articles and open source projects related to the go language on the Internet, which makes it easy for developers who know the go language Get started and implement microservices. After all, go language is the most suitable language for microservices other than java.\n\nThe advantage of the php language lies in the web ecosystem, and most of the applications developed are monolithic application architectures. In recent years, with the emergence of hyperf framework based on swoole extension, php can also develop microservice architecture, thanks to open source workers. However, when using \"php + microservices\" as the keyword, the articles and open source projects searched are simple cases. Developers cannot understand microservices through these simple cases, which makes me want to write this project. raw power.\n\n# Foreword\n\nJM is a complete microservice demo written based on php language + hyperf microservice framework. Unlike articles that can be found on the Internet with simple implementation of a single function point, JM starts from the actual project requirements and strives to achieve the git clone project. The file can help you build a complete knowledge system for microservices, so that you can paste and copy the code of this project when you actually use hyperf to develop a microservice project.\n\nThe microservice architecture is not an architecture that is more advanced than the monolithic architecture, but a choice after the project volume and the number of project developers reach a certain order of magnitude. Do not blindly advocate microservices. Forcibly promoting the microservice architecture when the team's development and operation and maintenance capabilities are insufficient may be counterproductive.\n\nThe components mentioned below are not only used in microservice architecture, such as elk, nacos, and dtm. They are also used in suitable scenarios in monolithic applications, and the essence of them can be used to meet business needs. If these components are used in production, it is best to choose to compile and install or purchase cloud services\n\n## Feature\n\n* Complete microservice architecture\n* JsonRpc call\n* Jwt authority authentication\n* Upload the file\n* Unified exception handling\n* Service Registration and Service Discovery\n* Message queue\n* Link tracking\n* Configuration Center\n* Service current limit\n* Service downgrade\n* Distributed log\n* Distributed transaction\n\n# Prepare\nMicroservices are an architecture that splits a monolithic application. By using third-party components to solve the problems caused by the split, you will encounter many strange problems when installing and deploying these components. In order to reduce the difficulty, most of the components of this project are installed by docker. I have verified the overall process several times on different computers. Even so, there are still problems such as composer, github, http/tcp access, ports, memory, docker version, etc. , the same operation may cause problems if you change the computer, which requires you to find relevant information according to the content of the error to solve it yourself.\n\n- 8 core 16G computer\n- familiar with docker\n- Learn about network protocols\n- Basic operation and maintenance capabilities\n\n# Install\n\n- docker install\n  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_ONE.md)\n  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_ONE.md)\n- docker-compose install\n  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_TWO.md)\n  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_TWO.md)\n\n# Use\n\n* Directory Structure\n  ```\n    |-- api-gateway //Gateway service project code \n    |-- order-srv //Order service project code\n    |-- user-srv // User service project code\n    |-- task-srv // Timed task and queue service project code\n    |-- doc // Documentation directory\n    |-- README.md //English description\n    |-- README-CN.md //Chinese description\n  ```\n\n* Complete microservice architecture\n  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/zfxnraiUJx.png!large)\n\n* JsonRpc call\n  - `GET http://127.0.0.1:9501/User/UserInfo` Communication single service\n  - `GET http://127.0.0.1:9501/User/UserBonusList` Communication single service\n  - `GET http://127.0.0.1:9501/User/UserStoredList` Communication single service\n  - `GET http://127.0.0.1:9501/Order/OrderList` Communication multiple services\n\n* Jwt authority authentication\n  - `GET http://127.0.0.1:9501/Auth/Login` User login\n  - `GET http://127.0.0.1:9501/Auth/Logout\n    Authorization : \tBearer {{token}}` User logged out\n\n\n* Upload the file\n  - RPC in microservices is a lightweight communication framework that is good at transporting strings. Not very friendly for text file transfers,\n    And for the file if it is forced into String, it will be a bunch of garbled characters. Therefore, the general solution idea is that regardless of the file type, \n  - all are converted into binary, and then the binary is Base64 encoded into String, and the encoded String is transferred to the background, and the background is restored to binary according to Base64 decoding, and the File object can be constructed through binary.\n  - `POST http://127.0.0.1:9501/File/UploadFile` The file is converted to a base64 string and transferred via json-rpc\n  - `file-srv.app.JsonRpc.FileRpcService.uploadFile` Generate a file by receiving a base64 string via json-rpc\n\n\n* Unified exception handling\n  - Encapsulate AppServiceExceptionHandler.php http request exceptions\n  - Encapsulate RateLimitExceptionHandler.php current limiting exceptions\n  - Encapsulate JsonRpcExceptionHandler.php JsonPrc exceptions\n  - Encapsulate DtmExceptionHandler.php DTM Distributed transaction exceptions\n\n* Service Registration and Service Discovery\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/03VknWhiB6.png!large)\n\n* Message queue\n  - `GET http://127.0.0.1:9501/User/UserRabbitMQ` Call the delivery user message queue interface\n  - `GET http://127.0.0.1:9501/Order/OrderRabbitMQ` Call the delivery order message queue interface\n  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/0BU5P5RHTL.jpeg!large)\n  \n* Link tracking\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/PaiIwXUVrr.png!large)\n\n* Configuration Center\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/SfiKibJ55r.png!large)\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/K4Zf5zlBhq.png!large)\n\n* Service current limit\n  `GET http://127.0.0.1:9501/RateLimit/Test`\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/QpZmGG31WD.png!large)\n\n* Service downgrade\n  `GET http://127.0.0.1:9501/CircuitBreaker/Test`\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/bpVBwAgOKl.png!large)\n\n* Distributed log\n\n  When the system becomes a cluster, the application logs on dozens or even hundreds of different servers can realize the functions of unified search, analysis and archiving of logs, which can be called a distributed log system.\n\n  There are many solutions in production, such as outputting logs directly to Elasticsearch, such as using log collection provided by cloud service providers. In this case, the log is synchronized to ELK through filebeat.\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/qFqXMfcYu2.png!large)\n\n\n* Distributed transaction\n\n  A database transaction ensures that all operations within the scope of the transaction can either succeed or fail. But for distributed systems, data operations come from multiple different databases, and the success or failure of a single database transaction does not mean that the data consistency of the entire system is correct, and can only be resolved through distributed transactions.\n\n  Distributed transaction means that the initiator, resource and resource manager and transaction coordinator of the transaction are located on different nodes of the distributed system. Two-phase submission, SAGA, TCC and other schemes are commonly used in the industry. After understanding the principle, you can also use http/tcp to achieve two-phase submission, SAGA, and TCC.\n\n  The following interface is implemented in a SAGA case via DTM scheduling.\n  \n  `POST http://127.0.0.1:9501/Order/CreateOrder` Distributed transaction\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/7tiJcnKiXi.png!large)\n  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/a5v6AdYVT2.png!large)\n  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/txAseIwfVr.png!large)\n  \n# Question\n* Service registration and service discovery without gRpc support\n* The configuration center component only supports config calls, and cannot do dynamic writing of env and framework restarts, but it can be achieved through k8s\n\n# Thank\n- hyperf：https://hyperf.wiki/2.2/#/README\n- dtm：https://en.dtm.pub/\n- nacos：https://nacos.io/zh-cn/docs/what-is-nacos.html\n- elk：https://www.elastic.co/cn/what-is/elk-stack "
  },
  {
    "path": "api-gateway/app/Constants/ErrorCode.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n/**\n * @Constants\n */\nclass ErrorCode extends AbstractConstants\n{\n    /**\n     * @Message(\"Server Error！\")\n     */\n    const SERVER_ERROR = 500;\n}\n"
  },
  {
    "path": "api-gateway/app/Constants/ResponseCode.php",
    "content": "<?php\n\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n/**\n * @Constants\n */\nclass ResponseCode extends AbstractConstants\n{\n    /**\n     * @Message(\"请求错误\");\n     */\n    const ERROR = 0;\n\n    /**\n     * @Message(\"成功\");\n     */\n    const SUCCESS = 200;\n\n    /**\n     * @Message(\"创建成功\");\n     */\n    const CREATE_ED = 201;\n\n    /**\n     * 请求成功但服务器未处理，响应中包含指示信息\n     * @Message(\"请求成功\");\n     */\n    const ACCEPT_ED = 202;\n\n    /**\n     * 请求成功，但是没有响应内容\n     * @Message(\"请求成功\");\n     */\n    const NO_CONTENT = 204;\n\n    /**\n     * 请求成功，缓存生效\n     * @Message(\"NO_TMODIFIED\");\n     */\n    const NO_TMODIFIED = 302;\n\n    /**\n     * 请求错误，无法解析请求体\n     * @Message(\"请求错误\");\n     */\n    const BAD_REQUEST = 400;\n\n    /**\n     * 认证失败\n     * @Message(\"请登录\");\n     */\n    const UNAUTHORIZED = 401;\n\n    /**\n     * 服务器已经接受到请求，但拒绝执行\n     * @Message(\"FORBIDDEN\");\n     */\n    const FORBIDDEN = 403;\n\n    /**\n     * 找不到请求的资源\n     * @Message(\"找不到请求的资源\");\n     */\n    const  NOT_FOUND = 404;\n\n    /**\n     * 方法不允许当前用户访问\n     * @Message(\"METHOD_NOT_ALLOWED\");\n     */\n    const  METHOD_NOT_ALLOWED = 405;\n\n    /**\n     * 请求资源已过期\n     * @Message(\"GONE\");\n     */\n    const  GONE = 410;\n\n    /**\n     * 请求体内的类型错误\n     * @Message(\"MEDIA_TYPE\");\n     */\n    const  MEDIA_TYPE = 405;\n\n    /**\n     * 验证失败\n     * @Message(\"验证失败\");\n     */\n    const  UNPROCESSABLE = 422;\n\n\n    /**\n     * 请求频繁\n     * @Message(\"请求频繁\");\n     */\n    const  MAX_REQUEST = 429;\n\n    /**\n     * RPC调用失败\n     * @Message(\"RPC调用失败\");\n     */\n    const  RPC_ERROR = 430;\n\n}"
  },
  {
    "path": "api-gateway/app/Controller/AbstractController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Contract\\ResponseInterface;\nuse Psr\\Container\\ContainerInterface;\n\nabstract class AbstractController\n{\n    #[Inject]\n    protected ContainerInterface $container;\n\n    #[Inject]\n    protected RequestInterface $request;\n\n    #[Inject]\n    protected ResponseInterface $response;\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/AuthController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Middleware\\UserAuthMiddleware;\nuse App\\Services\\AuthService;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\GetMapping;\nuse Hyperf\\HttpServer\\Annotation\\Middleware;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\n\n/**\n * 用户权限控制器\n * Class UserController\n * @package App\\Controller\n */\n#[Controller(prefix: '/Auth')]\nclass AuthController extends CommonController\n{\n    /**\n     * 注入AuthService\n     * @var AuthService\n     */\n    #[Inject]\n    protected AuthService $authService;\n\n    /**\n     * 用户登录\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'Login')]\n    public function Login(RequestInterface $request)\n    {\n        //调用authService.getRpcUserLogin\n        $res = $this->authService->getRpcUserLogin('1358888888');\n\n        return $this->success($res);\n    }\n\n    /**\n     * 用户退出\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'Logout')]\n    #[Middleware(UserAuthMiddleware::class)]\n    public function Logout(RequestInterface $request)\n    {\n        //调用authService.getRpcUserLogout\n        $res = $this->authService->getRpcUserLogout(getBearerToken($request->header('Authorization')));\n\n        return $this->success($res);\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/CircuitBreakerController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\UserService;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\CircuitBreaker\\Annotation\\CircuitBreaker;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\GetMapping;\n\n/**\n * 服务降级控制器\n * Class CircuitBreakerController\n * @package App\\Controller\n */\n#[Controller(prefix: '/CircuitBreaker')]\nclass CircuitBreakerController extends CommonController\n{\n\n    /**\n     * 注入UserService\n     * @var UserService\n     */\n    #[Inject]\n    protected UserService $userService;\n\n    /**\n     * 测试服务降级\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'Test')]\n    #[CircuitBreaker(options:[\"timeout\"=>0.05],failCounter:1, successCounter:1, fallback:\"App\\Controller\\CircuitBreakerController::circuitBreakerFallback\")]\n    public function test()\n    {\n        $this->userService->testCircuitBreaker();\n\n        return $this->success('这是服务降级');\n    }\n\n    /**\n     * 服务降级异常返回方法\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    public function circuitBreakerFallback()\n    {\n        return $this->success('服务降级啦~');\n    }\n\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/CommonController.php",
    "content": "<?php\n\nnamespace App\\Controller;\n\n/**\n * 通用控制器\n * Class CommonController\n * @package App\\Controller\n */\nclass CommonController extends AbstractController\n{\n    public function success($data = [])\n    {\n        return $this->response->json(responseSuccess(200, '', $data));\n    }\n\n}"
  },
  {
    "path": "api-gateway/app/Controller/ConfigController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\GetMapping;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\n\n/**\n * 配置控制器\n * Class ConfigController\n * @package App\\Controller\n */\n#[Controller(prefix: '/Config')]\nclass ConfigController extends CommonController\n{\n\n    /**\n     * 测试配置中心数据获取\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'Test')]\n    public function test(RequestInterface $request)\n    {\n        //获取nacos中的配置\n        $config = config('nacos_config');\n\n        return $this->success($config);\n    }\n\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/FileController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\FileService;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\PostMapping;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\n\n/**\n * 文件控制器\n * Class FileController\n * @package App\\Controller\n */\n#[Controller(prefix: '/File')]\nclass FileController extends CommonController\n{\n    /**\n     * 注入FileService\n     * @var FileService\n     */\n    #[Inject]\n    protected FileService $fileService;\n\n    /**\n     * 上传文件\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[PostMapping(path: 'UploadFile')]\n    public function uploadFile(RequestInterface $request)\n    {\n        $res = $this->fileService->getRpcUploadFile($request->file('file'));\n\n        return $this->success($res);\n    }\n\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/OrderController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\OrderService;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\GetMapping;\nuse Hyperf\\HttpServer\\Annotation\\PostMapping;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\n\n/**\n * 订单控制器\n * Class OrderController\n * @package App\\Controller\n */\n#[Controller(prefix: '/Order')]\nclass OrderController extends CommonController\n{\n    /**\n     * 注入OrderService\n     * @var OrderService\n     */\n    #[Inject]\n    protected OrderService $orderService;\n\n    /**\n     * 用户订单列表\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'OrderList')]\n    public function orderList(RequestInterface $request)\n    {\n        //调用orderService.getRpcOrderList方法\n        $res = $this->orderService->getRpcOrderList(1);\n\n        return $this->success($res);\n    }\n\n    /**\n     * 创建订单\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[PostMapping(path: 'CreateOrder')]\n    public function createOrder(RequestInterface $request)\n    {\n        //调用orderService.rpcCreateOrder方法\n        $res = $this->orderService->rpcCreateOrder([\n            'user_id' => 1,\n            'coupon_id' => 0,\n            'order_money' => '100',\n            'order_discount' => '100',\n            'order_fact_money' => '100',\n            'consume_number' => 1,\n            'payment' => 1,\n            'goods' => [\n                [\n                    'goods_id' => 1,\n                    'goods_sn' => 'JIN02',\n                    'sku_id' => 1,\n                    'user_id' => 1,\n                    'goods_name' => '测试商品',\n                    'number' => 1,\n                    'goods_tag_price' => '100',\n                    'goods_real_price' => '100',\n                    'goods_discount' => '100',\n                    'goods_fact_money' => '100'\n                ]\n            ]\n        ]);\n\n        return $this->success($res);\n    }\n\n    /**\n     * 投递订单消息到RabbitMQ\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'OrderRabbitMQ')]\n    public function orderRabbitMQ(RequestInterface $request)\n    {\n        //调用orderService.getRpcUserStoredList方法\n        $res = $this->orderService->getRpcOrderRabbitMQ();\n\n        return $this->success($res);\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/RateLimitController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\GetMapping;\nuse Hyperf\\RateLimit\\Annotation\\RateLimit;\n\n/**\n * 限流控制器\n * Class RateLimitController\n * @package App\\Controller\n */\n#[Controller(prefix: '/RateLimit')]\nclass RateLimitController extends CommonController\n{\n\n    /**\n     * 测试限流\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'Test')]\n    #[RateLimit(create:1,consume:1, capacity:1,waitTimeout:1)]\n    public function test()\n    {\n        return $this->success('这是测试限流');\n    }\n\n}\n"
  },
  {
    "path": "api-gateway/app/Controller/UserController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\UserService;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\GetMapping;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\n\n/**\n * 用户控制器\n * Class UserController\n * @package App\\Controller\n */\n#[Controller(prefix: '/User')]\nclass UserController extends CommonController\n{\n    /**\n     * 注入UserService\n     * @var UserService\n     */\n    #[Inject]\n    protected UserService $userService;\n\n    /**\n     * 用户信息\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'UserInfo')]\n    public function userInfo(RequestInterface $request)\n    {\n        //调用userService.getRpcUserInfo方法\n        $res = $this->userService->getRpcUserInfo(1);\n\n        return $this->success($res);\n    }\n\n    /**\n     * 用户积分列表\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'UserBonusList')]\n    public function userBonusList(RequestInterface $request)\n    {\n        //调用userService.getRpcUserBonusList方法\n        $res = $this->userService->getRpcUserBonusList(1,15);\n\n        return $this->success($res);\n    }\n\n    /**\n     * 用户储值列表\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'UserStoredList')]\n    public function userStoredList(RequestInterface $request)\n    {\n        //调用userService.getRpcUserStoredList方法\n        $res = $this->userService->getRpcUserStoredList(1,15);\n\n        return $this->success($res);\n    }\n\n    /**\n     * 投递用户消息到RabbitMQ\n     * @param RequestInterface $request\n     * @return \\Psr\\Http\\Message\\ResponseInterface\n     */\n    #[GetMapping(path: 'UserRabbitMQ')]\n    public function userRabbitMQ(RequestInterface $request)\n    {\n        //调用userService.getRpcUserStoredList方法\n        $res = $this->userService->getRpcUserRabbitMQ();\n\n        return $this->success($res);\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Exception/BusinessException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass BusinessException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Exception/Handler/AppExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Throwable;\n\nclass AppExceptionHandler extends ExceptionHandler\n{\n    /**\n     * @var StdoutLoggerInterface\n     */\n    protected $logger;\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Exception/Handler/AppServiceExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://doc.hyperf.io\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\ServiceException;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Throwable;\n\n/**\n * app异常处理\n * Class AppServiceExceptionHandler\n * @package App\\Exception\\Handler\n */\nclass AppServiceExceptionHandler extends ExceptionHandler\n{\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n        if ($throwable instanceof ServiceException) {\n\n            //阻止异常冒泡\n            $this->stopPropagation();\n\n            //返回自定义错误数据\n            $result = responseError($throwable->getCode(), $throwable->getMessage());\n\n            return $response->withStatus($throwable->getCode())\n                ->withAddedHeader('content-type', 'application/json')\n                ->withBody(new SwooleStream(json_encode($result, JSON_UNESCAPED_UNICODE)));\n        }\n\n        // 交给下一个异常处理器\n        return $response;\n    }\n\n    /**\n     *\n     * @param Throwable $throwable 抛出的异常\n     * @return bool 该异常处理器是否处理该异常\n     */\n    public function isValid(Throwable $throwable): bool\n    {\n        //当前的异常是否属于业务异常\n        return true;\n    }\n}"
  },
  {
    "path": "api-gateway/app/Exception/Handler/RateLimitExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://doc.hyperf.io\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\ServiceException;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Hyperf\\RateLimit\\Exception\\RateLimitException;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Throwable;\n\n/**\n * 限流器异常处理\n * Class RateLimitExceptionHandler\n * @package App\\Exception\\Handler\n */\nclass RateLimitExceptionHandler extends ExceptionHandler\n{\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n        if ($throwable instanceof RateLimitException) {\n            //阻止异常冒泡\n            $this->stopPropagation();\n\n            //返回自定义错误数据\n            $result = responseError($throwable->getCode(), '您被限流啦');\n\n            return $response->withStatus($throwable->getCode())\n                ->withAddedHeader('content-type', 'application/json')\n                ->withBody(new SwooleStream(json_encode($result, JSON_UNESCAPED_UNICODE)));\n        }\n\n        // 交给下一个异常处理器\n        return $response;\n    }\n\n    /**\n     *\n     * @param Throwable $throwable 抛出的异常\n     * @return bool 该异常处理器是否处理该异常\n     */\n    public function isValid(Throwable $throwable): bool\n    {\n        //当前的异常是否属于业务异常\n        return true;\n    }\n}"
  },
  {
    "path": "api-gateway/app/Exception/ServiceException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ResponseCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass ServiceException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ResponseCode::getMessage($code);\n        }\n        parent::__construct($message, $code, $previous);\n    }\n}"
  },
  {
    "path": "api-gateway/app/JsonRpc/FileRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/12/20\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface FileRpcServiceInterface\n{\n\n    public function uploadFile(string $type, string $base64string, string $fileName): array;\n\n}"
  },
  {
    "path": "api-gateway/app/JsonRpc/OrderRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface OrderRpcServiceInterface\n{\n\n    public function orderList(int $userId) : array;\n\n    public function createOrder(array $data) : array;\n\n    public function orderRabbitMQ(): array;\n\n}"
  },
  {
    "path": "api-gateway/app/JsonRpc/UserRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface UserRpcServiceInterface\n{\n\n    public function userInfo(int $userId): array;\n\n    public function userBonusList(int $page, int $pageSize): array;\n\n    public function userStoredList(int $page, int $pageSize): array;\n\n    public function userRabbitMQ(): array;\n\n    public function userLogin(string $phone): array;\n\n    public function userLogout(string $token): array;\n\n    public function userCheckToken(string $token): array;\n\n}"
  },
  {
    "path": "api-gateway/app/Kernel/Functions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://doc.hyperf.io\n * @contact  group@hyperf.io\n */\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Hyperf\\Redis\\Redis;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\Formatter\\FormatterInterface;\n\n/**\n * 获取Container\n */\nif (!function_exists('di')) {\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     * @param null|mixed $id\n     * @return mixed|\\Psr\\Container\\ContainerInterface\n     */\n    function di($id = null)\n    {\n        $container = ApplicationContext::getContainer();\n        if ($id) {\n            return $container->get($id);\n        }\n        return $container;\n    }\n}\n\n/**\n * 控制台日志\n */\nif (!function_exists('stdLog')) {\n    function stdLog()\n    {\n        return di()->get(StdoutLoggerInterface::class);\n    }\n}\n\n/**\n * 文件日志\n */\nif (!function_exists('logger')) {\n    function logger($name = 'log', $group = 'default')\n    {\n        return di()->get(LoggerFactory::class)->get($name, $group);\n    }\n}\n\n/**\n * redis 客户端实例\n */\nif (!function_exists('redis')) {\n    function redis()\n    {\n        return di()->get(Redis::class);\n    }\n}\n\n/**\n * 缓存实例 简单的缓存\n */\nif (!function_exists('cache')) {\n    function cache()\n    {\n        return di()->get(\\Psr\\SimpleCache\\CacheInterface::class);\n    }\n}\n\nif (!function_exists('format_throwable')) {\n    /**\n     * Format a throwable to string.\n     * @param Throwable $throwable\n     * @return string\n     */\n    function format_throwable(Throwable $throwable): string\n    {\n        return di()->get(FormatterInterface::class)->format($throwable);\n    }\n}\n\n\nif (!function_exists('responseSuccess')) {\n    function responseSuccess($code, $message = '', $data = [])\n    {\n        $content = ['code' => $code];\n        $message ? $content['msg'] = $message : $content['msg'] = \\App\\Constants\\ResponseCode::getMessage($code);\n        $data ? $content['data'] = $data : $content['data'] = [];\n        return $content;\n    }\n}\n\nif (!function_exists('responseError')) {\n    function responseError($code, $message = '', $data = [])\n    {\n        $content = ['code' => $code];\n        $message ? $content['msg'] = $message : $content['msg'] = \\App\\Constants\\ResponseCode::getMessage($code);\n        $data ? $content['data'] = $data : $content['data'] = [];\n        return $content;\n    }\n}\n\n\n/**\n * 判读字符串是否为json\n */\nif (!function_exists('isJson')) {\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     * @param string $string\n     */\n    function isJson($string)\n    {\n        json_decode($string);\n        return (json_last_error() == JSON_ERROR_NONE);\n    }\n}\n\n/**\n * 容器实例\n */\nif (!function_exists('container')) {\n    function container()\n    {\n        return ApplicationContext::getContainer();\n    }\n}\n\n/**\n * 获取BearerToken\n */\nif (!function_exists('getBearerToken')) {\n    function getBearerToken($Authorization)\n    {\n        if (\\Hyperf\\Utils\\Str::startsWith($Authorization, 'Bearer ')) {\n            return \\Hyperf\\Utils\\Str::substr($Authorization, 7);\n        }\n\n        return null;\n    }\n}\n\n\n\n"
  },
  {
    "path": "api-gateway/app/Listener/DbQueryExecutedListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\Arr;\nuse Hyperf\\Utils\\Str;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * @Listener\n */\nclass DbQueryExecutedListener implements ListenerInterface\n{\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->logger = $container->get(LoggerFactory::class)->get('sql');\n    }\n\n    public function listen(): array\n    {\n        return [\n            QueryExecuted::class,\n        ];\n    }\n\n    /**\n     * @param QueryExecuted $event\n     */\n    public function process(object $event) : void\n    {\n        if ($event instanceof QueryExecuted) {\n            $sql = $event->sql;\n            if (! Arr::isAssoc($event->bindings)) {\n                foreach ($event->bindings as $key => $value) {\n                    $sql = Str::replaceFirst('?', \"'{$value}'\", $sql);\n                }\n            }\n\n            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));\n        }\n\n        return;\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Listener/QueueHandleListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\AsyncQueue\\AnnotationJob;\nuse Hyperf\\AsyncQueue\\Event\\AfterHandle;\nuse Hyperf\\AsyncQueue\\Event\\BeforeHandle;\nuse Hyperf\\AsyncQueue\\Event\\Event;\nuse Hyperf\\AsyncQueue\\Event\\FailedHandle;\nuse Hyperf\\AsyncQueue\\Event\\RetryHandle;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\ExceptionHandler\\Formatter\\FormatterInterface;\nuse Hyperf\\Logger\\LoggerFactory;\n\n/**\n * @Listener\n */\nclass QueueHandleListener implements ListenerInterface\n{\n    /**\n     * @var \\Psr\\Log\\LoggerInterface\n     */\n    protected $logger;\n\n    /**\n     * @var FormatterInterface\n     */\n    protected $formatter;\n\n    public function __construct(LoggerFactory $loggerFactory, FormatterInterface $formatter)\n    {\n        $this->logger = $loggerFactory->get('queue');\n        $this->formatter = $formatter;\n    }\n\n    public function listen(): array\n    {\n        return [\n            AfterHandle::class,\n            BeforeHandle::class,\n            FailedHandle::class,\n            RetryHandle::class,\n        ];\n    }\n\n    public function process(object $event) : void\n    {\n        if ($event instanceof Event && $event->message->job()) {\n            $job = $event->message->job();\n            $jobClass = get_class($job);\n            if ($job instanceof AnnotationJob) {\n                $jobClass = sprintf('Job[%s@%s]', $job->class, $job->method);\n            }\n            $date = date('Y-m-d H:i:s');\n\n            switch (true) {\n                case $event instanceof BeforeHandle:\n                    $this->logger->info(sprintf('[%s] Processing %s.', $date, $jobClass));\n                    break;\n                case $event instanceof AfterHandle:\n                    $this->logger->info(sprintf('[%s] Processed %s.', $date, $jobClass));\n                    break;\n                case $event instanceof FailedHandle:\n                    $this->logger->error(sprintf('[%s] Failed %s.', $date, $jobClass));\n                    $this->logger->error($this->formatter->format($event->getThrowable()));\n                    break;\n                case $event instanceof RetryHandle:\n                    $this->logger->warning(sprintf('[%s] Retried %s.', $date, $jobClass));\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "api-gateway/app/Log.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\nclass Log\n{\n    public static function get(string $name = 'app')\n    {\n        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);\n    }\n}"
  },
  {
    "path": "api-gateway/app/Middleware/UserAuthMiddleware.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Middleware;\n\nuse App\\Exception\\ServiceException;\nuse App\\Services\\AuthService;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\Utils\\Str;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Hyperf\\HttpServer\\Contract\\ResponseInterface as HttpResponse;\nuse Throwable;\n\nclass UserAuthMiddleware implements MiddlewareInterface\n{\n\n    /**\n     * @var ContainerInterface\n     */\n    protected $container;\n\n    /**\n     * @var RequestInterface\n     */\n    protected $request;\n\n    /**\n     * @var HttpResponse\n     */\n    protected $response;\n\n    /**\n     * 注入AuthService\n     * @var AuthService\n     */\n    #[Inject]\n    protected AuthService $authService;\n\n    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)\n    {\n        $this->container = $container;\n        $this->response = $response;\n        $this->request = $request;\n    }\n\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        $token = $this->getBearerToken($request);\n\n        if (empty($token)){\n            throw new ServiceException(422,'token不存在');\n        }\n\n        //调用authService.getRpcUserCheckToken方法\n        $this->authService->getRpcUserCheckToken($token);\n\n        return $handler->handle($request);\n\n    }\n\n    public function getBearerToken($request)\n    {\n        $Authorization = $this->request->header('Authorization');\n\n        return getBearerToken($Authorization);\n    }\n}"
  },
  {
    "path": "api-gateway/app/Model/Model.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model as BaseModel;\nuse Hyperf\\ModelCache\\Cacheable;\nuse Hyperf\\ModelCache\\CacheableInterface;\nabstract class Model extends BaseModel implements CacheableInterface\n{\n    use Cacheable;\n}"
  },
  {
    "path": "api-gateway/app/Process/AsyncQueueConsumer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Process;\n\nuse Hyperf\\AsyncQueue\\Process\\ConsumerProcess;\nuse Hyperf\\Process\\Annotation\\Process;\n\n/**\n * @Process\n */\nclass AsyncQueueConsumer extends ConsumerProcess\n{\n}\n"
  },
  {
    "path": "api-gateway/app/Services/AuthService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\UserRpcServiceInterface;\nuse App\\Log;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Swoole\\Coroutine;\n\n/**\n * 用户权限service\n * Class AuthService\n * @package App\\Services\n */\nclass AuthService\n{\n\n    /**\n     * 注入UserRpcServiceInterface\n     * @var UserRpcServiceInterface\n     */\n    #[Inject]\n    protected UserRpcServiceInterface $userRpcServiceInterface;\n\n    /**\n     * 用户登录\n     * @param int $page\n     * @param int $pageSize\n     * @return mixed\n     */\n    public function getRpcUserLogin(string $phone)\n    {\n        Log::get()->info(\"调用getRpcUserLogin\");\n\n        try {\n            //调用用户服务中的用户登录方法\n            $res = $this->userRpcServiceInterface->userLogin($phone);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 用户退出\n     * @param string $token\n     * @return mixed\n     */\n    public function getRpcUserLogout(string $token)\n    {\n        Log::get()->info(\"调用getRpcUserLogout\");\n\n        try {\n            //调用用户服务中的用户退出方法\n            $res = $this->userRpcServiceInterface->userLogout($token);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 检查用户token\n     * @param string $token\n     * @return mixed\n     */\n    public function getRpcUserCheckToken(string $token)\n    {\n        Log::get()->info(\"调用getRpcUserLogout\");\n\n        try {\n            //调用用户服务中的检查用户token方法\n            $res = $this->userRpcServiceInterface->userCheckToken($token);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430,'token已过期');\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430,'token已过期');\n        }\n\n        return $res['data'];\n    }\n\n}"
  },
  {
    "path": "api-gateway/app/Services/FileService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\FileRpcServiceInterface;\nuse App\\Log;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\Utils\\Str;\n\n/**\n * 文件service\n * Class UserService\n * @package App\\Services\n */\nclass FileService\n{\n\n    /**\n     * 注入FileRpcServiceInterface\n     * @var FileRpcServiceInterface\n     */\n    #[Inject]\n    protected FileRpcServiceInterface $fileRpcServiceInterface;\n\n    /**\n     * 上传文件\n     * @param $file\n     * @return mixed\n     */\n    public function getRpcUploadFile($file)\n    {\n        Log::get()->info(\"调用uploadFile\");\n\n        $type =$file->getExtension(); //获取文件类型\n\n        $fileData = file_get_contents($file->getRealPath()); //获取文件二进制流\n\n        $base64String = 'data:' . $type . ';base64,' . chunk_split(base64_encode($fileData));\n\n        $fileName = Str::random(16) . '.' . $type;\n\n        try {\n            //调用文件服务中的文件上传方法\n            $res = $this->fileRpcServiceInterface->uploadFile($type,$base64String,$fileName);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n\n    }\n\n}"
  },
  {
    "path": "api-gateway/app/Services/OrderService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\OrderRpcServiceInterface;\nuse App\\Log;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * 订单service\n * Class OrderService\n * @package App\\Services\n */\nclass OrderService\n{\n\n    /**\n     * 注入OrderRpcServiceInterface\n     * @var OrderRpcServiceInterface\n     */\n    #[Inject]\n    protected OrderRpcServiceInterface $orderRpcServiceInterface;\n\n    /**\n     * 订单列表\n     * @param $userId\n     * @return mixed\n     */\n    public function getRpcOrderList(int $userId)\n    {\n        Log::get()->info(\"调用getRpcOrderList\");\n\n        try {\n            //调用订单服务中的订单列表方法\n            $res = $this->orderRpcServiceInterface->orderList($userId);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 创建列表\n     * @param $data\n     * @return mixed\n     */\n    public function rpcCreateOrder(array $data)\n    {\n        Log::get()->info(\"调用rpcCreateOrder\");\n\n        try {\n            //调用订单服务中的创建订单方法\n            $res = $this->orderRpcServiceInterface->createOrder($data);\n\n        } catch (\\Throwable $ex) {\n\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 投递用户消息到RabbitMQ\n     * @return mixed\n     */\n    public function getRpcOrderRabbitMQ()\n    {\n        Log::get()->info(\"调用getRpcUserRabbitMQ\");\n\n        try {\n            //调用订单服务中的投递订单消息到RabbitMQ方法\n            $res = $this->orderRpcServiceInterface->orderRabbitMQ();\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n}"
  },
  {
    "path": "api-gateway/app/Services/UserService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\UserRpcServiceInterface;\nuse App\\Log;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Swoole\\Coroutine;\n\n/**\n * 用户service\n * Class UserService\n * @package App\\Services\n */\nclass UserService\n{\n\n    /**\n     * 注入UserRpcServiceInterface\n     * @var UserRpcServiceInterface\n     */\n    #[Inject]\n    protected UserRpcServiceInterface $userRpcServiceInterface;\n\n    /**\n     * 用户信息\n     * @param $userId\n     * @return mixed\n     */\n    public function getRpcUserInfo($userId)\n    {\n        Log::get()->info(\"调用getRpcUserInfo\");\n\n        try {\n\n            //调用用户服务中的用户详情方法\n            $res = $this->userRpcServiceInterface->userInfo($userId);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 用户积分列表\n     * @param int $page\n     * @param int $pageSize\n     * @return mixed\n     */\n    public function getRpcUserBonusList(int $page, int $pageSize)\n    {\n        Log::get()->info(\"调用getRpcUserBonusList\");\n\n        try {\n            //调用用户服务中的用户积分列表方法\n            $res = $this->userRpcServiceInterface->userBonusList($page, $pageSize);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 用户储值列表\n     * @param int $page\n     * @param int $pageSize\n     * @return mixed\n     */\n    public function getRpcUserStoredList(int $page, int $pageSize)\n    {\n        Log::get()->info(\"调用getRpcUserStoredList\");\n\n        try {\n            //调用用户服务中的用户储值列表方法\n            $res = $this->userRpcServiceInterface->userStoredList($page, $pageSize);\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n    /**\n     * 测试服务降级\n     */\n    public function testCircuitBreaker()\n    {\n\n        Log::get()->info(\"调用testCircuitBreaker\");\n\n        Coroutine::sleep(2);\n    }\n\n    /**\n     * 投递用户消息到RabbitMQ\n     * @param int $page\n     * @param int $pageSize\n     * @return mixed\n     */\n    public function getRpcUserRabbitMQ()\n    {\n        Log::get()->info(\"调用getRpcUserRabbitMQ\");\n\n        try {\n            //调用用户服务中的投递用户消息到RabbitMQ方法\n            $res = $this->userRpcServiceInterface->userRabbitMQ();\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $ex->getCode(),\n                'file' => $ex->getFile(),\n                'message' => $ex->getMessage(),\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        if ($res['code'] !== 200) {\n            Log::get()->info(\"rpc调用失败\", [\n                'code' => $res['code'],\n                'file' => '',\n                'message' => $res['message']\n            ]);\n\n            throw new ServiceException(430);\n        }\n\n        return $res['data'];\n    }\n\n}"
  },
  {
    "path": "api-gateway/bin/hyperf.php",
    "content": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limit', '1G');\n\nerror_reporting(E_ALL);\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\n// Self-called anonymous function that creates its own scope and keep the global namespace clean.\n(function () {\n    Hyperf\\Di\\ClassLoader::init();\n    /** @var Psr\\Container\\ContainerInterface $container */\n    $container = require BASE_PATH . '/config/container.php';\n\n    $application = $container->get(Hyperf\\Contract\\ApplicationInterface::class);\n    $application->run();\n})();\n"
  },
  {
    "path": "api-gateway/composer.json",
    "content": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n        \"framework\",\n        \"hyperf\",\n        \"microservice\",\n        \"middleware\"\n    ],\n    \"description\": \"A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.\",\n    \"license\": \"Apache-2.0\",\n    \"require\": {\n        \"php\": \">=8.0\",\n        \"hyperf/async-queue\": \"3.0.*\",\n        \"hyperf/cache\": \"3.0.*\",\n        \"hyperf/circuit-breaker\": \"3.0.*\",\n        \"hyperf/code-generator\": \"^0.3.3\",\n        \"hyperf/command\": \"3.0.*\",\n        \"hyperf/config\": \"3.0.*\",\n        \"hyperf/config-nacos\": \"3.0.*\",\n        \"hyperf/constants\": \"3.0.*\",\n        \"hyperf/database\": \"3.0.*\",\n        \"hyperf/db-connection\": \"3.0.*\",\n        \"hyperf/framework\": \"3.0.*\",\n        \"hyperf/guzzle\": \"3.0.*\",\n        \"hyperf/http-server\": \"3.0.*\",\n        \"hyperf/json-rpc\": \"3.0.*\",\n        \"hyperf/logger\": \"3.0.*\",\n        \"hyperf/memory\": \"3.0.*\",\n        \"hyperf/model-cache\": \"3.0.*\",\n        \"hyperf/process\": \"3.0.*\",\n        \"hyperf/rate-limit\": \"3.0.*\",\n        \"hyperf/redis\": \"3.0.*\",\n        \"hyperf/rpc\": \"3.0.*\",\n        \"hyperf/rpc-client\": \"3.0.*\",\n        \"hyperf/rpc-server\": \"3.0.*\",\n        \"hyperf/service-governance\": \"3.0.*\",\n        \"hyperf/service-governance-nacos\": \"3.0.*\",\n        \"hyperf/tracer\": \"3.0.*\"\n    },\n    \"require-dev\": {\n        \"friendsofphp/php-cs-fixer\": \"^3.0\",\n        \"hyperf/devtool\": \"3.0.*\",\n        \"hyperf/ide-helper\": \"3.0.*\",\n        \"hyperf/testing\": \"3.0.*\",\n        \"hyperf/watcher\": \"3.0.*\",\n        \"mockery/mockery\": \"^1.0\",\n        \"phpstan/phpstan\": \"^0.12\",\n        \"swoole/ide-helper\": \"^4.5\"\n    },\n    \"suggest\": {\n        \"ext-openssl\": \"Required to use HTTPS.\",\n        \"ext-json\": \"Required to use JSON.\",\n        \"ext-pdo\": \"Required to use MySQL Client.\",\n        \"ext-pdo_mysql\": \"Required to use MySQL Client.\",\n        \"ext-redis\": \"Required to use Redis Client.\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\"\n        },\n        \"files\": [\n            \"app/Kernel/Functions.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"HyperfTest\\\\\": \"./test/\"\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true,\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"sort-packages\": true\n    },\n    \"extra\": [],\n    \"scripts\": {\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-autoload-dump\": [\n            \"rm -rf runtime/container\"\n        ],\n        \"test\": \"co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always\",\n        \"cs-fix\": \"php-cs-fixer fix $1\",\n        \"analyse\": \"phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config\",\n        \"start\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"php ./bin/hyperf.php start\"\n        ]\n    }\n}\n"
  },
  {
    "path": "api-gateway/config/autoload/annotations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ],\n        'ignore_annotations' => [\n            'mixin',\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/aspects.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Tracer\\Aspect\\JsonRpcAspect::class,\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/async_queue.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\AsyncQueue\\Driver\\RedisDriver::class,\n        'redis' => [\n            'pool' => 'default',\n        ],\n        'channel' => '{queue}',\n        'timeout' => 2,\n        'retry_seconds' => 5,\n        'handle_timeout' => 10,\n        'processes' => 1,\n        'concurrent' => [\n            'limit' => 10,\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/cache.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,\n        'packer' => Hyperf\\Utils\\Packer\\PhpSerializerPacker::class,\n        'prefix' => 'c:',\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/commands.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/config_center.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),\n    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),\n    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),\n    'drivers' => [\n        'nacos' => [\n            'driver' => Hyperf\\ConfigNacos\\NacosDriver::class,\n            'merge_mode' => Hyperf\\ConfigNacos\\Constants::CONFIG_MERGE_OVERWRITE,\n            'interval' => 3,\n            'default_key' => 'nacos_config',\n            'listener_config' => [\n                // dataId, group, tenant, type, content\n                'nacos_config' => [\n                    // 命名空间/ID\n                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId\n                    // DataID\n                    'data_id' => env('NACOS_DATA_ID'),\n                    // 组名\n                    'group' => 'DEFAULT_GROUP',\n                    'type' => 'json',\n                ],\n            ],\n            'client' => [\n                // 客户端\n                'host' => env('NACOS_HOST'),\n                'port' => env('NACOS_PORT'),\n                'username' => env('NACOS_USERNAME'),\n                'password' => env('NACOS_PASSWORD'),\n                'guzzle' => [\n                    'config' => null,\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/databases.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'host' => env('DB_HOST', 'localhost'),\n        'port' => env('DB_PORT', 3306),\n        'database' => env('DB_DATABASE', 'hyperf'),\n        'username' => env('DB_USERNAME', 'root'),\n        'password' => env('DB_PASSWORD', ''),\n        'charset' => env('DB_CHARSET', 'utf8mb4'),\n        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),\n        'prefix' => env('DB_PREFIX', ''),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),\n        ],\n        'cache' => [\n            'handler' => Hyperf\\ModelCache\\Handler\\RedisHandler::class,\n            'cache_key' => '{mc:%s:m:%s}:%s:%s',\n            'prefix' => 'default',\n            'ttl' => 3600 * 24,\n            'empty_model_ttl' => 600,\n            'load_script' => true,\n        ],\n        'commands' => [\n            'gen:model' => [\n                'path' => 'app/Model',\n                'force_casts' => true,\n                'inheritance' => 'Model',\n                'uses' => '',\n                'table_mapping' => [],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/dependencies.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/devtool.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n                'namespace' => 'App\\\\Amqp\\\\Consumer',\n            ],\n            'producer' => [\n                'namespace' => 'App\\\\Amqp\\\\Producer',\n            ],\n        ],\n        'aspect' => [\n            'namespace' => 'App\\\\Aspect',\n        ],\n        'command' => [\n            'namespace' => 'App\\\\Command',\n        ],\n        'controller' => [\n            'namespace' => 'App\\\\Controller',\n        ],\n        'job' => [\n            'namespace' => 'App\\\\Job',\n        ],\n        'listener' => [\n            'namespace' => 'App\\\\Listener',\n        ],\n        'middleware' => [\n            'namespace' => 'App\\\\Middleware',\n        ],\n        'Process' => [\n            'namespace' => 'App\\\\Processes',\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/exceptions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception\\Handler\\HttpExceptionHandler::class,\n            App\\Exception\\Handler\\AppExceptionHandler::class,\n            App\\Exception\\Handler\\AppServiceExceptionHandler::class,\n            App\\Exception\\Handler\\RateLimitExceptionHandler::class,\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/listeners.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/logger.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handler\\RotatingFileHandler::class,\n            'constructor' => [\n                'filename' => BASE_PATH . '/runtime/logs/hyperf.log',\n                'level' => Monolog\\Logger::DEBUG,\n            ],\n        ],\n        'formatter' => [\n            'class' => Monolog\\Formatter\\LineFormatter::class,\n            'constructor' => [\n                'format' => null,\n                'dateFormat' => 'Y-m-d H:i:s',\n                'allowInlineLineBreaks' => true,\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/middlewares.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n        \\Hyperf\\Tracer\\Middleware\\TraceMiddleware::class,\n//        \\App\\Exception\\Handler\\AppServiceExceptionHandler::class,\n    ],\n    'jsonrpc-http' => [\n        \\Hyperf\\Tracer\\Middleware\\TraceMiddleware::class,\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/nacos.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port\n    // 'url' => '',\n    // The nacos host info\n    'host' => env('NACOS_HOST'),\n    'port' => env('NACOS_PORT'),\n    // The nacos account info\n    'username' => env('NACOS_USERNAME'),\n    'password' => env('NACOS_PASSWORD'),\n    'guzzle' => [\n        'config' => null,\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/opentracing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zipkin'),\n    'enable' => [\n        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),\n        'redis' => env('TRACER_ENABLE_REDIS', false),\n        'db' => env('TRACER_ENABLE_DB', false),\n        'method' => env('TRACER_ENABLE_METHOD', false),\n    ],\n    'tracer' => [\n        'zipkin' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'options' => [\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            'sampler' => BinarySampler::createAsAlwaysSample(),\n        ],\n        'jaeger' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\JaegerTracerFactory::class,\n            'name' => env('APP_NAME', 'skeleton'),\n            'options' => [\n                'local_agent' => [\n                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),\n                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),\n                ],\n            ],\n        ],\n    ],\n    'tags' => [\n        // HTTP 客户端 (Guzzle)\n        'http_client' => [\n            'http.url' => 'http.url',\n            'http.method' => 'http.method',\n            'http.status_code' => 'http.status_code',\n        ],\n        // Redis 客户端\n        'redis' => [\n            'arguments' => 'arguments',\n            'result' => 'result',\n        ],\n        // 数据库客户端 (hyperf/database)\n        'db' => [\n            'db.query' => 'db.query',\n            'db.statement' => 'db.statement',\n            'db.query_time' => 'db.query_time',\n        ],\n    ]\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/processes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/rate_limit.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'create' => 1,\n    'consume' => 1,\n    'capacity' => 1,\n    'limitCallback' => [],\n    'waitTimeout' => 1,\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/redis.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        'auth' => env('REDIS_AUTH', null),\n        'port' => (int) env('REDIS_PORT', 6379),\n        'db' => (int) env('REDIS_DB', 0),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/server.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    'mode' => SWOOLE_PROCESS,\n    'servers' => [\n        [\n            'name' => 'http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9501,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [Hyperf\\HttpServer\\Server::class, 'onRequest'],\n            ],\n        ],\n    ],\n    'settings' => [\n        Constant::OPTION_ENABLE_COROUTINE => true,\n        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),\n        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',\n        Constant::OPTION_OPEN_TCP_NODELAY => true,\n        Constant::OPTION_MAX_COROUTINE => 100000,\n        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,\n        Constant::OPTION_MAX_REQUEST => 100000,\n        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,\n        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,\n    ],\n    'callbacks' => [\n        Event::ON_WORKER_START => [Hyperf\\Framework\\Bootstrap\\WorkerStartCallback::class, 'onWorkerStart'],\n        Event::ON_PIPE_MESSAGE => [Hyperf\\Framework\\Bootstrap\\PipeMessageCallback::class, 'onPipeMessage'],\n        Event::ON_WORKER_EXIT => [Hyperf\\Framework\\Bootstrap\\WorkerExitCallback::class, 'onWorkerExit'],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/services.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n// 这个是nacos服务的端口和地址\n$registry = [\n    'protocol' => 'nacos',\n    'address' => 'http://'.env('NACOS_HOST').':'.env('NACOS_PORT'),\n];\n\n// 这里配置需要用的rpc服务\n$services = [\n    [\n        'name' => 'OrderRpcService',\n        'service' => \\App\\JsonRpc\\OrderRpcServiceInterface::class\n    ],\n    [\n        'name' => 'UserRpcService',\n        'service' => \\App\\JsonRpc\\UserRpcServiceInterface::class\n    ],\n    [\n        'name' => 'FileRpcService',\n        'service' => \\App\\JsonRpc\\FileRpcServiceInterface::class\n    ]\n];\n\nreturn [\n    'enable' => [\n        // 开启服务发现\n        'discovery' => true,\n        // 开启服务注册\n        'register' => true,\n    ],\n    // 服务消费者相关配置\n    'consumers' => value(function () use ($services, $registry) {\n        // 循环生成rpc消费端\n        $consumers = [];\n        foreach ($services as $value) {\n            $consumers[] = [\n                'name' => $value['name'],\n                'service' => $value['service'],\n                'registry' => $registry\n            ];\n        }\n        return $consumers;\n    }),\n    // 服务提供者相关配置\n    'providers' => [],\n    // 服务驱动相关配置\n    'drivers' => [\n        // nacos 配置,当前使用\n        'nacos' => [\n            // The nacos host info\n            'host' => env('NACOS_HOST'),\n            'port' => env('NACOS_PORT'),\n            // nacos 账号密码信息\n            'username' => env('NACOS_USERNAME'),\n            'password' => env('NACOS_PASSWORD'),\n            'guzzle' => [\n                'config' => null,\n            ],\n            // 命名空间,public为默认系统空间\n            'group_name' => 'api',\n            // 命名空间ID\n             'namespace_id' => env('NACOS_TENANT'),\n            // 心跳检查秒数\n            'heartbeat' => 5,\n            'ephemeral' => true, // 是否注册临时实例\n        ],\n    ],\n];"
  },
  {
    "path": "api-gateway/config/autoload/tracer.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/25\n * @create: 11:29\n */\n\nreturn [\n    // 选择默认的 Tracer\n    'default' => env('TRACER_DRIVER', 'jaeger'),\n\n    // 这里的代码演示不对 enable 内的配置进行展开\n    'enable' => [],\n\n    'tracer' => [\n        // Zipkin 驱动配置\n        'zipkin' => [\n            // 当前应用的配置\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // 如果 ipv6 和 ipv6 为空组件会自动从 Server 中检测\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'options' => [\n                // Zipkin 服务的 endpoint 地址\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                // 请求超时秒数\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            // 采样器，默认为所有请求的都追踪\n            'sampler' => \\Zipkin\\Samplers\\BinarySampler::createAsAlwaysSample(),\n        ],\n    ],\n];"
  },
  {
    "path": "api-gateway/config/autoload/watcher.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Watcher\\Driver\\ScanFileDriver;\n\nreturn [\n    'driver' => ScanFileDriver::class,\n    'bin' => 'php',\n    'watch' => [\n        'dir' => ['app', 'config'],\n        'file' => ['.env'],\n        'scan_interval' => 2000,\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/config.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_name' => env('APP_NAME', 'skeleton'),\n    'app_env' => env('APP_ENV', 'dev'),\n    'scan_cacheable' => env('SCAN_CACHEABLE', false),\n    StdoutLoggerInterface::class => [\n        'log_level' => [\n            LogLevel::ALERT,\n            LogLevel::CRITICAL,\n//            LogLevel::DEBUG,\n            LogLevel::EMERGENCY,\n            LogLevel::ERROR,\n            LogLevel::INFO,\n            LogLevel::NOTICE,\n            LogLevel::WARNING,\n        ],\n    ],\n];\n"
  },
  {
    "path": "api-gateway/config/container.php",
    "content": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Di\\Container;\nuse Hyperf\\Di\\Definition\\DefinitionSourceFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\n$container = new Container((new DefinitionSourceFactory(true))());\n\nif (! $container instanceof \\Psr\\Container\\ContainerInterface) {\n    throw new RuntimeException('The dependency injection container is invalid.');\n}\nreturn ApplicationContext::setContainer($container);\n"
  },
  {
    "path": "api-gateway/config/routes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\\Controller\\UserController@userInfo');\n\nRouter::get('/favicon.ico', function () {\n    return '';\n});\n"
  },
  {
    "path": "api-gateway/test/Cases/ExampleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversNothing\n */\nclass ExampleTest extends HttpTestCase\n{\n    public function testExample()\n    {\n        $this->assertTrue(true);\n        $this->assertTrue(is_array($this->get('/')));\n    }\n}\n"
  },
  {
    "path": "api-gateway/test/HttpTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class HttpTestCase.\n * @method get($uri, $data = [], $headers = [])\n * @method post($uri, $data = [], $headers = [])\n * @method json($uri, $data = [], $headers = [])\n * @method file($uri, $data = [], $headers = [])\n * @method request($method, $path, $options = [])\n */\nabstract class HttpTestCase extends TestCase\n{\n    /**\n     * @var Client\n     */\n    protected $client;\n\n    public function __construct($name = null, array $data = [], $dataName = '')\n    {\n        parent::__construct($name, $data, $dataName);\n        $this->client = make(Client::class);\n    }\n\n    public function __call($name, $arguments)\n    {\n        return $this->client->{$name}(...$arguments);\n    }\n}\n"
  },
  {
    "path": "api-gateway/test/bootstrap.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_reporting(E_ALL);\ndate_default_timezone_set('Asia/Shanghai');\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nSwoole\\Runtime::enableCoroutine(true);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\nHyperf\\Di\\ClassLoader::init();\n\n$container = require BASE_PATH . '/config/container.php';\n\n$container->get(Hyperf\\Contract\\ApplicationInterface::class);\n"
  },
  {
    "path": "doc/DEPLOY_ONE.md",
    "content": "# docker安装\n\nMysql\n\n  ```bash  \n  1.安装 - 略\n  2.新建order-srv数据库\n  3.新建user-srv数据库\n```\n\nRedis\n ```bash  \n  1.安装 - 略\n```\n\nNacos\n ```bash  \n  1.docker run --name nacos-standalone -e MODE=standalone \\\n  -e JVM_XMS=512m -e JVM_XMN=256m -p 8848:8848 -d\n  nacos/nacos-server:v2.1.0\n  2.访问http://127.0.0.1:8848/nacos/#/login\n  3.用户名密码: nacos/nacos\n  4.命名空间->新建命名空间->增加空间 `dev`\n  5.配置管理->配置列表->dev->导入配置->/jin-microservices/doc/nacos_config.zip\n```\n\nRabbitmq\n ```bash  \n  1.docker run -d  --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3.9.2\n  2.docker exec -it rabbit /bin/bash\n  3.rabbitmq-plugins enable rabbitmq_management\n  4.访问http://127.0.0.1:15672 \n  5.用户名密码: guest/guest\n```\n\nELK\n\n ```bash  \n  1.vi /etc/sysctl.conf\n    #末尾添加一行\n    vm.max_map_count=262144\n    #查看结果\n    sysctl -p\n  2.docker run -p 5601:5601 -p 9200:9200 -p 5044:5044 -itd --name elk sebp/elk:7.17.1\n  3.docker exec -it elk bin/bash\n  4.cd /etc/logstash/conf.d\n  5.vim logstash.conf\n\t\t  input {\n\t\t\t  beats {\n\t\t\t\tport => 5044\n\t\t\t\tcodec => plain { charset => \"UTF-8\" }\n\t\t\t  }\n\t\t  }\n\t\t\t# 格式化日志\n\t\t  filter {\n\t\t\t  grok {\n\t\t\t\t  match => [ \"message\",\"\\[%{TIMESTAMP_ISO8601:logtime}\\] %{WORD:env}\\.(?<level>[A-Z]{4,5})\\: %{GREEDYDATA:msg}}\" ]\n\t\t\t\t  }\n\t\t   }\n\t\t   output {\n\t\t\t\telasticsearch {\n\t\t\t\t\t action => \"index\"\n\t\t\t\t\t hosts => [\"localhost\"]\n\t\t\t\t\t index => \"jm-log\"\n\t\t\t\t }\n\t\t\t}\n  6.rm 02-beats-input.conf  10-syslog.conf  11-nginx.conf  30-output.conf\n  7.docker restart elk\n  8.测试http://127.0.0.1:9200\n  9.访问http://127.0.0.1:5601/app/kibana\n```\n\nFilebeat\n ```bash \n 1.wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.13.3-linux-x86_64.tar.gz\n 2.tar -xvf filebeat-7.13.3-linux-x86_64.tar.gz\n 3.vi filebeat.yml\n    filebeat.inputs:\n      - type: log\n        paths:\n          - /jin-microservices/*/runtime/logs/*.log\n        multiline.pattern: '^\\[[0-9]{4}-[0-9]{2}-[0-9]{2}'\n        multiline.negate: true\n        multiline.match: after\n        multiline.timeout: 5s\n        scan_frequency: 5s\n    output:\n      # 输出到logstash中,logstash更换为自己的ip\n      logstash:\n        hosts: [\"127.0.0.1:5044\"]\n 4. ./filebeat-7.13.3-linux-x86_64/filebeat -e -c filebeat.yml \n ```\n\nZipkin\n\n ```bash  \n  1.docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin\n  2.访问 http://127.0.0.1:9411/zipkin/ \n```\n\nDTM\n\n ```bash  \n  1.docker run -itd  --name dtm -p 36789:36789 -p 36790:36790  yedf/dtm:1.14\n  2.访问http://127.0.0.1:36789\n```\n\n项目代码\n  ```bash  \n 1.docker run --name hyperf \\\n-v /workspace/skeleton:/data/project \\\n-p 9501:9501 -p 9502:9502  -p 9503:9503  -it  -p 9507:9507  -it \\\n--privileged -u root \\\n--entrypoint /bin/sh \\\nhyperf/hyperf:8.1-alpine-v3.15-swoole-v5\n2.docker exec -it hyperf /bin/bash\n3.cd /data/project/\n4.git clone https://github.com/Double-Jin/jin-microservices.git\n5.cd jin-microservices/api-gateway/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php start\n6.cd jin-microservices/user-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php migrate\n    php bin/hyperf.php db:seed\n    php bin/hyperf.php start\n7.cd jin-microservices/order-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php migrate\n    php bin/hyperf.php db:seed\n    php bin/hyperf.php start\n8.cd jin-microservices/task-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php start\n9.cd jin-microservices/file-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php start\n``` \n"
  },
  {
    "path": "doc/DEPLOY_TWO.md",
    "content": "# docker-composer安装\n\ndocker-compose\n\n```bash  \n 1.vi /etc/sysctl.conf\n    #末尾添加一行\n    vm.max_map_count=262144\n    #查看结果\n    sysctl -p\n 2.修改docker-composer.services.hyperf.volumes目录映射地址\n 3.docker-compose up\n 4.docker exec -it rabbit /bin/bash\n 5.rabbitmq-plugins enable rabbitmq_management\n 6.docker exec -it elk bin/bash\n 7.cd /etc/logstash/conf.d\n 8.vim logstash.conf\n\t\t  input {\n\t\t\t  beats {\n\t\t\t\tport => 5044\n\t\t\t\tcodec => plain { charset => \"UTF-8\" }\n\t\t\t  }\n\t\t  }\n\t\t\t# 格式化日志\n\t\t  filter {\n\t\t\t  grok {\n\t\t\t\t  match => [ \"message\",\"\\[%{TIMESTAMP_ISO8601:logtime}\\] %{WORD:env}\\.(?<level>[A-Z]{4,5})\\: %{GREEDYDATA:msg}}\" ]\n\t\t\t\t  }\n\t\t   }\n\t\t   output {\n\t\t\t\telasticsearch {\n\t\t\t\t\t action => \"index\"\n\t\t\t\t\t hosts => [\"localhost\"]\n\t\t\t\t\t index => \"jm-log\"\n\t\t\t\t }\n\t\t\t}\n 9.rm 02-beats-input.conf  10-syslog.conf  11-nginx.conf  30-output.conf\n 10.docker restart elk\n 11.连接mysql\n 12.新建order-srv数据库\n 13.新建user-srv数据库\n 14.访问http://127.0.0.1:8848/nacos/#/login\n 15.用户名密码: nacos/nacos\n 16.命名空间->新建命名空间->增加空间 `dev`\n 17.配置管理->配置列表->dev->导入配置->/jin-microservices/doc/nacos_config.zip\n```\n\nFilebeat\n ```bash \n 1.wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.13.3-linux-x86_64.tar.gz\n 2.tar -xvf filebeat-7.13.3-linux-x86_64.tar.gz\n 3.vi filebeat.yml\n    filebeat.inputs:\n      - type: log\n        paths:\n          - /jin-microservices/*/runtime/logs/*.log\n        multiline.pattern: '^\\[[0-9]{4}-[0-9]{2}-[0-9]{2}'\n        multiline.negate: true\n        multiline.match: after\n        multiline.timeout: 5s\n        scan_frequency: 5s\n    output:\n      # 输出到logstash中,logstash更换为自己的ip\n      logstash:\n        hosts: [\"127.0.0.1:5044\"]\n 4. ./filebeat-7.13.3-linux-x86_64/filebeat -e -c filebeat.yml \n ```\n\n验证\n```bash\n 1.访问http://127.0.0.1:8848/nacos/#/login 用户名密码: nacos/nacos\n 2.访问http://127.0.0.1:15672 用户名密码: guest/guest\n 2.访问http://127.0.0.1:9200\n 3.访问http://127.0.0.1:5601/app/kibana\n 4.访问http://127.0.0.1:9411/zipkin/ \n 5.访问http://127.0.0.1:36789\n```\n\n启动服务\n```bash\n1.docker exec -it hyperf /bin/bash\n2.cd /data/project/\n3.git clone https://github.com/Double-Jin/jin-microservices.git\n4.cd jin-microservices/api-gateway/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php start\n5.cd jin-microservices/user-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php migrate\n    php bin/hyperf.php db:seed\n    php bin/hyperf.php start\n6.cd jin-microservices/order-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php migrate\n    php bin/hyperf.php db:seed\n    php bin/hyperf.php start\n7.cd jin-microservices/task-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php start\n8.cd jin-microservices/file-srv/\n    composer update\n    复制.env.example为.env配置\n    php bin/hyperf.php start\n```\n\n"
  },
  {
    "path": "docker-compose.yaml",
    "content": "version: '3.9'\nservices:\n  hyperf:\n    container_name: hyperf\n    image: hyperf/hyperf:8.1-alpine-v3.15-swoole-v5\n    hostname: hyperf\n    restart: always\n    privileged: true\n    ports:\n      - 9501:9501\n      - 9502:9502\n      - 9503:9503\n      - 9507:9507\n    volumes:\n      - /Users/linjinjin/Documents/dnmp/www:/data/www\n    tty: true\n    networks:\n      - hyperf_networks\n\n  nacos:\n    container_name: nacos\n    image: nacos/nacos-server:v2.1.0\n    environment:\n      - MODE=standalone\n      - JVM_XMS=512m\n      - JVM_XMN=256m\n    hostname: nacos\n    restart: always\n    ports:\n      - 8848:8848\n    networks:\n      - hyperf_networks\n\n  rabbitmq:\n    container_name: rabbit\n    image: rabbitmq:3.9.2\n    hostname: rabbit\n    restart: always\n    ports:\n      - 15672:15672\n      - 5672:5672\n    networks:\n      - hyperf_networks\n\n  redis:\n    container_name: redis\n    image: redis:7.0\n    restart: always\n    hostname: redis\n    ports:\n      - 6379:6379\n    networks:\n      - hyperf_networks\n\n  elk:\n    container_name: elk\n    image: sebp/elk:7.17.1\n    restart: always\n    hostname: elk\n    ports:\n      - 5601:5601\n      - 9200:9200\n      - 5044:5044\n    networks:\n      - hyperf_networks\n\n  dtm:\n    image: yedf/dtm:1.14\n    container_name: dtm\n    hostname: dtm\n    restart: always\n    ports:\n      - \"36789:36789\"\n      - \"36790:36790\"\n    networks:\n      - hyperf_networks\n\n  zipkin:\n    image: openzipkin/zipkin:2\n    container_name: zipkin\n    hostname: zipkin\n    restart: always\n    ports:\n      - \"9411:9411\"\n    networks:\n      - hyperf_networks\n\nnetworks:\n  hyperf_networks:"
  },
  {
    "path": "file-srv/.github/workflows/Dockerfile",
    "content": "# Default Dockerfile\n#\n# @link     https://www.hyperf.io\n# @document https://hyperf.wiki\n# @contact  group@hyperf.io\n# @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n\nFROM hyperf/hyperf:8.0-alpine-v3.16-swoole\nLABEL maintainer=\"Hyperf Developers <group@hyperf.io>\" version=\"1.0\" license=\"MIT\" app.name=\"Hyperf\"\n\n##\n# ---------- env settings ----------\n##\n# --build-arg timezone=Asia/Shanghai\nARG timezone\n\nENV TIMEZONE=${timezone:-\"Asia/Shanghai\"} \\\n    APP_ENV=prod \\\n    SCAN_CACHEABLE=(true)\n\n# update\nRUN set -ex \\\n    # show php version and extensions\n    && php -v \\\n    && php -m \\\n    && php --ri swoole \\\n    #  ---------- some config ----------\n    && cd /etc/php* \\\n    # - config PHP\n    && { \\\n        echo \"upload_max_filesize=128M\"; \\\n        echo \"post_max_size=128M\"; \\\n        echo \"memory_limit=1G\"; \\\n        echo \"date.timezone=${TIMEZONE}\"; \\\n    } | tee conf.d/99_overrides.ini \\\n    # - config timezone\n    && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \\\n    && echo \"${TIMEZONE}\" > /etc/timezone \\\n    # ---------- clear works ----------\n    && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \\\n    && echo -e \"\\033[42;37m Build Completed :).\\033[0m\\n\"\n\nWORKDIR /opt/www\n\n# Composer Cache\n# COPY ./composer.* /opt/www/\n# RUN composer install --no-dev --no-scripts\n\nCOPY . /opt/www\nRUN print \"\\n\" | composer install -o && php bin/hyperf.php\n\nEXPOSE 9501\n\nENTRYPOINT [\"php\", \"/opt/www/bin/hyperf.php\", \"start\"]\n"
  },
  {
    "path": "file-srv/.github/workflows/build.yml",
    "content": "name: Build Docker\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n      - name: Build\n        run: cp -rf .github/workflows/Dockerfile . && docker build -t hyperf .\n"
  },
  {
    "path": "file-srv/.github/workflows/release.yml",
    "content": "on:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\nname: Release\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n      - name: Create Release\n        id: create_release\n        uses: actions/create-release@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: ${{ github.ref }}\n          release_name: Release ${{ github.ref }}\n          draft: false\n          prerelease: false\n"
  },
  {
    "path": "file-srv/.gitignore",
    "content": ".buildpath\n.settings/\n.project\n*.patch\n.idea/\n.git/\nruntime/\nvendor/\n.phpintel/\n.env\n.DS_Store\n.phpunit*\n*.cache\n"
  },
  {
    "path": "file-srv/.watcher.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nuse Hyperf\\Watcher\\Driver\\ScanFileDriver;\n\nreturn [\n    'driver' => ScanFileDriver::class,\n    'bin' => 'php',\n    'watch' => [\n        'dir' => ['app', 'config'],\n        'file' => ['.env'],\n        'scan_interval' => 2000,\n    ],\n];\n"
  },
  {
    "path": "file-srv/app/Constants/ErrorCode.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n#[Constants]\nclass ErrorCode extends AbstractConstants\n{\n    /**\n     * @Message(\"Server Error！\")\n     */\n    public const SERVER_ERROR = 500;\n}\n"
  },
  {
    "path": "file-srv/app/Controller/AbstractController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Contract\\ResponseInterface;\nuse Psr\\Container\\ContainerInterface;\n\nabstract class AbstractController\n{\n    #[Inject]\n    protected ContainerInterface $container;\n\n    #[Inject]\n    protected RequestInterface $request;\n\n    #[Inject]\n    protected ResponseInterface $response;\n}\n"
  },
  {
    "path": "file-srv/app/Controller/IndexController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Controller;\n\nclass IndexController extends AbstractController\n{\n    public function index()\n    {\n        $user = $this->request->input('user', 'Hyperf');\n        $method = $this->request->getMethod();\n\n        return [\n            'method' => $method,\n            'message' => \"Hello {$user}.\",\n        ];\n    }\n}\n"
  },
  {
    "path": "file-srv/app/Exception/BusinessException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass BusinessException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "file-srv/app/Exception/Handler/AppExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Exception\\Handler;\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Throwable;\n\nclass AppExceptionHandler extends ExceptionHandler\n{\n    public function __construct(protected StdoutLoggerInterface $logger)\n    {\n    }\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n        $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));\n        $this->logger->error($throwable->getTraceAsString());\n        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "file-srv/app/Exception/JsonRpcException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass JsonRpcException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "file-srv/app/JsonRpc/FileRpcService.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\nuse App\\Services\\AuthService;\nuse App\\Services\\FileService;\nuse Hyperf\\RpcServer\\Annotation\\RpcService;\nuse App\\Services\\UserService;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * 文件rpc服务\n * Class OrderRpcService\n * @package App\\JsonRpc\n */\n#[RpcService(name: \"FileRpcService\", protocol: \"jsonrpc-http\", server: \"jsonrpc-http\", publishTo: \"nacos\")]\nclass FileRpcService implements FileRpcServiceInterface\n{\n    #[Inject]\n    protected FileService $fileService;\n\n    /**\n     * 上传文件\n     * @param string $type\n     * @param string $base64string\n     * @param string $fileName\n     * @return array\n     */\n    public function uploadFile(string $type,string $base64string,string $fileName): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->fileService->uploadFile($type,$base64string,$fileName)\n        ];\n    }\n\n}"
  },
  {
    "path": "file-srv/app/JsonRpc/FileRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/12/20\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface FileRpcServiceInterface\n{\n\n    public function uploadFile(string $type, string $base64string, string $fileName): array;\n\n}"
  },
  {
    "path": "file-srv/app/Listener/DbQueryExecutedListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\Arr;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\n\n#[Listener]\nclass DbQueryExecutedListener implements ListenerInterface\n{\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->logger = $container->get(LoggerFactory::class)->get('sql');\n    }\n\n    public function listen(): array\n    {\n        return [\n            QueryExecuted::class,\n        ];\n    }\n\n    /**\n     * @param QueryExecuted $event\n     */\n    public function process(object $event): void\n    {\n        if ($event instanceof QueryExecuted) {\n            $sql = $event->sql;\n            if (! Arr::isAssoc($event->bindings)) {\n                $position = 0;\n                foreach ($event->bindings as $value) {\n                    $position = strpos($sql, '?', $position);\n                    if ($position === false) {\n                        break;\n                    }\n                    $value = \"'{$value}'\";\n                    $sql = substr_replace($sql, $value, $position, 1);\n                    $position += strlen($value);\n                }\n            }\n\n            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));\n        }\n    }\n}\n"
  },
  {
    "path": "file-srv/app/Listener/ResumeExitCoordinatorListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Listener;\n\nuse Hyperf\\Command\\Event\\AfterExecute;\nuse Hyperf\\Coordinator\\Constants;\nuse Hyperf\\Coordinator\\CoordinatorManager;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\n\n#[Listener]\nclass ResumeExitCoordinatorListener implements ListenerInterface\n{\n    public function listen(): array\n    {\n        return [\n            AfterExecute::class,\n        ];\n    }\n\n    public function process(object $event): void\n    {\n        CoordinatorManager::until(Constants::WORKER_EXIT)->resume();\n    }\n}\n"
  },
  {
    "path": "file-srv/app/Log.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\nclass Log\n{\n    public static function get(string $name = 'app')\n    {\n        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);\n    }\n}"
  },
  {
    "path": "file-srv/app/Model/Model.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model as BaseModel;\nuse Hyperf\\ModelCache\\Cacheable;\nuse Hyperf\\ModelCache\\CacheableInterface;\n\nabstract class Model extends BaseModel implements CacheableInterface\n{\n    use Cacheable;\n}\n"
  },
  {
    "path": "file-srv/app/Services/FileService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\JsonRpcException;\nuse App\\Log;\n\n/**\n * 文件service\n * Class UserService\n * @package App\\Services\n */\nclass FileService\n{\n\n    /**\n     * 上传文件\n     * @param $type 文件类型\n     * @param $base64string base64数据\n     * @param $fileName 文件名\n     * @return array|mixed[]\n     */\n    public function uploadFile(string $type,string $base64string,string $fileName)\n    {\n        Log::get()->info(\"调用uploadFile\");\n\n        try {\n\n            if (!file_exists(config('file.storage.local.root'))){\n                @mkdir(config('file.storage.local.root'), 0755, true);\n            }\n\n            $filePath = config('file.storage.local.root').'/'.$fileName;\n\n            //base64转换成文件\n            $baseFile = str_replace( 'data:' . $type . ';base64,', '', $base64string);\n            $newFile = fopen( $filePath, \"wb\" );\n            fwrite( $newFile, base64_decode( $baseFile) );\n            fclose( $newFile );\n\n        } catch (\\Throwable $ex) {\n\n            Log::get()->info(\"rpc调用失败\");\n\n            throw new JsonRpcException(430);\n        }\n\n        return [\n            'file_name' => $fileName,\n            'file_path' => $filePath\n        ];\n\n    }\n\n}"
  },
  {
    "path": "file-srv/bin/hyperf.php",
    "content": "#!/usr/bin/env php\n<?php\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limit', '1G');\n\nerror_reporting(E_ALL);\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\n// Self-called anonymous function that creates its own scope and keep the global namespace clean.\n(function () {\n    Hyperf\\Di\\ClassLoader::init();\n    /** @var Psr\\Container\\ContainerInterface $container */\n    $container = require BASE_PATH . '/config/container.php';\n\n    $application = $container->get(Hyperf\\Contract\\ApplicationInterface::class);\n    $application->run();\n})();\n"
  },
  {
    "path": "file-srv/composer.json",
    "content": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n        \"framework\",\n        \"hyperf\",\n        \"microservice\",\n        \"middleware\"\n    ],\n    \"description\": \"A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.\",\n    \"license\": \"Apache-2.0\",\n    \"require\": {\n        \"php\": \">=8.0\",\n        \"hyperf/cache\": \"3.0.*\",\n        \"hyperf/command\": \"3.0.*\",\n        \"hyperf/config\": \"3.0.*\",\n        \"hyperf/config-nacos\": \"3.0.*\",\n        \"hyperf/constants\": \"3.0.*\",\n        \"hyperf/database\": \"3.0.*\",\n        \"hyperf/db-connection\": \"3.0.*\",\n        \"hyperf/filesystem\": \"3.0.*\",\n        \"hyperf/framework\": \"3.0.*\",\n        \"hyperf/guzzle\": \"3.0.*\",\n        \"hyperf/http-server\": \"3.0.*\",\n        \"hyperf/json-rpc\": \"3.0.*\",\n        \"hyperf/logger\": \"3.0.*\",\n        \"hyperf/memory\": \"3.0.*\",\n        \"hyperf/model-cache\": \"3.0.*\",\n        \"hyperf/process\": \"3.0.*\",\n        \"hyperf/redis\": \"3.0.*\",\n        \"hyperf/rpc\": \"3.0.*\",\n        \"hyperf/rpc-client\": \"3.0.*\",\n        \"hyperf/rpc-server\": \"3.0.*\",\n        \"hyperf/service-governance\": \"3.0.*\",\n        \"hyperf/service-governance-nacos\": \"3.0.*\",\n        \"hyperf/tracer\": \"3.0.*\"\n    },\n    \"require-dev\": {\n        \"friendsofphp/php-cs-fixer\": \"^3.0\",\n        \"hyperf/devtool\": \"3.0.*\",\n        \"hyperf/testing\": \"3.0.*\",\n        \"mockery/mockery\": \"^1.0\",\n        \"phpstan/phpstan\": \"^1.0\",\n        \"swoole/ide-helper\": \"^5.0\",\n        \"hyperf/watcher\": \"3.0.*\"\n    },\n    \"suggest\": {\n        \"ext-openssl\": \"Required to use HTTPS.\",\n        \"ext-json\": \"Required to use JSON.\",\n        \"ext-pdo\": \"Required to use MySQL Client.\",\n        \"ext-pdo_mysql\": \"Required to use MySQL Client.\",\n        \"ext-redis\": \"Required to use Redis Client.\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\"\n        },\n        \"files\": []\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"HyperfTest\\\\\": \"./test/\"\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true,\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"sort-packages\": true\n    },\n    \"extra\": [],\n    \"scripts\": {\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-autoload-dump\": [\n            \"rm -rf runtime/container\"\n        ],\n        \"test\": \"co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always\",\n        \"cs-fix\": \"php-cs-fixer fix $1\",\n        \"analyse\": \"phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config\",\n        \"start\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"php ./bin/hyperf.php start\"\n        ]\n    }\n}\n"
  },
  {
    "path": "file-srv/config/autoload/annotations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ],\n        'ignore_annotations' => [\n            'mixin',\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/aspects.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n];\n"
  },
  {
    "path": "file-srv/config/autoload/cache.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,\n        'packer' => Hyperf\\Utils\\Packer\\PhpSerializerPacker::class,\n        'prefix' => 'c:',\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/commands.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n];\n"
  },
  {
    "path": "file-srv/config/autoload/config_center.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),\n    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),\n    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),\n    'drivers' => [\n        'nacos' => [\n            'driver' => Hyperf\\ConfigNacos\\NacosDriver::class,\n            'merge_mode' => Hyperf\\ConfigNacos\\Constants::CONFIG_MERGE_OVERWRITE,\n            'interval' => 3,\n            'default_key' => 'nacos_config',\n            'listener_config' => [\n                // dataId, group, tenant, type, content\n                'nacos_config' => [\n                    // 命名空间/ID\n                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId\n                    // DataID\n                    'data_id' => env('NACOS_DATA_ID'),\n                    // 组名\n                    'group' => 'DEFAULT_GROUP',\n                    'type' => 'json',\n                ],\n            ],\n            'client' => [\n                // 客户端\n                'host' => env('NACOS_HOST'),\n                'port' => env('NACOS_PORT'),\n                'username' => env('NACOS_USERNAME'),\n                'password' => env('NACOS_PASSWORD'),\n                'guzzle' => [\n                    'config' => null,\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/databases.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'host' => env('DB_HOST', 'localhost'),\n        'port' => env('DB_PORT', 3306),\n        'database' => env('DB_DATABASE', 'hyperf'),\n        'username' => env('DB_USERNAME', 'root'),\n        'password' => env('DB_PASSWORD', ''),\n        'charset' => env('DB_CHARSET', 'utf8mb4'),\n        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),\n        'prefix' => env('DB_PREFIX', ''),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),\n        ],\n        'cache' => [\n            'handler' => Hyperf\\ModelCache\\Handler\\RedisHandler::class,\n            'cache_key' => '{mc:%s:m:%s}:%s:%s',\n            'prefix' => 'default',\n            'ttl' => 3600 * 24,\n            'empty_model_ttl' => 600,\n            'load_script' => true,\n        ],\n        'commands' => [\n            'gen:model' => [\n                'path' => 'app/Model',\n                'force_casts' => true,\n                'inheritance' => 'Model',\n                'uses' => '',\n                'table_mapping' => [],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/dependencies.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n];\n"
  },
  {
    "path": "file-srv/config/autoload/devtool.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n                'namespace' => 'App\\\\Amqp\\\\Consumer',\n            ],\n            'producer' => [\n                'namespace' => 'App\\\\Amqp\\\\Producer',\n            ],\n        ],\n        'aspect' => [\n            'namespace' => 'App\\\\Aspect',\n        ],\n        'command' => [\n            'namespace' => 'App\\\\Command',\n        ],\n        'controller' => [\n            'namespace' => 'App\\\\Controller',\n        ],\n        'job' => [\n            'namespace' => 'App\\\\Job',\n        ],\n        'listener' => [\n            'namespace' => 'App\\\\Listener',\n        ],\n        'middleware' => [\n            'namespace' => 'App\\\\Middleware',\n        ],\n        'Process' => [\n            'namespace' => 'App\\\\Processes',\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/exceptions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception\\Handler\\HttpExceptionHandler::class,\n            App\\Exception\\Handler\\AppExceptionHandler::class,\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/file.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'default' => 'local',\n    'storage' => [\n        'local' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\LocalAdapterFactory::class,\n            'root' => __DIR__ . '/../../public/uploads/',\n        ],\n        'ftp' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\FtpAdapterFactory::class,\n            'host' => 'ftp.example.com',\n            'username' => 'username',\n            'password' => 'password',\n            // 'port' => 21,\n            // 'root' => '/path/to/root',\n            // 'passive' => true,\n            // 'ssl' => true,\n            // 'timeout' => 30,\n            // 'ignorePassiveAddress' => false,\n            // 'timestampsOnUnixListingsEnabled' => true,\n        ],\n        'memory' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\MemoryAdapterFactory::class,\n        ],\n        's3' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\S3AdapterFactory::class,\n            'credentials' => [\n                'key' => env('S3_KEY'),\n                'secret' => env('S3_SECRET'),\n            ],\n            'region' => env('S3_REGION'),\n            'version' => 'latest',\n            'bucket_endpoint' => false,\n            'use_path_style_endpoint' => false,\n            'endpoint' => env('S3_ENDPOINT'),\n            'bucket_name' => env('S3_BUCKET'),\n        ],\n        'minio' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\S3AdapterFactory::class,\n            'credentials' => [\n                'key' => env('S3_KEY'),\n                'secret' => env('S3_SECRET'),\n            ],\n            'region' => env('S3_REGION'),\n            'version' => 'latest',\n            'bucket_endpoint' => false,\n            'use_path_style_endpoint' => true,\n            'endpoint' => env('S3_ENDPOINT'),\n            'bucket_name' => env('S3_BUCKET'),\n        ],\n        'oss' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\AliyunOssAdapterFactory::class,\n            'accessId' => env('OSS_ACCESS_ID'),\n            'accessSecret' => env('OSS_ACCESS_SECRET'),\n            'bucket' => env('OSS_BUCKET'),\n            'endpoint' => env('OSS_ENDPOINT'),\n            // 'timeout' => 3600,\n            // 'connectTimeout' => 10,\n            // 'isCName' => false,\n            // 'token' => null,\n            // 'proxy' => null,\n        ],\n        'qiniu' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\QiniuAdapterFactory::class,\n            'accessKey' => env('QINIU_ACCESS_KEY'),\n            'secretKey' => env('QINIU_SECRET_KEY'),\n            'bucket' => env('QINIU_BUCKET'),\n            'domain' => env('QINBIU_DOMAIN'),\n        ],\n        'cos' => [\n            'driver' => \\Hyperf\\Filesystem\\Adapter\\CosAdapterFactory::class,\n            'region' => env('COS_REGION'),\n            'app_id' => env('COS_APPID'),\n            'secret_id' => env('COS_SECRET_ID'),\n            'secret_key' => env('COS_SECRET_KEY'),\n            // 可选，如果 bucket 为私有访问请打开此项\n            // 'signed_url' => false,\n            'bucket' => env('COS_BUCKET'),\n            'read_from_cdn' => false,\n            // 'timeout' => 60,\n            // 'connect_timeout' => 60,\n            // 'cdn' => '',\n            // 'scheme' => 'https',\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/listeners.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    Hyperf\\ExceptionHandler\\Listener\\ErrorExceptionHandler::class,\n    Hyperf\\Command\\Listener\\FailToHandleListener::class,\n];\n"
  },
  {
    "path": "file-srv/config/autoload/logger.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handler\\StreamHandler::class,\n            'constructor' => [\n                'stream' => BASE_PATH . '/runtime/logs/hyperf.log',\n                'level' => Monolog\\Logger::DEBUG,\n            ],\n        ],\n        'formatter' => [\n            'class' => Monolog\\Formatter\\LineFormatter::class,\n            'constructor' => [\n                'format' => null,\n                'dateFormat' => 'Y-m-d H:i:s',\n                'allowInlineLineBreaks' => true,\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/middlewares.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'http' => [\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/nacos.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port\n    // 'url' => '',\n    // The nacos host info\n    'host' => env('NACOS_HOST'),\n    'port' => env('NACOS_PORT'),\n    // The nacos account info\n    'username' => env('NACOS_USERNAME'),\n    'password' => env('NACOS_PASSWORD'),\n    'guzzle' => [\n        'config' => null,\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/opentracing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zipkin'),\n    'enable' => [\n        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),\n        'redis' => env('TRACER_ENABLE_REDIS', false),\n        'db' => env('TRACER_ENABLE_DB', false),\n        'method' => env('TRACER_ENABLE_METHOD', false),\n    ],\n    'tracer' => [\n        'zipkin' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'options' => [\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            'sampler' => BinarySampler::createAsAlwaysSample(),\n        ],\n        'jaeger' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\JaegerTracerFactory::class,\n            'name' => env('APP_NAME', 'skeleton'),\n            'options' => [\n                'local_agent' => [\n                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),\n                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),\n                ],\n            ],\n        ],\n    ],\n    'tags' => [\n        // HTTP 客户端 (Guzzle)\n        'http_client' => [\n            'http.url' => 'http.url',\n            'http.method' => 'http.method',\n            'http.status_code' => 'http.status_code',\n        ],\n        // Redis 客户端\n        'redis' => [\n            'arguments' => 'arguments',\n            'result' => 'result',\n        ],\n        // 数据库客户端 (hyperf/database)\n        'db' => [\n            'db.query' => 'db.query',\n            'db.statement' => 'db.statement',\n            'db.query_time' => 'db.query_time',\n        ],\n    ]\n];\n"
  },
  {
    "path": "file-srv/config/autoload/processes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n];\n"
  },
  {
    "path": "file-srv/config/autoload/redis.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        'auth' => env('REDIS_AUTH', null),\n        'port' => (int) env('REDIS_PORT', 6379),\n        'db' => (int) env('REDIS_DB', 0),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/server.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    'mode' => SWOOLE_PROCESS,\n    'servers' => [\n        [\n            'name' => 'jsonrpc-http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9507,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [\\Hyperf\\JsonRpc\\HttpServer::class, 'onRequest'],\n            ],\n            'settings' => [\n                'open_length_check' => true,\n                'package_length_type' => 'N',\n                'package_length_offset' => 0,\n                'package_body_offset' => 4,\n                'package_max_length' => 1024 * 1024 * 20,\n            ],\n        ],\n    ],\n    'settings' => [\n        Constant::OPTION_ENABLE_COROUTINE => true,\n        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),\n        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',\n        Constant::OPTION_OPEN_TCP_NODELAY => true,\n        Constant::OPTION_MAX_COROUTINE => 100000,\n        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,\n        Constant::OPTION_MAX_REQUEST => 100000,\n        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,\n        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,\n    ],\n    'callbacks' => [\n        Event::ON_WORKER_START => [Hyperf\\Framework\\Bootstrap\\WorkerStartCallback::class, 'onWorkerStart'],\n        Event::ON_PIPE_MESSAGE => [Hyperf\\Framework\\Bootstrap\\PipeMessageCallback::class, 'onPipeMessage'],\n        Event::ON_WORKER_EXIT => [Hyperf\\Framework\\Bootstrap\\WorkerExitCallback::class, 'onWorkerExit'],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/autoload/services.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n\nreturn [\n    'enable' => [\n        // 开启服务发现\n        'discovery' => true,\n        // 开启服务注册\n        'register' => true,\n    ],\n    // 服务消费者相关配置\n    'consumers' => [],\n    // 服务提供者相关配置\n    'providers' => [],\n    // 服务驱动相关配置\n    'drivers' => [\n        // nacos 配置,当前使用\n        'nacos' => [\n            // The nacos host info\n            'host' => env('NACOS_HOST'),\n            'port' => env('NACOS_PORT'),\n            // nacos 账号密码信息\n            'username' => env('NACOS_USERNAME'),\n            'password' => env('NACOS_PASSWORD'),\n            'guzzle' => [\n                'config' => null,\n            ],\n            // 命名空间,public为默认系统空间\n            'group_name' => 'api',\n            // 命名空间ID\n            'namespace_id' => env('NACOS_TENANT'),\n            // 心跳检查秒数\n            'heartbeat' => 5,\n            'ephemeral' => true, // 是否注册临时实例\n        ],\n    ],\n];"
  },
  {
    "path": "file-srv/config/config.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_name' => env('APP_NAME', 'skeleton'),\n    'app_env' => env('APP_ENV', 'dev'),\n    'scan_cacheable' => env('SCAN_CACHEABLE', false),\n    StdoutLoggerInterface::class => [\n        'log_level' => [\n            LogLevel::ALERT,\n            LogLevel::CRITICAL,\n//            LogLevel::DEBUG,\n            LogLevel::EMERGENCY,\n            LogLevel::ERROR,\n            LogLevel::INFO,\n            LogLevel::NOTICE,\n            LogLevel::WARNING,\n        ],\n    ],\n];\n"
  },
  {
    "path": "file-srv/config/container.php",
    "content": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nuse Hyperf\\Di\\Container;\nuse Hyperf\\Di\\Definition\\DefinitionSourceFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\n$container = new Container((new DefinitionSourceFactory())());\n\nreturn ApplicationContext::setContainer($container);\n"
  },
  {
    "path": "file-srv/config/routes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\\Controller\\IndexController@index');\n\nRouter::get('/favicon.ico', function () {\n    return '';\n});\n"
  },
  {
    "path": "file-srv/test/Cases/ExampleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversNothing\n */\nclass ExampleTest extends HttpTestCase\n{\n    public function testExample()\n    {\n        $this->assertTrue(true);\n        $this->assertTrue(is_array($this->get('/')));\n    }\n}\n"
  },
  {
    "path": "file-srv/test/HttpTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class HttpTestCase.\n * @method get($uri, $data = [], $headers = [])\n * @method post($uri, $data = [], $headers = [])\n * @method json($uri, $data = [], $headers = [])\n * @method file($uri, $data = [], $headers = [])\n * @method request($method, $path, $options = [])\n */\nabstract class HttpTestCase extends TestCase\n{\n    /**\n     * @var Client\n     */\n    protected $client;\n\n    public function __construct($name = null, array $data = [], $dataName = '')\n    {\n        parent::__construct($name, $data, $dataName);\n        $this->client = make(Client::class);\n    }\n\n    public function __call($name, $arguments)\n    {\n        return $this->client->{$name}(...$arguments);\n    }\n}\n"
  },
  {
    "path": "file-srv/test/bootstrap.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://hyperf.wiki\n * @contact  group@hyperf.io\n * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n */\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_reporting(E_ALL);\ndate_default_timezone_set('Asia/Shanghai');\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nSwoole\\Runtime::enableCoroutine(true);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\nHyperf\\Di\\ClassLoader::init();\n\n$container = require BASE_PATH . '/config/container.php';\n\n$container->get(Hyperf\\Contract\\ApplicationInterface::class);\n"
  },
  {
    "path": "order-srv/app/Amqp/Producer/OrderProducer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Producer;\n\nuse Hyperf\\Amqp\\Annotation\\Producer;\nuse Hyperf\\Amqp\\Message\\ProducerMessage;\n\n/**\n * 订单订阅消息生产者\n * Class OrderProducer\n * @package App\\Amqp\\Producer\n */\n#[Producer(exchange: 'order', routingKey: 'order')]\nclass OrderProducer extends ProducerMessage\n{\n    public function __construct($data)\n    {\n        $this->payload = $data;\n    }\n}\n"
  },
  {
    "path": "order-srv/app/Constants/ErrorCode.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n#[Constants]\nclass ErrorCode extends AbstractConstants\n{\n    /**\n     * @Message(\"Server Error！\")\n     */\n    const SERVER_ERROR = 500;\n}"
  },
  {
    "path": "order-srv/app/Constants/ResponseCode.php",
    "content": "<?php\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n#[Constants]\nclass ResponseCode extends AbstractConstants\n{\n    /**\n     * @Message(\"请求错误\");\n     */\n    const ERROR = 0;\n    /**\n     * @Message(\"成功\");\n     */\n    const SUCCESS = 200;\n    /**\n     * @Message(\"创建成功\");\n     */\n    const CREATE_ED = 201;\n    /**\n     * 请求成功但服务器未处理，响应中包含指示信息\n     * @Message(\"请求成功\");\n     */\n    const ACCEPT_ED = 202;\n    /**\n     * 请求成功，但是没有响应内容\n     * @Message(\"请求成功\");\n     */\n    const NO_CONTENT = 204;\n    /**\n     * 请求成功，缓存生效\n     * @Message(\"NO_TMODIFIED\");\n     */\n    const NO_TMODIFIED = 302;\n    /**\n     * 请求错误，无法解析请求体\n     * @Message(\"请求错误\");\n     */\n    const BAD_REQUEST = 400;\n    /**\n     * 认证失败\n     * @Message(\"请登录\");\n     */\n    const UNAUTHORIZED = 401;\n    /**\n     * 服务器已经接受到请求，但拒绝执行\n     * @Message(\"FORBIDDEN\");\n     */\n    const FORBIDDEN = 403;\n    /**\n     * 找不到请求的资源\n     * @Message(\"找不到请求的资源\");\n     */\n    const NOT_FOUND = 404;\n    /**\n     * 方法不允许当前用户访问\n     * @Message(\"METHOD_NOT_ALLOWED\");\n     */\n    const METHOD_NOT_ALLOWED = 405;\n    /**\n     * 请求资源已过期\n     * @Message(\"GONE\");\n     */\n    const GONE = 410;\n    /**\n     * 请求体内的类型错误\n     * @Message(\"MEDIA_TYPE\");\n     */\n    const MEDIA_TYPE = 405;\n    /**\n     * 验证失败\n     * @Message(\"验证失败\");\n     */\n    const UNPROCESSABLE = 422;\n    /**\n     * 请求频繁\n     * @Message(\"请求频繁\");\n     */\n    const MAX_REQUEST = 429;\n}"
  },
  {
    "path": "order-srv/app/Controller/AbstractController.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Contract\\ResponseInterface;\nuse Psr\\Container\\ContainerInterface;\n\nabstract class AbstractController\n{\n    \n    #[Inject]\n    protected ContainerInterface $container;\n    \n    #[Inject]\n    protected RequestInterface $request;\n    \n    #[Inject]\n    protected ResponseInterface $response;\n}"
  },
  {
    "path": "order-srv/app/Controller/SagaController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\OrderService;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\PostMapping;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * DTM.SAGA回调控制器\n * Class SagaController\n * @package App\\Controller\n */\n#[Controller(prefix: '/saga')]\nclass SagaController extends AbstractController\n{\n    /**\n     * 注入OrderService\n     * @var OrderService\n     */\n    #[Inject]\n    protected OrderService $orderService;\n\n    /**\n     * 订单创建成功\n     * @param RequestInterface $request\n     * @return string[]\n     */\n    #[PostMapping(path: 'sageCreateOrder')]\n    public function sageCreateOrder(RequestInterface $request): array\n    {\n        //调用orderService.sageCreateOrder方法\n        $this->orderService->sageCreateOrder($request->all());\n\n        return [\n            'dtm_result' => 'SUCCESS',\n        ];\n    }\n\n    /**\n     * 订单创建成功补偿\n     * @param RequestInterface $request\n     * @return string[]\n     */\n    #[PostMapping(path: 'sageCreateOrderCompensate')]\n    public function sageCreateOrderCompensate(RequestInterface $request): array\n    {\n        //调用orderService.sageCreateOrderCompensate方法\n        $this->orderService->sageCreateOrderCompensate($request->all());\n\n        return [\n            'dtm_result' => 'SUCCESS',\n        ];\n    }\n\n}\n"
  },
  {
    "path": "order-srv/app/Exception/Handler/DtmExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\JsonRpcException;\nuse App\\Exception\\ServiceException;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Hyperf\\Utils\\Context;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Throwable;\n\n/**\n * DTM异常处理\n * Class JsonRpcExceptionHandler\n * @package App\\Exception\\Handler\n */\nclass DtmExceptionHandler extends ExceptionHandler\n{\n    /**\n     * @var StdoutLoggerInterface\n     */\n    protected $logger;\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n\n        if ($throwable instanceof ServiceException) {\n\n            //阻止异常冒泡\n            $this->stopPropagation();\n\n            return $response->withStatus(409);\n        }\n\n        // 交给下一个异常处理器\n        return $response;\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "order-srv/app/Exception/Handler/JsonRpcExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\JsonRpcException;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Hyperf\\Context\\Context;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Throwable;\n\n/**\n * jsonRpc异常处理\n * Class JsonRpcExceptionHandler\n * @package App\\Exception\\Handler\n */\nclass JsonRpcExceptionHandler extends ExceptionHandler\n{\n    /**\n     * @var StdoutLoggerInterface\n     */\n    protected $logger;\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n\n        if ($throwable instanceof JsonRpcException) {\n\n\n            //阻止异常冒泡\n            $this->stopPropagation();\n\n            $request =  Context::get(ServerRequestInterface::class);\n            $jsonRpcTreaty = $request->getAttribute('data');\n            //返回自定义错误数据\n//            return di(ResponseBuilder::class)->buildResponse($request,$response);\n            $result = responseError($throwable->getCode(), $throwable->getMessage());\n\n            $jsonRpc = [\n                \"jsonrpc\" => $jsonRpcTreaty['jsonrpc'],\n                \"id\" => $jsonRpcTreaty['id'],\n                \"result\" => $result,\n                \"context\" => ''\n            ];\n\n            return $response->withStatus($throwable->getCode())\n                ->withAddedHeader('content-type', 'application/json; charset=utf-8')\n                ->withBody(new SwooleStream(json_encode($jsonRpc, JSON_UNESCAPED_UNICODE)));\n        }\n\n        // 交给下一个异常处理器\n        return $response;\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "order-srv/app/Exception/JsonRpcException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass JsonRpcException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "order-srv/app/Exception/ServiceException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass ServiceException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "order-srv/app/JsonRpc/OrderRpcService.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\nuse Hyperf\\RpcServer\\Annotation\\RpcService;\nuse App\\Services\\OrderService;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * 订单rpc服务\n * Class OrderRpcService\n * @package App\\JsonRpc\n */\n#[RpcService(name:\"OrderRpcService\", protocol:\"jsonrpc-http\", server:\"jsonrpc-http\", publishTo:\"nacos\")]\nclass OrderRpcService implements OrderRpcServiceInterface\n{\n    /**\n     * 注入OrderService\n     * @var OrderService\n     */\n    #[Inject]\n    protected OrderService $orderService;\n\n    /**\n     * 订单列表\n     * @param int $userId\n     * @return array\n     */\n    public function orderList(int $userId): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->orderService->orderList($userId)\n        ];\n    }\n\n    /**\n     * 创建订单\n     * @param array $data\n     * @return array\n     */\n    public function createOrder(array $data): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->orderService->createOrder($data)\n        ];\n    }\n\n    /**\n     * 投递订单消息到RabbitMQ\n     * @return array\n     */\n    public function orderRabbitMQ() : array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->orderService->orderRabbitMQ()\n        ];\n    }\n}"
  },
  {
    "path": "order-srv/app/JsonRpc/OrderRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface OrderRpcServiceInterface\n{\n\n    public function orderList(int $userId): array;\n\n    public function createOrder(array $data): array;\n\n    public function orderRabbitMQ(): array;\n\n}"
  },
  {
    "path": "order-srv/app/JsonRpc/UserRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface UserRpcServiceInterface\n{\n\n    public function userInfo(int $userId): array;\n    \n    public function userBonusList(int $page, int $pageSize): array;\n\n    public function userStoredList(int $page, int $pageSize): array;\n\n    public function userRabbitMQ(): array;\n\n    public function userLogin(string $phone): array;\n\n    public function userLogout(string $token): array;\n\n\n}"
  },
  {
    "path": "order-srv/app/Kernel/Functions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://doc.hyperf.io\n * @contact  group@hyperf.io\n */\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Hyperf\\Redis\\Redis;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\Formatter\\FormatterInterface;\n\n/**\n * 获取Container\n */\nif (!function_exists('di')) {\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     * @param null|mixed $id\n     * @return mixed|\\Psr\\Container\\ContainerInterface\n     */\n    function di($id = null)\n    {\n        $container = ApplicationContext::getContainer();\n        if ($id) {\n            return $container->get($id);\n        }\n        return $container;\n    }\n}\n\n/**\n * 控制台日志\n */\nif (!function_exists('stdLog')) {\n    function stdLog()\n    {\n        return di()->get(StdoutLoggerInterface::class);\n    }\n}\n\n/**\n * 文件日志\n */\nif (!function_exists('logger')) {\n    function logger($name = 'log', $group = 'default')\n    {\n        return di()->get(LoggerFactory::class)->get($name, $group);\n    }\n}\n\n/**\n * redis 客户端实例\n */\nif (!function_exists('redis')) {\n    function redis()\n    {\n        return di()->get(Redis::class);\n    }\n}\n\n/**\n * 缓存实例 简单的缓存\n */\nif (!function_exists('cache')) {\n    function cache()\n    {\n        return di()->get(\\Psr\\SimpleCache\\CacheInterface::class);\n    }\n}\n\nif (!function_exists('format_throwable')) {\n    /**\n     * Format a throwable to string.\n     * @param Throwable $throwable\n     * @return string\n     */\n    function format_throwable(Throwable $throwable): string\n    {\n        return di()->get(FormatterInterface::class)->format($throwable);\n    }\n}\n\n\nif (!function_exists('responseSuccess')) {\n    function responseSuccess($code, $message = '', $data = [])\n    {\n        $content = ['code' => $code];\n        $message ? $content['msg'] = $message : $content['msg'] = \\App\\Constants\\ResponseCode::getMessage($code);\n        $data ? $content['data'] = $data : $content['data'] = [];\n        return $content;\n    }\n}\n\nif (!function_exists('responseError')) {\n    function responseError($code, $message = '', $data = [])\n    {\n        $content = ['code' => $code];\n        $data ? $content['data'] = $data : $content['data'] = [];\n        return $content;\n    }\n}\n\n\n/**\n * 判读字符串是否为json\n */\nif (!function_exists('isJson')) {\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     * @param string $string\n     */\n    function isJson($string)\n    {\n        json_decode($string);\n        return (json_last_error() == JSON_ERROR_NONE);\n    }\n}\n\n\n/**\n * 返回jsonRpc结构\n */\nif (!function_exists('successJsonRpc')) {\n    function successJsonRpc($code, $data)\n    {\n        return [\n            'code' => $code,\n            'data' => $data\n        ];\n    }\n}\n\n\n"
  },
  {
    "path": "order-srv/app/Listener/DbQueryExecutedListener.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\Arr;\nuse Hyperf\\Utils\\Str;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\n\n#[Listener]\nclass DbQueryExecutedListener implements ListenerInterface\n{\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n    \n    public function __construct(ContainerInterface $container)\n    {\n        $this->logger = $container->get(LoggerFactory::class)->get('sql');\n    }\n    \n    public function listen() : array\n    {\n        return [QueryExecuted::class];\n    }\n    /**\n     * @param QueryExecuted $event\n     */\n    public function process(object $event) : void\n    {\n        if ($event instanceof QueryExecuted) {\n            $sql = $event->sql;\n            if (!Arr::isAssoc($event->bindings)) {\n                foreach ($event->bindings as $key => $value) {\n                    $sql = Str::replaceFirst('?', \"'{$value}'\", $sql);\n                }\n            }\n            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));\n        }\n    }\n}"
  },
  {
    "path": "order-srv/app/Log.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\nclass Log\n{\n    public static function get(string $name = 'app')\n    {\n        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);\n    }\n}"
  },
  {
    "path": "order-srv/app/Model/Order.php",
    "content": "<?php\n\ndeclare (strict_types=1);\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\nclass Order extends Model\n{\n    const CREATED_AT = 'create_time';\n    const UPDATED_AT = 'update_time';\n\n    protected ?string $dateFormat = 'U';\n    /**\n     * The table associated with the model.\n     *\n     */\n    protected ?string $table = 'order';\n    /**\n     * The attributes that are mass assignable.\n     *\n     */\n    protected array $fillable = ['order_no', 'user_id', 'coupon_id', 'order_money', 'order_discount', 'order_fact_money', 'consume_number', 'order_status', 'payment'];\n    /**\n     * The attributes that should be cast to native types.\n     *\n     */\n    protected array $casts = ['id' => 'integer'];\n\n    public function orderGoods()\n    {\n        return $this->hasMany(OrderGoods::class, 'order_no', 'order_no');\n    }\n}"
  },
  {
    "path": "order-srv/app/Model/OrderGoods.php",
    "content": "<?php\n\ndeclare (strict_types=1);\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\nclass OrderGoods extends Model\n{\n    const CREATED_AT = 'create_time';\n    const UPDATED_AT = 'update_time';\n\n    protected ?string $dateFormat = 'U';\n    /**\n     * The table associated with the model.\n     *\n     */\n    protected ?string $table = 'order_goods';\n    /**\n     * The attributes that are mass assignable.\n     *\n     */\n    protected array $fillable = ['order_no', 'goods_id', 'goods_sn', 'sku_id', 'user_id', 'goods_name', 'number', 'goods_tag_price', 'goods_real_price', 'goods_discount', 'goods_fact_money'];\n    /**\n     * The attributes that should be cast to native types.\n     *\n     * @var array\n     */\n    protected array $casts = ['id' => 'integer'];\n}"
  },
  {
    "path": "order-srv/app/Services/OrderService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Amqp\\Producer\\OrderProducer;\nuse App\\JsonRpc\\UserRpcServiceInterface;\nuse App\\Model\\OrderGoods;\nuse DtmClient\\Saga;\nuse DtmClient\\TransContext;\nuse App\\Exception\\JsonRpcException;\nuse App\\Exception\\ServiceException;\nuse App\\Log;\nuse App\\Model\\Order;\nuse Hyperf\\Amqp\\Producer;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * 订单service\n * Class OrderService\n * @package App\\Services\n */\nclass OrderService\n{\n    /**\n     * 注入DTM.SAGA\n     * @var Saga\n     */\n    #[Inject]\n    protected Saga $saga;\n\n    /**\n     * 注入UserRpcServiceInterface\n     * @var UserRpcServiceInterface\n     */\n    #[Inject]\n    protected UserRpcServiceInterface $userRpcServiceInterface;\n\n    /**\n     * 订单列表\n     * @param $userId\n     * @return mixed[]\n     */\n    public function orderList($userId)\n    {\n        Log::get()->info(\"调用orderList\");\n\n        $list = Order::query()\n            ->where('user_id', $userId)\n            ->get();\n\n        if (empty($list)) {\n            Log::get()->info(\"订单为空\");\n\n            throw new JsonRpcException(10001);\n        }\n\n        //调用用户服务拿到用户信息\n        foreach ($list as $item) {\n            try {\n                //调用用户服务中的用户详情方法\n                $res = $this->userRpcServiceInterface->userInfo($item->user_id);\n\n            } catch (\\Throwable $ex) {\n                Log::get()->info(\"rpc调用失败\");\n\n                throw new JsonRpcException(430);\n            }\n\n            if ($res['code'] !== 200) {\n                Log::get()->info(\"rpc调用失败\");\n\n                throw new JsonRpcException(430);\n            }\n\n            //拼装数据\n            $item->user = $res['data'];\n        }\n\n        return $list->toArray();\n\n    }\n\n    /**\n     * 创建订单\n     * @param $data\n     * @return string\n     */\n    public function createOrder($data)\n    {\n        Log::get()->info(\"调用createOrder\");\n\n        try {\n            //分布式事务\n            $data['order_no'] = date(\"YmdHis\");\n\n            //获取用户储值\n            //todo\n\n            //判断商品库存\n            //todo\n\n            $this->saga->init();\n            //创建订单\n            $this->saga->add(\n                env('DTM_ORDER_URL') . '/saga/sageCreateOrder',\n                env('DTM_ORDER_URL') . '/saga/sageCreateOrderCompensate',\n                $data\n            );\n            //扣用户余额\n            $this->saga->add(\n                env('DTM_USER_URL') . '/saga/changeStored',\n                env('DTM_USER_URL'). '/saga/changeStoredCompensate',\n                ['order_no'=>$data['order_no'] ,'user_id'=>$data['user_id'],'amount'=>-$data['order_fact_money']]\n            );\n\n            // 提交 Saga 事务\n            $this->saga->submit();\n\n        } catch (\\Throwable $ex) {\n            Log::get()->info(\"rpc调用失败\");\n\n            throw new JsonRpcException(430);\n        }\n\n        return TransContext::getGid();\n\n    }\n\n    /**\n     * SAGA订单创建成功\n     * @param $data\n     * @return string\n     */\n    public function sageCreateOrder($data)\n    {\n        Log::get()->info(\"分布式事务-sageCreateOrder\",$data);\n\n        //分布式事务\n        try {\n            Order::create([\n                'order_no' => $data['order_no'],\n                'user_id' => $data['user_id'],\n                'coupon_id' => $data['coupon_id'],\n                'order_money' => $data['order_money'],\n                'order_discount' => $data['order_fact_money'],\n                'consume_number' => $data['consume_number'],\n                'order_status' => 0,\n                'payment' => $data['payment'],\n            ]);\n\n            foreach ($data['goods'] as $item) {\n                OrderGoods::create([\n                    'order_no' => $data['order_no'],\n                    'goods_id' => $item['goods_id'],\n                    'goods_sn' => $item['goods_sn'],\n                    'sku_id' => $item['sku_id'],\n                    'user_id' => $item['user_id'],\n                    'goods_name' => $item['goods_name'],\n                    'number' => $item['number'],\n                    'goods_tag_price' => $item['goods_tag_price'],\n                    'goods_real_price' => $item['goods_real_price'],\n                    'goods_discount' => $item['goods_fact_money'],\n                ]);\n            }\n\n        } catch (\\Throwable $e) {\n            Log::get()->info(\"分布式事务-sageCreateOrder-调用失败\");\n\n            throw new ServiceException();\n        }\n\n        return true;\n    }\n\n\n    /**\n     * SAGA订单创建补偿\n     * @param $data\n     * @return string\n     */\n    public function sageCreateOrderCompensate($data)\n    {\n        Log::get()->info(\"分布式事务-sageCreateOrderCompensate\",$data);\n\n        //分布式事务\n        try {\n            Order::query()\n                ->where('order_no',$data['order_no'])\n                ->where('user_id',$data['user_id'])\n                ->delete();\n\n            OrderGoods::query()\n                ->where('order_no',$data['order_no'])\n                ->where('user_id',$data['user_id'])\n                ->delete();\n\n        } catch (\\Throwable $e) {\n            Log::get()->info(\"分布式事务-sageCreateOrderCompensate-调用失败\");\n\n            throw new ServiceException();\n        }\n\n        return true;\n\n    }\n\n    /**\n     * 投递订单消息到RabbitMQ\n     */\n    public function orderRabbitMQ()\n    {\n\n        //拼装数据\n        $message = new OrderProducer([\n            'id' => 1\n        ]);\n\n        $producer = di()->get(Producer::class);\n\n        //投递消息\n        $result = $producer->produce($message);\n\n        //投递消息失败\n        if ($result != true){\n            throw new JsonRpcException(430);\n        }\n\n    }\n\n\n}"
  },
  {
    "path": "order-srv/bin/hyperf.php",
    "content": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limit', '1G');\n\nerror_reporting(E_ALL);\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\n// Self-called anonymous function that creates its own scope and keep the global namespace clean.\n(function () {\n    Hyperf\\Di\\ClassLoader::init();\n    /** @var Psr\\Container\\ContainerInterface $container */\n    $container = require BASE_PATH . '/config/container.php';\n\n    $application = $container->get(Hyperf\\Contract\\ApplicationInterface::class);\n    $application->run();\n})();\n"
  },
  {
    "path": "order-srv/composer.json",
    "content": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n        \"framework\",\n        \"hyperf\",\n        \"microservice\",\n        \"middleware\"\n    ],\n    \"description\": \"A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.\",\n    \"license\": \"Apache-2.0\",\n    \"require\": {\n        \"php\": \">=8.0\",\n        \"dtm/dtm-client\": \"^0.3.0\",\n        \"hyperf/amqp\": \"3.0.*\",\n        \"hyperf/cache\": \"3.0.*\",\n        \"hyperf/command\": \"3.0.*\",\n        \"hyperf/config\": \"3.0.*\",\n        \"hyperf/config-nacos\": \"3.0.*\",\n        \"hyperf/constants\": \"3.0.*\",\n        \"hyperf/database\": \"3.0.*\",\n        \"hyperf/db-connection\": \"3.0.*\",\n        \"hyperf/framework\": \"3.0.*\",\n        \"hyperf/guzzle\": \"3.0.*\",\n        \"hyperf/http-server\": \"3.0.*\",\n        \"hyperf/json-rpc\": \"3.0.*\",\n        \"hyperf/logger\": \"3.0.*\",\n        \"hyperf/memory\": \"3.0.*\",\n        \"hyperf/model-cache\": \"3.0.*\",\n        \"hyperf/paginator\": \"3.0.*\",\n        \"hyperf/process\": \"3.0.*\",\n        \"hyperf/redis\": \"3.0.*\",\n        \"hyperf/rpc\": \"3.0.*\",\n        \"hyperf/rpc-client\": \"3.0.*\",\n        \"hyperf/rpc-server\": \"3.0.*\",\n        \"hyperf/service-governance\": \"3.0.*\",\n        \"hyperf/service-governance-nacos\": \"3.0.*\",\n        \"hyperf/tracer\": \"3.0.*\"\n    },\n    \"require-dev\": {\n        \"friendsofphp/php-cs-fixer\": \"^3.0\",\n        \"hyperf/devtool\": \"3.0.*\",\n        \"hyperf/ide-helper\": \"3.0.*\",\n        \"hyperf/testing\": \"3.0.*\",\n        \"hyperf/watcher\": \"3.0.*\",\n        \"mockery/mockery\": \"^1.0\",\n        \"phpstan/phpstan\": \"^0.12\",\n        \"swoole/ide-helper\": \"^4.5\"\n    },\n    \"suggest\": {\n        \"ext-openssl\": \"Required to use HTTPS.\",\n        \"ext-json\": \"Required to use JSON.\",\n        \"ext-pdo\": \"Required to use MySQL Client.\",\n        \"ext-pdo_mysql\": \"Required to use MySQL Client.\",\n        \"ext-redis\": \"Required to use Redis Client.\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\"\n        },\n        \"files\": [\n            \"app/Kernel/Functions.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"HyperfTest\\\\\": \"./test/\"\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true,\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"sort-packages\": true\n    },\n    \"extra\": [],\n    \"scripts\": {\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-autoload-dump\": [\n            \"rm -rf runtime/container\"\n        ],\n        \"test\": \"co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always\",\n        \"cs-fix\": \"php-cs-fixer fix $1\",\n        \"analyse\": \"phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config\",\n        \"start\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"php ./bin/hyperf.php start\"\n        ]\n    }\n}\n"
  },
  {
    "path": "order-srv/config/autoload/amqp.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('AMQP_HOST', 'localhost'),\n        'port' => (int) env('AMQP_PORT', 5672),\n        'user' => env('AMQP_USER', 'guest'),\n        'password' => env('AMQP_PASSWORD', 'guest'),\n        'vhost' => env('AMQP_VHOST', '/'),\n        'open_ssl' => false,\n        'concurrent' => [\n            'limit' => 1,\n        ],\n        'pool' => [\n            'connections' => 2,\n        ],\n        'params' => [\n            'insist' => false,\n            'login_method' => 'AMQPLAIN',\n            'login_response' => null,\n            'locale' => 'en_US',\n            'connection_timeout' => 3,\n            'read_write_timeout' => 6,\n            'context' => null,\n            'keepalive' => true,\n            'heartbeat' => 3,\n            'channel_rpc_timeout' => 0.0,\n            'close_on_destruct' => false,\n            'max_idle_channels' => 10,\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/annotations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ],\n        'ignore_annotations' => [\n            'mixin',\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/aspects.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Tracer\\Aspect\\JsonRpcAspect::class,\n];\n"
  },
  {
    "path": "order-srv/config/autoload/cache.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,\n        'packer' => Hyperf\\Utils\\Packer\\PhpSerializerPacker::class,\n        'prefix' => 'c:',\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/commands.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/config_center.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),\n    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),\n    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),\n    'drivers' => [\n        'nacos' => [\n            'driver' => Hyperf\\ConfigNacos\\NacosDriver::class,\n            'merge_mode' => Hyperf\\ConfigNacos\\Constants::CONFIG_MERGE_OVERWRITE,\n            'interval' => 3,\n            'default_key' => 'nacos_config',\n            'listener_config' => [\n                // dataId, group, tenant, type, content\n                'nacos_config' => [\n                    // 命名空间/ID\n                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId\n                    // DataID\n                    'data_id' => env('NACOS_DATA_ID'),\n                    // 组名\n                    'group' => 'DEFAULT_GROUP',\n                    'type' => 'json',\n                ],\n            ],\n            'client' => [\n                // 客户端\n                'host' => env('NACOS_HOST'),\n                'port' => env('NACOS_PORT'),\n                'username' => env('NACOS_USERNAME'),\n                'password' => env('NACOS_PASSWORD'),\n                'guzzle' => [\n                    'config' => null,\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/databases.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'host' => env('DB_HOST', 'localhost'),\n        'port' => env('DB_PORT', 3306),\n        'database' => env('DB_DATABASE', 'hyperf'),\n        'username' => env('DB_USERNAME', 'root'),\n        'password' => env('DB_PASSWORD', ''),\n        'charset' => env('DB_CHARSET', 'utf8mb4'),\n        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),\n        'prefix' => env('DB_PREFIX', ''),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),\n        ],\n//        'cache' => [\n//            'handler' => Hyperf\\ModelCache\\Handler\\RedisHandler::class,\n//            'cache_key' => '{mc:%s:m:%s}:%s:%s',\n//            'prefix' => 'default',\n//            'ttl' => 3600 * 24,\n//            'empty_model_ttl' => 600,\n//            'load_script' => true,\n//        ],\n        'commands' => [\n            'gen:model' => [\n                'path' => 'app/Model',\n                'force_casts' => true,\n                'inheritance' => 'Model',\n                'uses' => '',\n                'table_mapping' => [],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/dependencies.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/devtool.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n                'namespace' => 'App\\\\Amqp\\\\Consumer',\n            ],\n            'producer' => [\n                'namespace' => 'App\\\\Amqp\\\\Producer',\n            ],\n        ],\n        'aspect' => [\n            'namespace' => 'App\\\\Aspect',\n        ],\n        'command' => [\n            'namespace' => 'App\\\\Command',\n        ],\n        'controller' => [\n            'namespace' => 'App\\\\Controller',\n        ],\n        'job' => [\n            'namespace' => 'App\\\\Job',\n        ],\n        'listener' => [\n            'namespace' => 'App\\\\Listener',\n        ],\n        'middleware' => [\n            'namespace' => 'App\\\\Middleware',\n        ],\n        'Process' => [\n            'namespace' => 'App\\\\Processes',\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/dtm.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of DTM-PHP.\n *\n * @license  https://github.com/dtm-php/dtm-client/blob/master/LICENSE\n */\nuse DtmClient\\Constants\\Protocol;\nuse DtmClient\\Constants\\DbType;\n\nreturn [\n    'protocol' => Protocol::HTTP,\n    'server' => env('DTM_HOST'),\n    'port' => [\n        'http' => 36789,\n        'grpc' => 36790,\n    ],\n    'barrier' => [\n        // DB 模式下的子事务屏障配置\n        'db' => [\n            'type' => DbType::MySQL\n        ],\n        // Redis 模式下的子事务屏障配置\n        'redis' => [\n            // 子事务屏障记录的超时时间\n            'expire_seconds' => 7 * 86400,\n        ],\n        'apply' => [],\n    ],\n    'guzzle' => [\n        'options' => [],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/exceptions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception\\Handler\\HttpExceptionHandler::class,\n            App\\Exception\\Handler\\DtmExceptionHandler::class,\n        ],\n        'jsonrpc-http' => [\n            App\\Exception\\Handler\\JsonRpcExceptionHandler::class,\n        ]\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/listeners.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/logger.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handler\\RotatingFileHandler::class,\n            'constructor' => [\n                'filename' => BASE_PATH . '/runtime/logs/hyperf.log',\n                'level' => Monolog\\Logger::DEBUG,\n            ],\n        ],\n        'formatter' => [\n            'class' => Monolog\\Formatter\\LineFormatter::class,\n            'constructor' => [\n                'format' => null,\n                'dateFormat' => 'Y-m-d H:i:s',\n                'allowInlineLineBreaks' => true,\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/middlewares.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n        \\DtmClient\\Middleware\\DtmMiddleware::class,\n    ],\n    'jsonrpc-http' => [\n        \\Hyperf\\Tracer\\Middleware\\TraceMiddleware::class,\n        \\DtmClient\\Middleware\\DtmMiddleware::class,\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/nacos.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port\n    // 'url' => '',\n    // The nacos host info\n    'host' => env('NACOS_HOST'),\n    'port' => env('NACOS_PORT'),\n    // The nacos account info\n    'username' => env('NACOS_USERNAME'),\n    'password' => env('NACOS_PASSWORD'),\n    'guzzle' => [\n        'config' => null,\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/opentracing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zipkin'),\n    'enable' => [\n        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),\n        'redis' => env('TRACER_ENABLE_REDIS', false),\n        'db' => env('TRACER_ENABLE_DB', false),\n        'method' => env('TRACER_ENABLE_METHOD', false),\n    ],\n    'tracer' => [\n        'zipkin' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'options' => [\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            'sampler' => BinarySampler::createAsAlwaysSample(),\n        ],\n        'jaeger' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\JaegerTracerFactory::class,\n            'name' => env('APP_NAME', 'skeleton'),\n            'options' => [\n                'local_agent' => [\n                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),\n                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),\n                ],\n            ],\n        ],\n    ],\n    'tags' => [\n        // HTTP 客户端 (Guzzle)\n        'http_client' => [\n            'http.url' => 'http.url',\n            'http.method' => 'http.method',\n            'http.status_code' => 'http.status_code',\n        ],\n        // Redis 客户端\n        'redis' => [\n            'arguments' => 'arguments',\n            'result' => 'result',\n        ],\n        // 数据库客户端 (hyperf/database)\n        'db' => [\n            'db.query' => 'db.query',\n            'db.statement' => 'db.statement',\n            'db.query_time' => 'db.query_time',\n        ],\n    ]\n];\n"
  },
  {
    "path": "order-srv/config/autoload/processes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/redis.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        'auth' => env('REDIS_AUTH', null),\n        'port' => (int) env('REDIS_PORT', 6379),\n        'db' => (int) env('REDIS_DB', 0),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/server.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    'mode' => SWOOLE_PROCESS,\n    'servers' => [\n        [\n            'name' => 'http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9502,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [Hyperf\\HttpServer\\Server::class, 'onRequest'],\n            ],\n        ],\n        [\n            'name' => 'jsonrpc-http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9505,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [\\Hyperf\\JsonRpc\\HttpServer::class, 'onRequest'],\n            ],\n        ],\n    ],\n    'settings' => [\n        Constant::OPTION_ENABLE_COROUTINE => true,\n        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),\n        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',\n        Constant::OPTION_OPEN_TCP_NODELAY => true,\n        Constant::OPTION_MAX_COROUTINE => 100000,\n        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,\n        Constant::OPTION_MAX_REQUEST => 100000,\n        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,\n        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,\n    ],\n    'callbacks' => [\n        Event::ON_WORKER_START => [Hyperf\\Framework\\Bootstrap\\WorkerStartCallback::class, 'onWorkerStart'],\n        Event::ON_PIPE_MESSAGE => [Hyperf\\Framework\\Bootstrap\\PipeMessageCallback::class, 'onPipeMessage'],\n        Event::ON_WORKER_EXIT => [Hyperf\\Framework\\Bootstrap\\WorkerExitCallback::class, 'onWorkerExit'],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/autoload/services.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n// 这个是nacos服务的端口和地址\n$registry = [\n    'protocol' => 'nacos',\n    'address' => 'http://'.env('NACOS_HOST').':'.env('NACOS_PORT'),\n];\n\n// 这里配置需要用的rpc服务\n$services = [\n    [\n        'name' => 'UserRpcService',\n        'service' => \\App\\JsonRpc\\UserRpcServiceInterface::class\n    ]\n];\n\nreturn [\n    'enable' => [\n        // 开启服务发现\n        'discovery' => true,\n        // 开启服务注册\n        'register' => true,\n    ],\n    // 服务消费者相关配置\n    'consumers' => value(function () use ($services, $registry) {\n        // 循环生成rpc消费端\n        $consumers = [];\n        foreach ($services as $value) {\n            $consumers[] = [\n                'name' => $value['name'],\n                'service' => $value['service'],\n                'registry' => $registry\n            ];\n        }\n        return $consumers;\n    }),\n    // 服务提供者相关配置\n    'providers' => [],\n    // 服务驱动相关配置\n    'drivers' => [\n        // nacos 配置,当前使用\n        'nacos' => [\n            // The nacos host info\n            'host' => env('NACOS_HOST'),\n            'port' => env('NACOS_PORT'),\n            // nacos 账号密码信息\n            'username' => env('NACOS_USERNAME'),\n            'password' => env('NACOS_PASSWORD'),\n            'guzzle' => [\n                'config' => null,\n            ],\n            // 命名空间,public为默认系统空间\n            'group_name' => 'api',\n            // 命名空间ID\n             'namespace_id' => env('NACOS_TENANT'),\n            // 心跳检查秒数\n            'heartbeat' => 5,\n            'ephemeral' => true, // 是否注册临时实例\n        ],\n    ],\n];"
  },
  {
    "path": "order-srv/config/autoload/tracer.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/25\n * @create: 11:29\n */\n\n\nreturn [\n    // 选择默认的 Tracer\n    'default' => env('TRACER_DRIVER', 'jaeger'),\n\n    // 这里的代码演示不对 enable 内的配置进行展开\n    'enable' => [],\n\n    'tracer' => [\n        // Zipkin 驱动配置\n        'zipkin' => [\n            // 当前应用的配置\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // 如果 ipv6 和 ipv6 为空组件会自动从 Server 中检测\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'options' => [\n                // Zipkin 服务的 endpoint 地址\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                // 请求超时秒数\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            // 采样器，默认为所有请求的都追踪\n            'sampler' => \\Zipkin\\Samplers\\BinarySampler::createAsAlwaysSample(),\n        ],\n    ],\n];"
  },
  {
    "path": "order-srv/config/autoload/watcher.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Watcher\\Driver\\ScanFileDriver;\n\nreturn [\n    'driver' => ScanFileDriver::class,\n    'bin' => 'php',\n    'watch' => [\n        'dir' => ['app', 'config'],\n        'file' => ['.env'],\n        'scan_interval' => 2000,\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/config.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_name' => env('APP_NAME', 'skeleton'),\n    'app_env' => env('APP_ENV', 'dev'),\n    'scan_cacheable' => env('SCAN_CACHEABLE', false),\n    StdoutLoggerInterface::class => [\n        'log_level' => [\n            LogLevel::ALERT,\n            LogLevel::CRITICAL,\n//            LogLevel::DEBUG,\n            LogLevel::EMERGENCY,\n            LogLevel::ERROR,\n            LogLevel::INFO,\n            LogLevel::NOTICE,\n            LogLevel::WARNING,\n        ],\n    ],\n];\n"
  },
  {
    "path": "order-srv/config/container.php",
    "content": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Di\\Container;\nuse Hyperf\\Di\\Definition\\DefinitionSourceFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\n$container = new Container((new DefinitionSourceFactory(true))());\n\nif (! $container instanceof \\Psr\\Container\\ContainerInterface) {\n    throw new RuntimeException('The dependency injection container is invalid.');\n}\nreturn ApplicationContext::setContainer($container);\n"
  },
  {
    "path": "order-srv/config/routes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::get('/favicon.ico', function () {\n    return '';\n});"
  },
  {
    "path": "order-srv/migrations/2022_06_08_061612_create_order_table.php",
    "content": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration;\n\nclass CreateOrderTable extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('order', function (Blueprint $table) {\n            $table->bigIncrements('id');\n\n            $table->string('order_no')->nullable()->comment('订单编号');\n\n            $table->integer('user_id')->default(0)->comment('线下订单编号');\n            $table->integer('coupon_id')->default(0)->comment('会员优惠券id');\n\n            $table->decimal('order_money',10,2)->default(0)->comment('订单金额');\n            $table->decimal('order_discount',10,2)->default(0)->comment('订单折扣');\n            $table->decimal('order_fact_money',10,2)->default(0)->comment('订单实际金额');\n\n            $table->integer('consume_number')->default(0)->comment('商品数量');\n\n            $table->tinyInteger('order_status')->default(0)->comment('订单状态, -1 已关闭 0 待支付 1 支付成功 2 已发货 3 退款处理  4 已完成');\n            $table->tinyInteger('payment')->default(1)->comment('支付方式 1储值 2微信');\n\n            $table->integer('create_time')->default(0)->comment('创建时间');\n            $table->integer('update_time')->default(0)->comment('更新时间');\n\n            $table->comment('订单表');\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('order');\n    }\n}\n"
  },
  {
    "path": "order-srv/migrations/2022_06_08_063020_create_order_goods_table.php",
    "content": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration;\n\nclass CreateOrderGoodsTable extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('order_goods', function (Blueprint $table) {\n\n            $table->bigIncrements('id');\n\n            $table->string('order_no',35)->nullable()->comment('订单编号');\n            $table->integer('goods_id')->default(0)->comment('商品id');\n            $table->string('goods_sn',35)->nullable()->comment('商品编号');\n            $table->integer('sku_id')->default(0)->comment('skuid');\n            $table->integer('user_id')->default(0)->comment('用户id');\n            $table->string('goods_name',35)->nullable()->comment('商品名');\n            $table->integer('number')->default(0)->comment('商品个数');\n\n            $table->decimal('goods_tag_price',10,2)->default(0)->comment('吊牌价');\n            $table->decimal('goods_real_price',10,2)->default(0)->comment('实际价');\n            $table->decimal('goods_discount',10,2)->default(0)->comment('商户折扣');\n            $table->decimal('goods_fact_money',10,2)->default(0)->comment('商品实际金额');\n\n            $table->integer('create_time')->default(0)->comment('创建时间');\n            $table->integer('update_time')->default(0)->comment('更新时间');\n\n            $table->comment('订单商品表');\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('order_goods');\n    }\n}\n"
  },
  {
    "path": "order-srv/seeders/order_goods_seeder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass OrderGoodsSeeder extends Seeder\n{\n    /**\n     * Run the database seeds.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        \\Hyperf\\DbConnection\\Db::table('order_goods')->insert([\n            'order_no' => '20220527',\n            'goods_id' => 2,\n            'goods_sn' => 'AS12',\n            'sku_id' => 10,\n            'user_id' => 1,\n            'goods_name' => '测试商品',\n            'number' => 1,\n            'goods_tag_price' => 100.00,\n            'goods_real_price' => 100.00,\n            'goods_discount' => 100.00,\n            'goods_fact_money' => 100.00,\n            'create_time' =>time(),\n            'update_time' =>time(),\n        ]);\n    }\n}\n"
  },
  {
    "path": "order-srv/seeders/order_seeder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass OrderSeeder extends Seeder\n{\n    /**\n     * Run the database seeds.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        \\Hyperf\\DbConnection\\Db::table('order')->insert([\n            'order_no' => '20220527',\n            'user_id' => 1,\n            'coupon_id' => 0,\n            'order_money' => 100.00,\n            'order_discount' => 100.00,\n            'order_fact_money' => 100.00,\n            'consume_number' => 1,\n            'order_status' => 1,\n            'payment' => 1,\n            'create_time' =>time(),\n            'update_time' =>time(),\n        ]);\n\n    }\n}\n"
  },
  {
    "path": "order-srv/test/Cases/ExampleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversNothing\n */\nclass ExampleTest extends HttpTestCase\n{\n    public function testExample()\n    {\n        $this->assertTrue(true);\n        $this->assertTrue(is_array($this->get('/')));\n    }\n}\n"
  },
  {
    "path": "order-srv/test/HttpTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class HttpTestCase.\n * @method get($uri, $data = [], $headers = [])\n * @method post($uri, $data = [], $headers = [])\n * @method json($uri, $data = [], $headers = [])\n * @method file($uri, $data = [], $headers = [])\n * @method request($method, $path, $options = [])\n */\nabstract class HttpTestCase extends TestCase\n{\n    /**\n     * @var Client\n     */\n    protected $client;\n\n    public function __construct($name = null, array $data = [], $dataName = '')\n    {\n        parent::__construct($name, $data, $dataName);\n        $this->client = make(Client::class);\n    }\n\n    public function __call($name, $arguments)\n    {\n        return $this->client->{$name}(...$arguments);\n    }\n}\n"
  },
  {
    "path": "order-srv/test/bootstrap.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_reporting(E_ALL);\ndate_default_timezone_set('Asia/Shanghai');\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nSwoole\\Runtime::enableCoroutine(true);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\nHyperf\\Di\\ClassLoader::init();\n\n$container = require BASE_PATH . '/config/container.php';\n\n$container->get(Hyperf\\Contract\\ApplicationInterface::class);\n"
  },
  {
    "path": "task-srv/.github/workflows/Dockerfile",
    "content": "# Default Dockerfile\n#\n# @link     https://www.hyperf.io\n# @document https://hyperf.wiki\n# @contact  group@hyperf.io\n# @license  https://github.com/hyperf/hyperf/blob/master/LICENSE\n\nFROM hyperf/hyperf:8.0-alpine-v3.15-swoole\nLABEL maintainer=\"Hyperf Developers <group@hyperf.io>\" version=\"1.0\" license=\"MIT\" app.name=\"Hyperf\"\n\n##\n# ---------- env settings ----------\n##\n# --build-arg timezone=Asia/Shanghai\nARG timezone\n\nENV TIMEZONE=${timezone:-\"Asia/Shanghai\"} \\\n    APP_ENV=prod \\\n    SCAN_CACHEABLE=(true)\n\n# update\nRUN set -ex \\\n    # show php version and extensions\n    && php -v \\\n    && php -m \\\n    && php --ri swoole \\\n    #  ---------- some config ----------\n    && cd /etc/php8 \\\n    # - config PHP\n    && { \\\n        echo \"upload_max_filesize=128M\"; \\\n        echo \"post_max_size=128M\"; \\\n        echo \"memory_limit=1G\"; \\\n        echo \"date.timezone=${TIMEZONE}\"; \\\n    } | tee conf.d/99_overrides.ini \\\n    # - config timezone\n    && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \\\n    && echo \"${TIMEZONE}\" > /etc/timezone \\\n    # ---------- clear works ----------\n    && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \\\n    && echo -e \"\\033[42;37m Build Completed :).\\033[0m\\n\"\n\nWORKDIR /opt/www\n\n# Composer Cache\n# COPY ./composer.* /opt/www/\n# RUN composer install --no-dev --no-scripts\n\nCOPY . /opt/www\nRUN print \"\\n\" | composer install -o && php bin/hyperf.php\n\nEXPOSE 9501\n\nENTRYPOINT [\"php\", \"/opt/www/bin/hyperf.php\", \"start\"]\n"
  },
  {
    "path": "task-srv/.github/workflows/build.yml",
    "content": "name: Build Docker\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n      - name: Build\n        run: cp -rf .github/workflows/Dockerfile . && docker build -t hyperf .\n"
  },
  {
    "path": "task-srv/.github/workflows/release.yml",
    "content": "on:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\nname: Release\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n      - name: Create Release\n        id: create_release\n        uses: actions/create-release@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: ${{ github.ref }}\n          release_name: Release ${{ github.ref }}\n          draft: false\n          prerelease: false\n"
  },
  {
    "path": "task-srv/.gitignore",
    "content": ".buildpath\n.settings/\n.project\n*.patch\n.idea/\n.git/\nruntime/\nvendor/\n.phpintel/\n.env\n.DS_Store\n.phpunit*\n*.cache\n"
  },
  {
    "path": "task-srv/app/Amqp/Consumer/OrderConsumer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Consumer;\n\nuse App\\Log;\nuse Hyperf\\Amqp\\Result;\nuse Hyperf\\Amqp\\Annotation\\Consumer;\nuse Hyperf\\Amqp\\Message\\ConsumerMessage;\nuse PhpAmqpLib\\Message\\AMQPMessage;\n\n/**\n * 订单订阅消息消费者\n * Class OrderConsumer\n * @package App\\Amqp\\Consumer\n */\n#[Consumer(exchange: 'order', routingKey: 'order', queue: 'order', name: \"OrderConsumer\", nums: 1)]\nclass OrderConsumer extends ConsumerMessage\n{\n    public function consumeMessage($data, AMQPMessage $message): string\n    {\n        Log::get()->info(\"消费订单队列\",$data);\n\n        return Result::ACK;\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Amqp/Consumer/UserConsumer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Consumer;\n\nuse App\\Log;\nuse Hyperf\\Amqp\\Result;\nuse Hyperf\\Amqp\\Annotation\\Consumer;\nuse Hyperf\\Amqp\\Message\\ConsumerMessage;\nuse PhpAmqpLib\\Message\\AMQPMessage;\n\n/**\n * 用户订阅消息消费者\n * Class UserConsumer\n * @package App\\Amqp\\Consumer\n */\n#[Consumer(exchange: 'user', routingKey: 'user', queue: 'user', name: \"UserConsumer\", nums: 1)]\nclass UserConsumer extends ConsumerMessage\n{\n    public function consumeMessage($data, AMQPMessage $message): string\n    {\n        Log::get()->info(\"消费用户队列\",$data);\n\n        return Result::ACK;\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Command/TestCommand.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Command;\n\nuse App\\Log;\nuse Hyperf\\Command\\Command as HyperfCommand;\nuse Psr\\Container\\ContainerInterface;\nuse Hyperf\\Command\\Annotation\\Command;\n\n#[Command]\nclass TestCommand extends HyperfCommand\n{\n    /**\n     * @var ContainerInterface\n     */\n    protected $container;\n\n    /**\n     * 执行的命令行\n     *\n     * @var string\n     */\n    protected ?string $name = 'TestCommand';\n\n\n    public function handle()\n    {\n\n        Log::get()->info(\"运行TestCommand任务:\".date(\"Y-m-d H:i:s\"));\n\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Controller/AbstractController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Contract\\ResponseInterface;\nuse Psr\\Container\\ContainerInterface;\n\nabstract class AbstractController\n{\n    #[Inject]\n    protected ContainerInterface $container;\n\n    #[Inject]\n    protected RequestInterface $request;\n\n    #[Inject]\n    protected ResponseInterface $response;\n}\n"
  },
  {
    "path": "task-srv/app/Controller/IndexController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nclass IndexController extends AbstractController\n{\n    public function index()\n    {\n        $user = $this->request->input('user', 'Hyperf');\n        $method = $this->request->getMethod();\n\n        return [\n            'method' => $method,\n            'message' => \"Hello {$user}.\",\n        ];\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Exception/Handler/AppExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Throwable;\n\nclass AppExceptionHandler extends ExceptionHandler\n{\n    public function __construct(protected StdoutLoggerInterface $logger)\n    {\n    }\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n        $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));\n        $this->logger->error($throwable->getTraceAsString());\n        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Listener/DbQueryExecutedListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\Arr;\nuse Hyperf\\Utils\\Str;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\n\n#[Listener]\nclass DbQueryExecutedListener implements ListenerInterface\n{\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->logger = $container->get(LoggerFactory::class)->get('sql');\n    }\n\n    public function listen(): array\n    {\n        return [\n            QueryExecuted::class,\n        ];\n    }\n\n    /**\n     * @param QueryExecuted $event\n     */\n    public function process(object $event): void\n    {\n        if ($event instanceof QueryExecuted) {\n            $sql = $event->sql;\n            if (! Arr::isAssoc($event->bindings)) {\n                foreach ($event->bindings as $key => $value) {\n                    $sql = Str::replaceFirst('?', \"'{$value}'\", $sql);\n                }\n            }\n\n            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));\n        }\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Listener/QueueHandleListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\AsyncQueue\\AnnotationJob;\nuse Hyperf\\AsyncQueue\\Event\\AfterHandle;\nuse Hyperf\\AsyncQueue\\Event\\BeforeHandle;\nuse Hyperf\\AsyncQueue\\Event\\Event;\nuse Hyperf\\AsyncQueue\\Event\\FailedHandle;\nuse Hyperf\\AsyncQueue\\Event\\RetryHandle;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\ExceptionHandler\\Formatter\\FormatterInterface;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Psr\\Log\\LoggerInterface;\n\n#[Listener]\nclass QueueHandleListener implements ListenerInterface\n{\n    protected LoggerInterface $logger;\n\n    public function __construct(LoggerFactory $loggerFactory, protected FormatterInterface $formatter)\n    {\n        $this->logger = $loggerFactory->get('queue');\n    }\n\n    public function listen(): array\n    {\n        return [\n            AfterHandle::class,\n            BeforeHandle::class,\n            FailedHandle::class,\n            RetryHandle::class,\n        ];\n    }\n\n    public function process(object $event): void\n    {\n        if ($event instanceof Event && $event->message->job()) {\n            $job = $event->message->job();\n            $jobClass = get_class($job);\n            if ($job instanceof AnnotationJob) {\n                $jobClass = sprintf('Job[%s@%s]', $job->class, $job->method);\n            }\n            $date = date('Y-m-d H:i:s');\n\n            switch (true) {\n                case $event instanceof BeforeHandle:\n                    $this->logger->info(sprintf('[%s] Processing %s.', $date, $jobClass));\n                    break;\n                case $event instanceof AfterHandle:\n                    $this->logger->info(sprintf('[%s] Processed %s.', $date, $jobClass));\n                    break;\n                case $event instanceof FailedHandle:\n                    $this->logger->error(sprintf('[%s] Failed %s.', $date, $jobClass));\n                    $this->logger->error($this->formatter->format($event->getThrowable()));\n                    break;\n                case $event instanceof RetryHandle:\n                    $this->logger->warning(sprintf('[%s] Retried %s.', $date, $jobClass));\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "task-srv/app/Log.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\nclass Log\n{\n    public static function get(string $name = 'app')\n    {\n        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);\n    }\n}"
  },
  {
    "path": "task-srv/app/Model/Model.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model as BaseModel;\nuse Hyperf\\ModelCache\\Cacheable;\nuse Hyperf\\ModelCache\\CacheableInterface;\n\nabstract class Model extends BaseModel implements CacheableInterface\n{\n    use Cacheable;\n}\n"
  },
  {
    "path": "task-srv/app/Process/AsyncQueueConsumer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Process;\n\nuse Hyperf\\AsyncQueue\\Process\\ConsumerProcess;\nuse Hyperf\\Process\\Annotation\\Process;\n\n#[Process]\nclass AsyncQueueConsumer extends ConsumerProcess\n{\n}\n"
  },
  {
    "path": "task-srv/bin/hyperf.php",
    "content": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limit', '1G');\n\nerror_reporting(E_ALL);\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\n// Self-called anonymous function that creates its own scope and keep the global namespace clean.\n(function () {\n    Hyperf\\Di\\ClassLoader::init();\n    /** @var Psr\\Container\\ContainerInterface $container */\n    $container = require BASE_PATH . '/config/container.php';\n\n    $application = $container->get(Hyperf\\Contract\\ApplicationInterface::class);\n    $application->run();\n})();\n"
  },
  {
    "path": "task-srv/composer.json",
    "content": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n        \"framework\",\n        \"hyperf\",\n        \"microservice\",\n        \"middleware\"\n    ],\n    \"description\": \"A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.\",\n    \"license\": \"Apache-2.0\",\n    \"require\": {\n        \"php\": \">=8.0\",\n        \"hyperf/amqp\": \"3.0.*\",\n        \"hyperf/async-queue\": \"3.0.*\",\n        \"hyperf/cache\": \"3.0.*\",\n        \"hyperf/command\": \"3.0.*\",\n        \"hyperf/config\": \"3.0.*\",\n        \"hyperf/config-nacos\": \"3.0.*\",\n        \"hyperf/crontab\": \"3.0.*\",\n        \"hyperf/database\": \"3.0.*\",\n        \"hyperf/db-connection\": \"3.0.*\",\n        \"hyperf/framework\": \"3.0.*\",\n        \"hyperf/guzzle\": \"3.0.*\",\n        \"hyperf/http-server\": \"3.0.*\",\n        \"hyperf/logger\": \"3.0.*\",\n        \"hyperf/memory\": \"3.0.*\",\n        \"hyperf/model-cache\": \"3.0.*\",\n        \"hyperf/process\": \"3.0.*\",\n        \"hyperf/redis\": \"3.0.*\",\n        \"hyperf/tracer\": \"3.0.*\"\n    },\n    \"require-dev\": {\n        \"friendsofphp/php-cs-fixer\": \"^3.0\",\n        \"hyperf/devtool\": \"3.0.*\",\n        \"hyperf/ide-helper\": \"3.0.*\",\n        \"hyperf/testing\": \"3.0.*\",\n        \"mockery/mockery\": \"^1.0\",\n        \"phpstan/phpstan\": \"^0.12\",\n        \"swoole/ide-helper\": \"^4.5\"\n    },\n    \"suggest\": {\n        \"ext-openssl\": \"Required to use HTTPS.\",\n        \"ext-json\": \"Required to use JSON.\",\n        \"ext-pdo\": \"Required to use MySQL Client.\",\n        \"ext-pdo_mysql\": \"Required to use MySQL Client.\",\n        \"ext-redis\": \"Required to use Redis Client.\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\"\n        },\n        \"files\": []\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"HyperfTest\\\\\": \"./test/\"\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true,\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"sort-packages\": true\n    },\n    \"extra\": [],\n    \"scripts\": {\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-autoload-dump\": [\n            \"rm -rf runtime/container\"\n        ],\n        \"test\": \"co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always\",\n        \"cs-fix\": \"php-cs-fixer fix $1\",\n        \"analyse\": \"phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config\",\n        \"start\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"php ./bin/hyperf.php start\"\n        ]\n    }\n}\n"
  },
  {
    "path": "task-srv/config/autoload/amqp.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('AMQP_HOST', 'localhost'),\n        'port' => (int) env('AMQP_PORT', 5672),\n        'user' => env('AMQP_USER', 'guest'),\n        'password' => env('AMQP_PASSWORD', 'guest'),\n        'vhost' => env('AMQP_VHOST', '/'),\n        'concurrent' => [\n            'limit' => 1,\n        ],\n        'pool' => [\n            'connections' => 2,\n        ],\n        'params' => [\n            'insist' => false,\n            'login_method' => 'AMQPLAIN',\n            'login_response' => null,\n            'locale' => 'en_US',\n            'connection_timeout' => 3,\n            'read_write_timeout' => 6,\n            'context' => null,\n            'keepalive' => true,\n            'heartbeat' => 3,\n            'channel_rpc_timeout' => 0.0,\n            'close_on_destruct' => false,\n            'max_idle_channels' => 10,\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/annotations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ],\n        'ignore_annotations' => [\n            'mixin',\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/aspects.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/async_queue.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\AsyncQueue\\Driver\\RedisDriver::class,\n        'redis' => [\n            'pool' => 'default',\n        ],\n        'channel' => '{queue}',\n        'timeout' => 2,\n        'retry_seconds' => 5,\n        'handle_timeout' => 10,\n        'processes' => 1,\n        'concurrent' => [\n            'limit' => 10,\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/cache.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,\n        'packer' => Hyperf\\Utils\\Packer\\PhpSerializerPacker::class,\n        'prefix' => 'c:',\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/commands.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/config_center.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),\n    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),\n    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),\n    'drivers' => [\n        'nacos' => [\n            'driver' => Hyperf\\ConfigNacos\\NacosDriver::class,\n            'merge_mode' => Hyperf\\ConfigNacos\\Constants::CONFIG_MERGE_OVERWRITE,\n            'interval' => 3,\n            'default_key' => 'nacos_config',\n            'listener_config' => [\n                // dataId, group, tenant, type, content\n                'nacos_config' => [\n                    // 命名空间/ID\n                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId\n                    // DataID\n                    'data_id' => env('NACOS_DATA_ID'),\n                    // 组名\n                    'group' => 'DEFAULT_GROUP',\n                    'type' => 'json',\n                ],\n            ],\n            'client' => [\n                // 客户端\n                'host' => env('NACOS_HOST'),\n                'port' => env('NACOS_PORT'),\n                'username' => env('NACOS_USERNAME'),\n                'password' => env('NACOS_PASSWORD'),\n                'guzzle' => [\n                    'config' => null,\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/crontab.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/6/23\n * @create: 14:55\n */\n\nuse Hyperf\\Crontab\\Crontab;\n\nreturn [\n    // 是否开启定时任务\n    'enable' => true,\n    'crontab' => [\n        (new Crontab())->setType('command')\n            ->setName('TestCommand')\n            ->setRule('* * * * *')->setCallback([\n                'command' => 'TestCommand',\n            ]),\n    ],\n];"
  },
  {
    "path": "task-srv/config/autoload/databases.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'host' => env('DB_HOST', 'localhost'),\n        'port' => env('DB_PORT', 3306),\n        'database' => env('DB_DATABASE', 'hyperf'),\n        'username' => env('DB_USERNAME', 'root'),\n        'password' => env('DB_PASSWORD', ''),\n        'charset' => env('DB_CHARSET', 'utf8mb4'),\n        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),\n        'prefix' => env('DB_PREFIX', ''),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),\n        ],\n        'cache' => [\n            'handler' => Hyperf\\ModelCache\\Handler\\RedisHandler::class,\n            'cache_key' => '{mc:%s:m:%s}:%s:%s',\n            'prefix' => 'default',\n            'ttl' => 3600 * 24,\n            'empty_model_ttl' => 600,\n            'load_script' => true,\n        ],\n        'commands' => [\n            'gen:model' => [\n                'path' => 'app/Model',\n                'force_casts' => true,\n                'inheritance' => 'Model',\n                'uses' => '',\n                'table_mapping' => [],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/dependencies.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/devtool.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n                'namespace' => 'App\\\\Amqp\\\\Consumer',\n            ],\n            'producer' => [\n                'namespace' => 'App\\\\Amqp\\\\Producer',\n            ],\n        ],\n        'aspect' => [\n            'namespace' => 'App\\\\Aspect',\n        ],\n        'command' => [\n            'namespace' => 'App\\\\Command',\n        ],\n        'controller' => [\n            'namespace' => 'App\\\\Controller',\n        ],\n        'job' => [\n            'namespace' => 'App\\\\Job',\n        ],\n        'listener' => [\n            'namespace' => 'App\\\\Listener',\n        ],\n        'middleware' => [\n            'namespace' => 'App\\\\Middleware',\n        ],\n        'Process' => [\n            'namespace' => 'App\\\\Processes',\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/exceptions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception\\Handler\\HttpExceptionHandler::class,\n            App\\Exception\\Handler\\AppExceptionHandler::class,\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/listeners.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/logger.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handler\\RotatingFileHandler::class,\n            'constructor' => [\n                'filename' => BASE_PATH . '/runtime/logs/hyperf.log',\n                'level' => Monolog\\Logger::DEBUG,\n            ],\n        ],\n        'formatter' => [\n            'class' => Monolog\\Formatter\\LineFormatter::class,\n            'constructor' => [\n                'format' => null,\n                'dateFormat' => 'Y-m-d H:i:s',\n                'allowInlineLineBreaks' => true,\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/middlewares.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/nacos.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port\n    // 'url' => '',\n    // The nacos host info\n    'host' => env('NACOS_HOST'),\n    'port' => env('NACOS_PORT'),\n    // The nacos account info\n    'username' => env('NACOS_USERNAME'),\n    'password' => env('NACOS_PASSWORD'),\n    'guzzle' => [\n        'config' => null,\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/opentracing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zipkin'),\n    'enable' => [\n        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),\n        'redis' => env('TRACER_ENABLE_REDIS', false),\n        'db' => env('TRACER_ENABLE_DB', false),\n        'method' => env('TRACER_ENABLE_METHOD', false),\n    ],\n    'tracer' => [\n        'zipkin' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'options' => [\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            'sampler' => BinarySampler::createAsAlwaysSample(),\n        ],\n        'jaeger' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\JaegerTracerFactory::class,\n            'name' => env('APP_NAME', 'skeleton'),\n            'options' => [\n                'local_agent' => [\n                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),\n                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/processes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Crontab\\Process\\CrontabDispatcherProcess::class,\n];\n"
  },
  {
    "path": "task-srv/config/autoload/redis.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        'auth' => env('REDIS_AUTH', null),\n        'port' => (int) env('REDIS_PORT', 6379),\n        'db' => (int) env('REDIS_DB', 0),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/server.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    'mode' => SWOOLE_PROCESS,\n    'servers' => [\n        [\n            'name' => 'http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9506,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [Hyperf\\HttpServer\\Server::class, 'onRequest'],\n            ],\n        ],\n    ],\n    'settings' => [\n        Constant::OPTION_ENABLE_COROUTINE => true,\n        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),\n        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',\n        Constant::OPTION_OPEN_TCP_NODELAY => true,\n        Constant::OPTION_MAX_COROUTINE => 100000,\n        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,\n        Constant::OPTION_MAX_REQUEST => 100000,\n        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,\n        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,\n    ],\n    'callbacks' => [\n        Event::ON_WORKER_START => [Hyperf\\Framework\\Bootstrap\\WorkerStartCallback::class, 'onWorkerStart'],\n        Event::ON_PIPE_MESSAGE => [Hyperf\\Framework\\Bootstrap\\PipeMessageCallback::class, 'onPipeMessage'],\n        Event::ON_WORKER_EXIT => [Hyperf\\Framework\\Bootstrap\\WorkerExitCallback::class, 'onWorkerExit'],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/config.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_name' => env('APP_NAME', 'skeleton'),\n    'app_env' => env('APP_ENV', 'dev'),\n    'scan_cacheable' => env('SCAN_CACHEABLE', false),\n    StdoutLoggerInterface::class => [\n        'log_level' => [\n            LogLevel::ALERT,\n            LogLevel::CRITICAL,\n//            LogLevel::DEBUG,\n            LogLevel::EMERGENCY,\n            LogLevel::ERROR,\n            LogLevel::INFO,\n            LogLevel::NOTICE,\n            LogLevel::WARNING,\n        ],\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/container.php",
    "content": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Di\\Container;\nuse Hyperf\\Di\\Definition\\DefinitionSourceFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\n$container = new Container((new DefinitionSourceFactory(true))());\n\nif (! $container instanceof \\Psr\\Container\\ContainerInterface) {\n    throw new RuntimeException('The dependency injection container is invalid.');\n}\nreturn ApplicationContext::setContainer($container);\n"
  },
  {
    "path": "task-srv/config/routes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\\Controller\\IndexController@index');\n\nRouter::get('/favicon.ico', function () {\n    return '';\n});\n"
  },
  {
    "path": "task-srv/test/Cases/ExampleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversNothing\n */\nclass ExampleTest extends HttpTestCase\n{\n    public function testExample()\n    {\n        $this->assertTrue(true);\n        $this->assertTrue(is_array($this->get('/')));\n    }\n}\n"
  },
  {
    "path": "task-srv/test/HttpTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class HttpTestCase.\n * @method get($uri, $data = [], $headers = [])\n * @method post($uri, $data = [], $headers = [])\n * @method json($uri, $data = [], $headers = [])\n * @method file($uri, $data = [], $headers = [])\n * @method request($method, $path, $options = [])\n */\nabstract class HttpTestCase extends TestCase\n{\n    /**\n     * @var Client\n     */\n    protected $client;\n\n    public function __construct($name = null, array $data = [], $dataName = '')\n    {\n        parent::__construct($name, $data, $dataName);\n        $this->client = make(Client::class);\n    }\n\n    public function __call($name, $arguments)\n    {\n        return $this->client->{$name}(...$arguments);\n    }\n}\n"
  },
  {
    "path": "task-srv/test/bootstrap.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_reporting(E_ALL);\ndate_default_timezone_set('Asia/Shanghai');\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nSwoole\\Runtime::enableCoroutine(true);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\nHyperf\\Di\\ClassLoader::init();\n\n$container = require BASE_PATH . '/config/container.php';\n\n$container->get(Hyperf\\Contract\\ApplicationInterface::class);\n"
  },
  {
    "path": "user-srv/app/Amqp/Producer/UserProducer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Producer;\n\nuse Hyperf\\Amqp\\Annotation\\Producer;\nuse Hyperf\\Amqp\\Message\\ProducerMessage;\n\n/**\n * 用户订阅消息生产者\n * Class UserProducer\n * @package App\\Amqp\\Producer\n */\n#[Producer(exchange: 'user', routingKey: 'user')]\nclass UserProducer extends ProducerMessage\n{\n    public function __construct($data)\n    {\n        $this->payload = $data;\n    }\n}\n"
  },
  {
    "path": "user-srv/app/Constants/ErrorCode.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n/**\n * @Constants\n */\nclass ErrorCode extends AbstractConstants\n{\n    /**\n     * @Message(\"Server Error！\")\n     */\n    const SERVER_ERROR = 500;\n}\n"
  },
  {
    "path": "user-srv/app/Constants/ResponseCode.php",
    "content": "<?php\n\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n/**\n * @Constants\n */\nclass ResponseCode extends AbstractConstants\n{\n    /**\n     * @Message(\"请求错误\");\n     */\n    const ERROR = 0;\n\n    /**\n     * @Message(\"成功\");\n     */\n    const SUCCESS = 200;\n\n    /**\n     * @Message(\"创建成功\");\n     */\n    const CREATE_ED = 201;\n\n    /**\n     * 请求成功但服务器未处理，响应中包含指示信息\n     * @Message(\"请求成功\");\n     */\n    const ACCEPT_ED = 202;\n\n    /**\n     * 请求成功，但是没有响应内容\n     * @Message(\"请求成功\");\n     */\n    const NO_CONTENT = 204;\n\n    /**\n     * 请求成功，缓存生效\n     * @Message(\"NO_TMODIFIED\");\n     */\n    const NO_TMODIFIED = 302;\n\n    /**\n     * 请求错误，无法解析请求体\n     * @Message(\"请求错误\");\n     */\n    const BAD_REQUEST = 400;\n\n    /**\n     * 认证失败\n     * @Message(\"请登录\");\n     */\n    const UNAUTHORIZED = 401;\n\n    /**\n     * 服务器已经接受到请求，但拒绝执行\n     * @Message(\"FORBIDDEN\");\n     */\n    const FORBIDDEN = 403;\n\n    /**\n     * 找不到请求的资源\n     * @Message(\"找不到请求的资源\");\n     */\n    const  NOT_FOUND = 404;\n\n    /**\n     * 方法不允许当前用户访问\n     * @Message(\"METHOD_NOT_ALLOWED\");\n     */\n    const  METHOD_NOT_ALLOWED = 405;\n\n    /**\n     * 请求资源已过期\n     * @Message(\"GONE\");\n     */\n    const  GONE = 410;\n\n    /**\n     * 请求体内的类型错误\n     * @Message(\"MEDIA_TYPE\");\n     */\n    const  MEDIA_TYPE = 405;\n\n    /**\n     * 验证失败\n     * @Message(\"验证失败\");\n     */\n    const  UNPROCESSABLE = 422;\n\n\n    /**\n     * 请求频繁\n     * @Message(\"请求频繁\");\n     */\n    const  MAX_REQUEST = 429;\n\n\n\n}"
  },
  {
    "path": "user-srv/app/Controller/AbstractController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Contract\\ResponseInterface;\nuse Psr\\Container\\ContainerInterface;\n\nabstract class AbstractController\n{\n    /**\n     * @Inject\n     * @var ContainerInterface\n     */\n    protected $container;\n\n    /**\n     * @Inject\n     * @var RequestInterface\n     */\n    protected $request;\n\n    /**\n     * @Inject\n     * @var ResponseInterface\n     */\n    protected $response;\n}\n"
  },
  {
    "path": "user-srv/app/Controller/SagaController.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\UserService;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\HttpServer\\Annotation\\PostMapping;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * DTM.SAGA回调控制器\n * Class SagaController\n * @package App\\Controller\n */\n#[Controller(prefix: '/saga')]\nclass SagaController extends AbstractController\n{\n    /**\n     * 注入OrderService\n     * @var UserService\n     */\n    #[Inject]\n    protected UserService $userService;\n\n    /**\n     * 改变储值成功\n     * @param RequestInterface $request\n     * @return string[]\n     */\n    #[PostMapping(path: 'changeStored')]\n    public function changeStored(RequestInterface $request): array\n    {\n        //调用userService.changeStored方法\n        $this->userService->changeStored(\n            $request->input('user_id'),\n            $request->input('amount'),\n            $request->input('order_no'),\n        );\n\n        return [\n            'dtm_result' => 'SUCCESS',\n        ];\n    }\n\n    /**\n     * 改变储值成功补偿\n     * @param RequestInterface $request\n     * @return string[]\n     */\n    #[PostMapping(path: 'changeStoredCompensate')]\n    public function changeStoredCompensate(RequestInterface $request): array\n    {\n        //调用userService.changeStoredCompensate方法\n        $this->userService->changeStoredCompensate(\n            $request->input('user_id'),\n            $request->input('amount'),\n            $request->input('order_no'),\n        );\n\n        return [\n            'dtm_result' => 'SUCCESS',\n        ];\n    }\n}\n"
  },
  {
    "path": "user-srv/app/Exception/Handler/DtmExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\JsonRpcException;\nuse App\\Exception\\ServiceException;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Hyperf\\Utils\\Context;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Throwable;\n\n/**\n * DTM异常处理\n * Class JsonRpcExceptionHandler\n * @package App\\Exception\\Handler\n */\nclass DtmExceptionHandler extends ExceptionHandler\n{\n    /**\n     * @var StdoutLoggerInterface\n     */\n    protected $logger;\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n\n        if ($throwable instanceof ServiceException) {\n\n            //阻止异常冒泡\n            $this->stopPropagation();\n\n            return $response->withStatus(409);\n        }\n\n        // 交给下一个异常处理器\n        return $response;\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "user-srv/app/Exception/Handler/JsonRpcExceptionHandler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\JsonRpcException;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\ExceptionHandler;\nuse Hyperf\\HttpMessage\\Stream\\SwooleStream;\nuse Hyperf\\Context\\Context;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Throwable;\n\n/**\n * jsonRpc异常处理\n * Class JsonRpcExceptionHandler\n * @package App\\Exception\\Handler\n */\nclass JsonRpcExceptionHandler extends ExceptionHandler\n{\n    /**\n     * @var StdoutLoggerInterface\n     */\n    protected $logger;\n\n    public function handle(Throwable $throwable, ResponseInterface $response)\n    {\n\n        if ($throwable instanceof JsonRpcException) {\n\n\n            //阻止异常冒泡\n            $this->stopPropagation();\n\n            $request =  Context::get(ServerRequestInterface::class);\n            $jsonRpcTreaty = $request->getAttribute('data');\n            //返回自定义错误数据\n//            return di(ResponseBuilder::class)->buildResponse($request,$response);\n            $result = responseError($throwable->getCode(), $throwable->getMessage());\n\n            $jsonRpc = [\n                \"jsonrpc\" => $jsonRpcTreaty['jsonrpc'],\n                \"id\" => $jsonRpcTreaty['id'],\n                \"result\" => $result,\n                \"context\" => ''\n            ];\n\n            return $response->withStatus($throwable->getCode())\n                ->withAddedHeader('content-type', 'application/json; charset=utf-8')\n                ->withBody(new SwooleStream(json_encode($jsonRpc, JSON_UNESCAPED_UNICODE)));\n        }\n\n        // 交给下一个异常处理器\n        return $response;\n    }\n\n    public function isValid(Throwable $throwable): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "user-srv/app/Exception/JsonRpcException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass JsonRpcException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "user-srv/app/Exception/ServiceException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\ServerException;\nuse Throwable;\n\nclass ServiceException extends ServerException\n{\n    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)\n    {\n        if (is_null($message)) {\n            $message = ErrorCode::getMessage($code);\n        }\n\n        parent::__construct($message, $code, $previous);\n    }\n}\n"
  },
  {
    "path": "user-srv/app/JsonRpc/UserRpcService.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\nuse App\\Services\\AuthService;\nuse Hyperf\\RpcServer\\Annotation\\RpcService;\nuse App\\Services\\UserService;\nuse Hyperf\\Di\\Annotation\\Inject;\n\n/**\n * 用户rpc服务\n * Class OrderRpcService\n * @package App\\JsonRpc\n */\n#[RpcService(name: \"UserRpcService\", protocol: \"jsonrpc-http\", server: \"jsonrpc-http\", publishTo: \"nacos\")]\nclass UserRpcService implements UserRpcServiceInterface\n{\n    #[Inject]\n    protected UserService $userService;\n\n    #[Inject]\n    protected AuthService $authService;\n\n    /**\n     * 用户详情\n     * @param int $userId\n     * @return array\n     */\n    public function userInfo(int $userId): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->userService->userInfo($userId)\n        ];\n    }\n\n    /**\n     * 用户积分列表\n     * @param int $page\n     * @param int $pageSize\n     * @return array\n     */\n    public function userBonusList(int $page, int $pageSize): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->userService->userBonusList($page, $pageSize)\n        ];\n    }\n\n    /**\n     * 用户储值列表\n     * @param int $page\n     * @param int $pageSize\n     * @return array\n     */\n    public function userStoredList(int $page, int $pageSize): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->userService->userStoredList($page, $pageSize)\n        ];\n    }\n\n    /**\n     * 投递用户消息到RabbitMQ\n     * @return array\n     */\n    public function userRabbitMQ() : array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->userService->userRabbitMQ()\n        ];\n    }\n\n    /**\n     * 用户登录\n     * @param string $phone\n     * @return array\n     */\n    public function userLogin(string $phone): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->authService->userLogin($phone)\n        ];\n    }\n\n    /**\n     * 用户退出\n     * @param string $token\n     * @return array\n     */\n    public function userLogout(string $token): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->authService->userLogout($token)\n        ];\n    }\n\n    /**\n     * 检查用户token\n     * @param string $token\n     * @return array\n     */\n    public function userCheckToken(string $token): array\n    {\n        return [\n            'code' => 200,\n            'data' => $this->authService->userCheckToken($token)\n        ];\n    }\n}"
  },
  {
    "path": "user-srv/app/JsonRpc/UserRpcServiceInterface.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface UserRpcServiceInterface\n{\n\n    public function userInfo(int $userId): array;\n\n    public function userBonusList(int $page, int $pageSize): array;\n\n    public function userStoredList(int $page, int $pageSize): array;\n\n    public function userRabbitMQ(): array;\n\n    public function userLogin(string $phone): array;\n\n    public function userLogout(string $token): array;\n\n    public function userCheckToken(string $token): array;\n\n}"
  },
  {
    "path": "user-srv/app/Kernel/Functions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://doc.hyperf.io\n * @contact  group@hyperf.io\n */\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Hyperf\\Redis\\Redis;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf\\ExceptionHandler\\Formatter\\FormatterInterface;\n\n/**\n * 获取Container\n */\nif (!function_exists('di')) {\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     * @param null|mixed $id\n     * @return mixed|\\Psr\\Container\\ContainerInterface\n     */\n    function di($id = null)\n    {\n        $container = ApplicationContext::getContainer();\n        if ($id) {\n            return $container->get($id);\n        }\n        return $container;\n    }\n}\n\n/**\n * 控制台日志\n */\nif (!function_exists('stdLog')) {\n    function stdLog()\n    {\n        return di()->get(StdoutLoggerInterface::class);\n    }\n}\n\n/**\n * 文件日志\n */\nif (!function_exists('logger')) {\n    function logger($name = 'log', $group = 'default')\n    {\n        return di()->get(LoggerFactory::class)->get($name, $group);\n    }\n}\n\n/**\n * redis 客户端实例\n */\nif (!function_exists('redis')) {\n    function redis()\n    {\n        return di()->get(Redis::class);\n    }\n}\n\n/**\n * 缓存实例 简单的缓存\n */\nif (!function_exists('cache')) {\n    function cache()\n    {\n        return di()->get(\\Psr\\SimpleCache\\CacheInterface::class);\n    }\n}\n\nif (!function_exists('format_throwable')) {\n    /**\n     * Format a throwable to string.\n     * @param Throwable $throwable\n     * @return string\n     */\n    function format_throwable(Throwable $throwable): string\n    {\n        return di()->get(FormatterInterface::class)->format($throwable);\n    }\n}\n\n\nif (!function_exists('responseSuccess')) {\n    function responseSuccess($code, $message = '', $data = [])\n    {\n        $content = ['code' => $code];\n        $message ? $content['msg'] = $message : $content['msg'] = \\App\\Constants\\ResponseCode::getMessage($code);\n        $data ? $content['data'] = $data : $content['data'] = [];\n        return $content;\n    }\n}\n\nif (!function_exists('responseError')) {\n    function responseError($code, $message = '', $data = [])\n    {\n        $content = ['code' => $code];\n        $data ? $content['data'] = $data : $content['data'] = [];\n        return $content;\n    }\n}\n\n\n/**\n * 判读字符串是否为json\n */\nif (!function_exists('isJson')) {\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     * @param string $string\n     */\n    function isJson($string)\n    {\n        json_decode($string);\n        return (json_last_error() == JSON_ERROR_NONE);\n    }\n}\n\n\n/**\n * 返回jsonRpc结构\n */\nif (!function_exists('successJsonRpc')) {\n    function successJsonRpc($code, $data)\n    {\n        return [\n            'code' => $code,\n            'data' => $data\n        ];\n    }\n}\n\n\n"
  },
  {
    "path": "user-srv/app/Listener/DbQueryExecutedListener.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Annotation\\Listener;\nuse Hyperf\\Event\\Contract\\ListenerInterface;\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\Arr;\nuse Hyperf\\Utils\\Str;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * @Listener\n */\nclass DbQueryExecutedListener implements ListenerInterface\n{\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->logger = $container->get(LoggerFactory::class)->get('sql');\n    }\n\n    public function listen(): array\n    {\n        return [\n            QueryExecuted::class,\n        ];\n    }\n\n    /**\n     * @param QueryExecuted $event\n     */\n    public function process(object $event) : void\n    {\n        if ($event instanceof QueryExecuted) {\n            $sql = $event->sql;\n            if (! Arr::isAssoc($event->bindings)) {\n                foreach ($event->bindings as $key => $value) {\n                    $sql = Str::replaceFirst('?', \"'{$value}'\", $sql);\n                }\n            }\n\n            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));\n        }\n    }\n}\n"
  },
  {
    "path": "user-srv/app/Log.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\nclass Log\n{\n    public static function get(string $name = 'app')\n    {\n        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);\n    }\n}"
  },
  {
    "path": "user-srv/app/Model/User.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\nuse Qbhy\\HyperfAuth\\AuthAbility;\nuse Qbhy\\HyperfAuth\\Authenticatable;\n\nclass User extends Model implements Authenticatable\n{\n    use AuthAbility;\n\n    const CREATED_AT = 'create_time';\n\n    const UPDATED_AT = 'update_time';\n\n    protected ?string $dateFormat = 'U';\n    /**\n     * The table associated with the model.\n     *\n     * @var string\n     */\n    protected ?string $table = 'user';\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected array $fillable = [\n        'user_name',\n        'user_image',\n        'phone',\n        'sex',\n    ];\n    /**\n     * The attributes that should be cast to native types.\n     *\n     * @var array\n     */\n    protected array $casts = ['id' => 'integer'];\n\n    public function bonus()\n    {\n        return $this->hasMany(UserBonusLog::class, 'user_id', 'id');\n    }\n\n    public function stored()\n    {\n        return $this->hasMany(UserStoredLog::class, 'user_id', 'id');\n    }\n}"
  },
  {
    "path": "user-srv/app/Model/UserBonusLog.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\n\nclass UserBonusLog extends Model\n{\n\n    const CREATED_AT = 'create_time';\n\n    const UPDATED_AT = 'update_time';\n\n    protected ?string $dateFormat = 'U';\n    /**\n     * The table associated with the model.\n     *\n     * @var string\n     */\n    protected ?string $table = 'user_bonus_log';\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected array $fillable = [\n        'user_id',\n        'type',\n        'bonus',\n        'source',\n        'remark',\n    ];\n    /**\n     * The attributes that should be cast to native types.\n     *\n     * @var array\n     */\n    protected array $casts = ['id' => 'integer'];\n\n}"
  },
  {
    "path": "user-srv/app/Model/UserStoredLog.php",
    "content": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\n\nclass UserStoredLog extends Model\n{\n    const CREATED_AT = 'create_time';\n\n    const UPDATED_AT = 'update_time';\n\n    protected ?string $dateFormat = 'U';\n    /**\n     * The table associated with the model.\n     *\n     * @var string\n     */\n    protected ?string $table = 'user_stored_log';\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected array $fillable = [\n        'user_id',\n        'type',\n        'amount',\n        'source',\n        'remark',\n    ];\n    /**\n     * The attributes that should be cast to native types.\n     *\n     * @var array\n     */\n    protected array $casts = ['id' => 'integer'];\n}"
  },
  {
    "path": "user-srv/app/Services/AuthService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\JsonRpcException;\nuse App\\Log;\nuse App\\Model\\User;\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Qbhy\\HyperfAuth\\Authenticatable;\nuse Qbhy\\HyperfAuth\\AuthManager;\n\n/**\n * 用户service\n * Class AuthService\n * @package App\\Services\n */\nclass AuthService\n{\n\n    #[Inject]\n    protected AuthManager $auth;\n\n    /**\n     * 用户登录\n     * @param $phone\n     * @return mixed\n     */\n    public function userLogin($phone)\n    {\n        Log::get()->info(\"调用userLogin\");\n\n        $user = User::query()\n            ->withSum('bonus', 'bonus')\n            ->withSum('stored', 'amount')\n            ->where('phone',$phone)\n            ->first();\n\n        if (empty($user)) {\n            Log::get()->info(\"用户不存在\");\n\n            throw new JsonRpcException(10001);\n        }\n\n        return [\n            'user_info' => $user,\n            'token_type' => 'bearer_token',\n            'token' => $this->auth->guard('jwt')->login($user),\n        ];\n    }\n\n    /**\n     * 用户退出\n     * @param $token\n     * @return mixed\n     */\n    public function userLogout($token)\n    {\n        Log::get()->info(\"调用userLogout\");\n\n        $this->auth->guard('jwt')->logout($token);\n\n        return ;\n    }\n\n    /**\n     * 检查用户token\n     * @param $token\n     * @return mixed\n     */\n    public function userCheckToken($token)\n    {\n        Log::get()->info(\"调用userCheckToken\");\n\n        $guard = $this->auth->guard('jwt');\n\n        try {\n\n            if (! $guard->user($token) instanceof Authenticatable) {\n                throw new JsonRpcException(422);\n            }\n\n        }catch (\\Throwable $exception){\n            throw new JsonRpcException(422);\n        }\n\n        return ;\n    }\n}"
  },
  {
    "path": "user-srv/app/Services/UserService.php",
    "content": "<?php\n\n\nnamespace App\\Services;\n\nuse Hyperf\\Amqp\\Producer;\nuse App\\Amqp\\Producer\\UserProducer;\nuse App\\Exception\\JsonRpcException;\nuse App\\Exception\\ServiceException;\nuse App\\Log;\nuse App\\Model\\User;\nuse App\\Model\\UserBonusLog;\nuse App\\Model\\UserStoredLog;\n\n/**\n * 用户service\n * Class UserService\n * @package App\\Services\n */\nclass UserService\n{\n\n    /**\n     * 用户详情\n     * @param $userId\n     * @return array|mixed[]\n     */\n    public function userInfo($userId)\n    {\n        Log::get()->info(\"调用userInfo\");\n\n        $User = User::query()\n            ->withSum('bonus', 'bonus')\n            ->withSum('stored', 'amount')\n            ->find($userId);\n\n        if (empty($User)) {\n            Log::get()->info(\"用户不存在\");\n\n            throw new JsonRpcException(10001);\n        }\n\n        return $User->toArray();\n\n    }\n\n    /**\n     * 用户积分列表\n     * @param $page\n     * @param $pageSize\n     * @return mixed\n     */\n    public function userBonusList($page, $pageSize)\n    {\n        Log::get()->info(\"调用userBonusList\");\n\n        $list = UserBonusLog::query()\n            ->paginate($pageSize, ['*'], 'page', $page);\n\n        if ($list->isEmpty()) {\n            Log::get()->info(\"用户积分不存在\");\n\n            throw new JsonRpcException(10002);\n        }\n\n        return $list->toArray();\n    }\n\n    /**\n     * 用户储值列表\n     * @param $page\n     * @param $pageSize\n     * @return mixed\n     */\n    public function userStoredList($page, $pageSize)\n    {\n        Log::get()->info(\"调用userBonusList\");\n\n        $list = UserStoredLog::query()\n            ->paginate($pageSize, ['*'], 'page', $page);\n\n        if ($list->isEmpty()) {\n            Log::get()->info(\"用户储值不存在\");\n\n            throw new JsonRpcException(10003);\n        }\n\n        return $list->toArray();\n    }\n\n    /**\n     * SAGA改变用户储值成功\n     * @param $userId\n     * @param $amount\n     * @param $orderNo\n     */\n    public function changeStored($userId, $amount, $orderNo)\n    {\n        Log::get()->info(\"分布式事务-changeStored\", [\n            'user_id' => $userId,\n            'amount' => $amount,\n            'order_no' => $orderNo,\n        ]);\n\n        //分布式事务\n        try {\n\n            UserStoredLog::create([\n                'user_id' => $userId,\n                'type' => $amount >= 0 ? 1 : -1,\n                'amount' => $amount,\n                'source' => 'order',\n                'remark' => $orderNo\n            ]);\n\n        } catch (\\Throwable $e) {\n            Log::get()->info(\"分布式事务-changeStored-调用失败\");\n\n            throw new ServiceException();\n        }\n\n    }\n\n    /**\n     * SAGA改变用户储值补偿\n     * @param $userId\n     * @param $amount\n     * @param $orderNo\n     */\n    public function changeStoredCompensate($userId, $amount, $orderNo)\n    {\n        Log::get()->info(\"分布式事务-changeStoredCompensate\", [\n            'user_id' => $userId,\n            'amount' => $amount,\n            'order_no' => $orderNo,\n        ]);\n\n        //分布式事务\n        try {\n            UserStoredLog::query()\n                ->where('user_id', $userId)\n                ->where('source', 'order')\n                ->where('remark', $orderNo)\n                ->delete();\n\n        } catch (\\Throwable $e) {\n            Log::get()->info(\"分布式事务-changeStoredCompensate-调用失败\");\n\n            throw new ServiceException();\n        }\n\n    }\n\n    /**\n     * 投递用户消息到RabbitMQ\n     */\n    public function userRabbitMQ()\n    {\n\n        //拼装数据\n        $message = new UserProducer([\n            'id' => 1\n        ]);\n\n        $producer = di()->get(Producer::class);\n\n        //投递消息\n        $result = $producer->produce($message);\n\n        //投递消息失败\n        if ($result != true){\n            throw new JsonRpcException(430);\n        }\n\n    }\n}"
  },
  {
    "path": "user-srv/bin/hyperf.php",
    "content": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limit', '1G');\n\nerror_reporting(E_ALL);\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\n// Self-called anonymous function that creates its own scope and keep the global namespace clean.\n(function () {\n    Hyperf\\Di\\ClassLoader::init();\n    /** @var Psr\\Container\\ContainerInterface $container */\n    $container = require BASE_PATH . '/config/container.php';\n\n    $application = $container->get(Hyperf\\Contract\\ApplicationInterface::class);\n    $application->run();\n})();\n"
  },
  {
    "path": "user-srv/composer.json",
    "content": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n        \"framework\",\n        \"hyperf\",\n        \"microservice\",\n        \"middleware\"\n    ],\n    \"description\": \"A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.\",\n    \"license\": \"Apache-2.0\",\n    \"require\": {\n        \"php\": \">=8.0\",\n        \"96qbhy/hyperf-auth\": \"^3.0.0\",\n        \"dtm/dtm-client\": \"^0.3.0\",\n        \"hyperf/amqp\": \"3.0.*\",\n        \"hyperf/cache\": \"3.0.*\",\n        \"hyperf/command\": \"3.0.*\",\n        \"hyperf/config\": \"3.0.*\",\n        \"hyperf/config-nacos\": \"3.0.*\",\n        \"hyperf/constants\": \"3.0.*\",\n        \"hyperf/database\": \"3.0.*\",\n        \"hyperf/db-connection\": \"3.0.*\",\n        \"hyperf/framework\": \"3.0.*\",\n        \"hyperf/guzzle\": \"3.0.*\",\n        \"hyperf/http-server\": \"3.0.*\",\n        \"hyperf/json-rpc\": \"3.0.*\",\n        \"hyperf/logger\": \"3.0.*\",\n        \"hyperf/memory\": \"3.0.*\",\n        \"hyperf/model-cache\": \"3.0.*\",\n        \"hyperf/paginator\": \"3.0.*\",\n        \"hyperf/process\": \"3.0.*\",\n        \"hyperf/redis\": \"3.0.*\",\n        \"hyperf/rpc\": \"3.0.*\",\n        \"hyperf/rpc-client\": \"3.0.*\",\n        \"hyperf/rpc-server\": \"3.0.*\",\n        \"hyperf/service-governance\": \"3.0.*\",\n        \"hyperf/service-governance-nacos\": \"3.0.*\",\n        \"hyperf/tracer\": \"3.0.*\"\n    },\n    \"require-dev\": {\n        \"friendsofphp/php-cs-fixer\": \"^3.0\",\n        \"hyperf/devtool\": \"3.0.*\",\n        \"hyperf/ide-helper\": \"3.0.*\",\n        \"hyperf/testing\": \"3.0.*\",\n        \"hyperf/watcher\": \"3.0.*\",\n        \"mockery/mockery\": \"^1.0\",\n        \"phpstan/phpstan\": \"^0.12\",\n        \"swoole/ide-helper\": \"^4.5\"\n    },\n    \"suggest\": {\n        \"ext-openssl\": \"Required to use HTTPS.\",\n        \"ext-json\": \"Required to use JSON.\",\n        \"ext-pdo\": \"Required to use MySQL Client.\",\n        \"ext-pdo_mysql\": \"Required to use MySQL Client.\",\n        \"ext-redis\": \"Required to use Redis Client.\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\"\n        },\n        \"files\": [\n            \"app/Kernel/Functions.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"HyperfTest\\\\\": \"./test/\"\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true,\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"sort-packages\": true\n    },\n    \"extra\": [],\n    \"scripts\": {\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-autoload-dump\": [\n            \"rm -rf runtime/container\"\n        ],\n        \"test\": \"co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always\",\n        \"cs-fix\": \"php-cs-fixer fix $1\",\n        \"analyse\": \"phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config\",\n        \"start\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"php ./bin/hyperf.php start\"\n        ]\n    }\n}\n"
  },
  {
    "path": "user-srv/config/autoload/amqp.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('AMQP_HOST', 'localhost'),\n        'port' => (int) env('AMQP_PORT', 5672),\n        'user' => env('AMQP_USER', 'guest'),\n        'password' => env('AMQP_PASSWORD', 'guest'),\n        'vhost' => env('AMQP_VHOST', '/'),\n        'open_ssl' => false,\n        'concurrent' => [\n            'limit' => 1,\n        ],\n        'pool' => [\n            'connections' => 2,\n        ],\n        'params' => [\n            'insist' => false,\n            'login_method' => 'AMQPLAIN',\n            'login_response' => null,\n            'locale' => 'en_US',\n            'connection_timeout' => 3,\n            'read_write_timeout' => 6,\n            'context' => null,\n            'keepalive' => true,\n            'heartbeat' => 3,\n            'channel_rpc_timeout' => 0.0,\n            'close_on_destruct' => false,\n            'max_idle_channels' => 10,\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/annotations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ],\n        'ignore_annotations' => [\n            'mixin',\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/aspects.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Tracer\\Aspect\\JsonRpcAspect::class,\n];\n"
  },
  {
    "path": "user-srv/config/autoload/auth.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of qbhy/hyperf-auth.\n *\n * @link     https://github.com/qbhy/hyperf-auth\n * @document https://github.com/qbhy/hyperf-auth/blob/master/README.md\n * @contact  qbhy0715@qq.com\n * @license  https://github.com/qbhy/hyperf-auth/blob/master/LICENSE\n */\nuse Qbhy\\SimpleJwt\\Encoders;\nuse Qbhy\\SimpleJwt\\EncryptAdapters as Encrypter;\n\n/*\n * This file is part of qbhy/hyperf-auth.\n *\n * @link     https://github.com/qbhy/hyperf-auth\n * @document https://github.com/qbhy/hyperf-auth/blob/master/README.md\n * @contact  qbhy0715@qq.com\n * @license  https://github.com/qbhy/hyperf-auth/blob/master/LICENSE\n */\nreturn [\n    'default' => [\n        'guard' => 'jwt',\n        'provider' => 'user',\n    ],\n    'guards' => [\n        'jwt' => [\n            'driver' => Qbhy\\HyperfAuth\\Guard\\JwtGuard::class,\n            'provider' => 'user',\n\n            /*\n             * 以下是 simple-jwt 配置\n            * 必填\n            * jwt 服务端身份标识\n            */\n            'secret' => env('SIMPLE_JWT_SECRET'),\n\n            /*\n             * 可选配置\n             * jwt 默认头部token使用的字段\n             */\n            'header_name' => env('JWT_HEADER_NAME', 'Authorization'),\n\n            /*\n             * 可选配置\n             * jwt 生命周期，单位秒\n             */\n            'ttl' => (int) env('SIMPLE_JWT_TTL', 60 * 60 * 24*3),\n\n            /*\n             * 可选配置\n             * 允许过期多久以内的 token 进行刷新\n             */\n            'refresh_ttl' => (int) env('SIMPLE_JWT_REFRESH_TTL', 60 * 60 * 24 * 7),\n\n            /*\n             * 可选配置\n             * 默认使用的加密类\n             */\n            'default' => Encrypter\\PasswordHashEncrypter::class,\n\n            /*\n             * 可选配置\n             * 加密类必须实现 Qbhy\\SimpleJwt\\Interfaces\\Encrypter 接口\n             */\n            'drivers' => [\n                Encrypter\\PasswordHashEncrypter::alg() => Encrypter\\PasswordHashEncrypter::class,\n                Encrypter\\CryptEncrypter::alg() => Encrypter\\CryptEncrypter::class,\n                Encrypter\\SHA1Encrypter::alg() => Encrypter\\SHA1Encrypter::class,\n                Encrypter\\Md5Encrypter::alg() => Encrypter\\Md5Encrypter::class,\n            ],\n\n            /*\n             * 可选配置\n             * 编码类\n             */\n            'encoder' => new Encoders\\Base64UrlSafeEncoder(),\n            //            'encoder' => new Encoders\\Base64Encoder(),\n\n            /*\n             * 可选配置\n             * 缓存类\n             */\n//            'cache' => new \\Doctrine\\Common\\Cache\\FilesystemCache(sys_get_temp_dir()),\n            // 如果需要分布式部署，请选择 redis 或者其他支持分布式的缓存驱动\n            'cache' => function () {\n                return make(Qbhy\\HyperfAuth\\HyperfRedisCache::class);\n            },\n\n            /*\n             * 可选配置\n             * 缓存前缀\n             */\n            'prefix' => env('SIMPLE_JWT_PREFIX', 'jwt'),\n        ],\n        'session' => [\n            'driver' => Qbhy\\HyperfAuth\\Guard\\SessionGuard::class,\n            'provider' => 'users',\n        ],\n    ],\n\n    'providers' => [\n        'user' => [\n            'driver' => \\Qbhy\\HyperfAuth\\Provider\\EloquentProvider::class,\n            'model' => App\\Model\\User::class, //  需要实现 Qbhy\\HyperfAuth\\Authenticatable 接口\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/cache.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,\n        'packer' => Hyperf\\Utils\\Packer\\PhpSerializerPacker::class,\n        'prefix' => 'c:',\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/commands.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "user-srv/config/autoload/config_center.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),\n    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),\n    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),\n    'drivers' => [\n        'nacos' => [\n            'driver' => Hyperf\\ConfigNacos\\NacosDriver::class,\n            'merge_mode' => Hyperf\\ConfigNacos\\Constants::CONFIG_MERGE_OVERWRITE,\n            'interval' => 3,\n            'default_key' => 'nacos_config',\n            'listener_config' => [\n                // dataId, group, tenant, type, content\n                'nacos_config' => [\n                    // 命名空间/ID\n                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId\n                    // DataID\n                    'data_id' => env('NACOS_DATA_ID'),\n                    // 组名\n                    'group' => 'DEFAULT_GROUP',\n                    'type' => 'json',\n                ],\n            ],\n            'client' => [\n                // 客户端\n                'host' => env('NACOS_HOST'),\n                'port' => env('NACOS_PORT'),\n                'username' => env('NACOS_USERNAME'),\n                'password' => env('NACOS_PASSWORD'),\n                'guzzle' => [\n                    'config' => null,\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/databases.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'host' => env('DB_HOST', 'localhost'),\n        'port' => env('DB_PORT', 3306),\n        'database' => env('DB_DATABASE', 'hyperf'),\n        'username' => env('DB_USERNAME', 'root'),\n        'password' => env('DB_PASSWORD', ''),\n        'charset' => env('DB_CHARSET', 'utf8mb4'),\n        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),\n        'prefix' => env('DB_PREFIX', ''),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),\n        ],\n//        'cache' => [\n//            'handler' => Hyperf\\ModelCache\\Handler\\RedisHandler::class,\n//            'cache_key' => '{mc:%s:m:%s}:%s:%s',\n//            'prefix' => 'default',\n//            'ttl' => 3600 * 24,\n//            'empty_model_ttl' => 600,\n//            'load_script' => true,\n//        ],\n        'commands' => [\n            'gen:model' => [\n                'path' => 'app/Model',\n                'force_casts' => true,\n                'inheritance' => 'Model',\n                'uses' => '',\n                'table_mapping' => [],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/dependencies.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "user-srv/config/autoload/devtool.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n                'namespace' => 'App\\\\Amqp\\\\Consumer',\n            ],\n            'producer' => [\n                'namespace' => 'App\\\\Amqp\\\\Producer',\n            ],\n        ],\n        'aspect' => [\n            'namespace' => 'App\\\\Aspect',\n        ],\n        'command' => [\n            'namespace' => 'App\\\\Command',\n        ],\n        'controller' => [\n            'namespace' => 'App\\\\Controller',\n        ],\n        'job' => [\n            'namespace' => 'App\\\\Job',\n        ],\n        'listener' => [\n            'namespace' => 'App\\\\Listener',\n        ],\n        'middleware' => [\n            'namespace' => 'App\\\\Middleware',\n        ],\n        'Process' => [\n            'namespace' => 'App\\\\Processes',\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/dtm.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of DTM-PHP.\n *\n * @license  https://github.com/dtm-php/dtm-client/blob/master/LICENSE\n */\nuse DtmClient\\Constants\\Protocol;\nuse DtmClient\\Constants\\DbType;\n\nreturn [\n    'protocol' => Protocol::HTTP,\n    'server' => '127.0.0.1',\n    'port' => [\n        'http' => 36789,\n        'grpc' => 36790,\n    ],\n    'barrier' => [\n        'db' => [\n            'type' => DbType::MySQL\n        ],\n        'apply' => [],\n    ],\n    'guzzle' => [\n        'options' => [],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/exceptions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception\\Handler\\HttpExceptionHandler::class,\n            App\\Exception\\Handler\\DtmExceptionHandler::class,\n        ],\n        'jsonrpc-http' => [\n            App\\Exception\\Handler\\JsonRpcExceptionHandler::class,\n        ]\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/listeners.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "user-srv/config/autoload/logger.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handler\\RotatingFileHandler::class,\n            'constructor' => [\n                'filename' => BASE_PATH . '/runtime/logs/hyperf.log',\n                'level' => Monolog\\Logger::DEBUG,\n            ],\n        ],\n        'formatter' => [\n            'class' => Monolog\\Formatter\\LineFormatter::class,\n            'constructor' => [\n                'format' => null,\n                'dateFormat' => 'Y-m-d H:i:s',\n                'allowInlineLineBreaks' => true,\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/middlewares.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n        \\DtmClient\\Middleware\\DtmMiddleware::class,\n    ],\n    'jsonrpc-http' => [\n        \\Hyperf\\Tracer\\Middleware\\TraceMiddleware::class,\n        \\DtmClient\\Middleware\\DtmMiddleware::class,\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/nacos.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port\n    // 'url' => '',\n    // The nacos host info\n    'host' => env('NACOS_HOST'),\n    'port' => env('NACOS_PORT'),\n    // The nacos account info\n    'username' => env('NACOS_USERNAME'),\n    'password' => env('NACOS_PASSWORD'),\n    'guzzle' => [\n        'config' => null,\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/opentracing.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zipkin'),\n    'enable' => [\n        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),\n        'redis' => env('TRACER_ENABLE_REDIS', false),\n        'db' => env('TRACER_ENABLE_DB', false),\n        'method' => env('TRACER_ENABLE_METHOD', false),\n    ],\n    'tracer' => [\n        'zipkin' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'options' => [\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            'sampler' => BinarySampler::createAsAlwaysSample(),\n        ],\n        'jaeger' => [\n            'driver' => \\Hyperf\\Tracer\\Adapter\\JaegerTracerFactory::class,\n            'name' => env('APP_NAME', 'skeleton'),\n            'options' => [\n                'local_agent' => [\n                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),\n                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),\n                ],\n            ],\n        ],\n    ],\n    'tags' => [\n        // HTTP 客户端 (Guzzle)\n        'http_client' => [\n            'http.url' => 'http.url',\n            'http.method' => 'http.method',\n            'http.status_code' => 'http.status_code',\n        ],\n        // Redis 客户端\n        'redis' => [\n            'arguments' => 'arguments',\n            'result' => 'result',\n        ],\n        // 数据库客户端 (hyperf/database)\n        'db' => [\n            'db.query' => 'db.query',\n            'db.statement' => 'db.statement',\n            'db.query_time' => 'db.query_time',\n        ],\n    ]\n];\n"
  },
  {
    "path": "user-srv/config/autoload/processes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "user-srv/config/autoload/redis.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        'auth' => env('REDIS_AUTH', null),\n        'port' => (int) env('REDIS_PORT', 6379),\n        'db' => (int) env('REDIS_DB', 0),\n        'pool' => [\n            'min_connections' => 1,\n            'max_connections' => 10,\n            'connect_timeout' => 10.0,\n            'wait_timeout' => 3.0,\n            'heartbeat' => -1,\n            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/server.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    'mode' => SWOOLE_PROCESS,\n    'servers' => [\n        [\n            'name' => 'http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9503,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [Hyperf\\HttpServer\\Server::class, 'onRequest'],\n            ],\n        ],\n        [\n            'name' => 'jsonrpc-http',\n            'type' => Server::SERVER_HTTP,\n            'host' => '0.0.0.0',\n            'port' => 9504,\n            'sock_type' => SWOOLE_SOCK_TCP,\n            'callbacks' => [\n                Event::ON_REQUEST => [\\Hyperf\\JsonRpc\\HttpServer::class, 'onRequest'],\n            ],\n        ],\n    ],\n    'settings' => [\n        Constant::OPTION_ENABLE_COROUTINE => true,\n        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),\n        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',\n        Constant::OPTION_OPEN_TCP_NODELAY => true,\n        Constant::OPTION_MAX_COROUTINE => 100000,\n        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,\n        Constant::OPTION_MAX_REQUEST => 100000,\n        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,\n        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,\n    ],\n    'callbacks' => [\n        Event::ON_WORKER_START => [Hyperf\\Framework\\Bootstrap\\WorkerStartCallback::class, 'onWorkerStart'],\n        Event::ON_PIPE_MESSAGE => [Hyperf\\Framework\\Bootstrap\\PipeMessageCallback::class, 'onPipeMessage'],\n        Event::ON_WORKER_EXIT => [Hyperf\\Framework\\Bootstrap\\WorkerExitCallback::class, 'onWorkerExit'],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/autoload/services.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n\nreturn [\n    'enable' => [\n        // 开启服务发现\n        'discovery' => true,\n        // 开启服务注册\n        'register' => true,\n    ],\n    // 服务消费者相关配置\n    'consumers' => [],\n    // 服务提供者相关配置\n    'providers' => [],\n    // 服务驱动相关配置\n    'drivers' => [\n        // nacos 配置,当前使用\n        'nacos' => [\n            // The nacos host info\n            'host' => env('NACOS_HOST'),\n            'port' => env('NACOS_PORT'),\n            // nacos 账号密码信息\n            'username' => env('NACOS_USERNAME'),\n            'password' => env('NACOS_PASSWORD'),\n            'guzzle' => [\n                'config' => null,\n            ],\n            // 命名空间,public为默认系统空间\n            'group_name' => 'api',\n            // 命名空间ID\n             'namespace_id' => env('NACOS_TENANT'),\n            // 心跳检查秒数\n            'heartbeat' => 5,\n            'ephemeral' => true, // 是否注册临时实例\n        ],\n    ],\n];"
  },
  {
    "path": "user-srv/config/autoload/tracer.php",
    "content": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/25\n * @create: 11:29\n */\n\nreturn [\n    // 选择默认的 Tracer\n    'default' => env('TRACER_DRIVER', 'jaeger'),\n\n    // 这里的代码演示不对 enable 内的配置进行展开\n    'enable' => [],\n\n    'tracer' => [\n        // Zipkin 驱动配置\n        'zipkin' => [\n            // 当前应用的配置\n            'app' => [\n                'name' => env('APP_NAME', 'skeleton'),\n                // 如果 ipv6 和 ipv6 为空组件会自动从 Server 中检测\n                'ipv4' => '127.0.0.1',\n                'ipv6' => null,\n                'port' => 9501,\n            ],\n            'driver' => \\Hyperf\\Tracer\\Adapter\\ZipkinTracerFactory::class,\n            'options' => [\n                // Zipkin 服务的 endpoint 地址\n                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),\n                // 请求超时秒数\n                'timeout' => env('ZIPKIN_TIMEOUT', 1),\n            ],\n            // 采样器，默认为所有请求的都追踪\n            'sampler' => \\Zipkin\\Samplers\\BinarySampler::createAsAlwaysSample(),\n        ],\n\n    ],\n];"
  },
  {
    "path": "user-srv/config/autoload/watcher.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Watcher\\Driver\\ScanFileDriver;\n\nreturn [\n    'driver' => ScanFileDriver::class,\n    'bin' => 'php',\n    'watch' => [\n        'dir' => ['app', 'config'],\n        'file' => ['.env'],\n        'scan_interval' => 2000,\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/config.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_name' => env('APP_NAME', 'skeleton'),\n    'app_env' => env('APP_ENV', 'dev'),\n    'scan_cacheable' => env('SCAN_CACHEABLE', false),\n    StdoutLoggerInterface::class => [\n        'log_level' => [\n            LogLevel::ALERT,\n            LogLevel::CRITICAL,\n//            LogLevel::DEBUG,\n            LogLevel::EMERGENCY,\n            LogLevel::ERROR,\n            LogLevel::INFO,\n            LogLevel::NOTICE,\n            LogLevel::WARNING,\n        ],\n    ],\n];\n"
  },
  {
    "path": "user-srv/config/container.php",
    "content": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Di\\Container;\nuse Hyperf\\Di\\Definition\\DefinitionSourceFactory;\nuse Hyperf\\Utils\\ApplicationContext;\n\n$container = new Container((new DefinitionSourceFactory(true))());\n\nif (! $container instanceof \\Psr\\Container\\ContainerInterface) {\n    throw new RuntimeException('The dependency injection container is invalid.');\n}\nreturn ApplicationContext::setContainer($container);\n"
  },
  {
    "path": "user-srv/config/routes.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::get('/favicon.ico', function () {\n    return '';\n});\n"
  },
  {
    "path": "user-srv/migrations/2022_06_08_072031_create_user_table.php",
    "content": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration;\n\nclass CreateUserTable extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('user', function (Blueprint $table) {\n            $table->bigIncrements('id');\n\n            $table->string('user_name', 50)->nullable()->comment('用户名');\n            $table->string('user_image', 255)->nullable()->comment('头像');\n            $table->string('phone', 30)->nullable()->comment('手机号');\n            $table->tinyInteger('sex')->default(0)->comment('性别,1男，2女，0未知');\n\n            $table->integer('create_time')->default(0)->comment('创建时间');\n            $table->integer('update_time')->default(0)->comment('更新时间');\n\n            $table->comment('用户表');\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('user');\n    }\n}\n"
  },
  {
    "path": "user-srv/migrations/2022_06_08_072120_create_user_bonus_log_table.php",
    "content": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration;\n\nclass CreateUserBonusLogTable extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('user_bonus_log', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->integer('user_id')->default(0)->comment('用户id');\n            $table->tinyInteger('type')->default(0)->comment('积分类型 -1减去积分 1 增加积分');\n            $table->integer('bonus')->default(0)->comment('积分值');\n            $table->string('source',50)->nullable()->comment('来源: order订单 admin_change后台调整');\n            $table->string('remark',50)->nullable()->comment('备注');\n\n            $table->integer('create_time')->default(0)->comment('创建时间');\n            $table->integer('update_time')->default(0)->comment('更新时间');\n\n            $table->comment('用户积分表');\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('user_bonus_log');\n    }\n}\n"
  },
  {
    "path": "user-srv/migrations/2022_06_08_072134_create_user_stored_log_table.php",
    "content": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration;\n\nclass CreateUserStoredLogTable extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('user_stored_log', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->integer('user_id')->default(0)->comment('用户id');\n            $table->tinyInteger('type')->default(0)->comment('积分类型 -1减去储值 1 增加储值');\n            $table->decimal('amount',10,2)->default(0)->comment('金额');\n            $table->string('source',50)->nullable()->comment('来源: pay充值 order订单 admin_change后台调整');\n            $table->string('remark',50)->nullable()->comment('备注');\n\n            $table->integer('create_time')->default(0)->comment('创建时间');\n            $table->integer('update_time')->default(0)->comment('更新时间');\n\n            $table->comment('用户储值表');\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('user_stored_log');\n    }\n}\n"
  },
  {
    "path": "user-srv/seeders/user_bonus_log_seeder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass UserBonusLogSeeder extends Seeder\n{\n    /**\n     * Run the database seeds.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        for ($i = 0;$i <20;$i++){\n            \\Hyperf\\DbConnection\\Db::table('user_bonus_log')->insert([\n                'user_id' => 1,\n                'type' => 1,\n                'bonus' => mt_rand(1,10),\n                'source' => 1,\n                'remark' => 'order',\n                'create_time' =>time(),\n                'update_time' =>time(),\n            ]);\n        }\n\n    }\n}\n"
  },
  {
    "path": "user-srv/seeders/user_seeder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass UserSeeder extends Seeder\n{\n    /**\n     * Run the database seeds.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        \\Hyperf\\DbConnection\\Db::table('user')->insert([\n            'user_name' => 'DoubleJin',\n            'user_image' => 'http://thirdwx.qlogo.cn/mmopen/Px0DzaTpW96d5vicVMbA6hkjic31msWnF1gU1yicrfNsmkxd1UT8N4vlTV6UArXQm1cBo3AB9I74dfGIquZ21SuJRLCuA5fIia7v/132',\n            'phone' => '1358888888',\n            'sex' => 1,\n            'create_time' =>time(),\n            'update_time' =>time(),\n        ]);\n    }\n}\n"
  },
  {
    "path": "user-srv/seeders/user_stored_log_seeder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass UserStoredLogSeeder extends Seeder\n{\n    /**\n     * Run the database seeds.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        for ($i = 0;$i <20;$i++){\n            \\Hyperf\\DbConnection\\Db::table('user_stored_log')->insert([\n                'user_id' => 1,\n                'type' => 1,\n                'amount' => mt_rand(1,10),\n                'source' => 1,\n                'remark' => 'pay',\n                'create_time' =>time(),\n                'update_time' =>time(),\n            ]);\n        }\n    }\n}\n"
  },
  {
    "path": "user-srv/test/Cases/ExampleTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversNothing\n */\nclass ExampleTest extends HttpTestCase\n{\n    public function testExample()\n    {\n        $this->assertTrue(true);\n        $this->assertTrue(is_array($this->get('/')));\n    }\n}\n"
  },
  {
    "path": "user-srv/test/HttpTestCase.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Class HttpTestCase.\n * @method get($uri, $data = [], $headers = [])\n * @method post($uri, $data = [], $headers = [])\n * @method json($uri, $data = [], $headers = [])\n * @method file($uri, $data = [], $headers = [])\n * @method request($method, $path, $options = [])\n */\nabstract class HttpTestCase extends TestCase\n{\n    /**\n     * @var Client\n     */\n    protected $client;\n\n    public function __construct($name = null, array $data = [], $dataName = '')\n    {\n        parent::__construct($name, $data, $dataName);\n        $this->client = make(Client::class);\n    }\n\n    public function __call($name, $arguments)\n    {\n        return $this->client->{$name}(...$arguments);\n    }\n}\n"
  },
  {
    "path": "user-srv/test/bootstrap.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_reporting(E_ALL);\ndate_default_timezone_set('Asia/Shanghai');\n\n! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));\n! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);\n\nSwoole\\Runtime::enableCoroutine(true);\n\nrequire BASE_PATH . '/vendor/autoload.php';\n\nHyperf\\Di\\ClassLoader::init();\n\n$container = require BASE_PATH . '/config/container.php';\n\n$container->get(Hyperf\\Contract\\ApplicationInterface::class);\n"
  }
]