Full Code of Double-Jin/jin-microservices for AI

main 15c02c8d0bb6 cached
264 files
240.1 KB
74.0k tokens
323 symbols
1 requests
Download .txt
Showing preview only (308K chars total). Download the full file or copy to clipboard to get everything.
Repository: Double-Jin/jin-microservices
Branch: main
Commit: 15c02c8d0bb6
Files: 264
Total size: 240.1 KB

Directory structure:
gitextract_8s8otvkg/

├── .gitignore
├── LICENSE
├── README-CN.md
├── README.md
├── api-gateway/
│   ├── app/
│   │   ├── Constants/
│   │   │   ├── ErrorCode.php
│   │   │   └── ResponseCode.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   ├── AuthController.php
│   │   │   ├── CircuitBreakerController.php
│   │   │   ├── CommonController.php
│   │   │   ├── ConfigController.php
│   │   │   ├── FileController.php
│   │   │   ├── OrderController.php
│   │   │   ├── RateLimitController.php
│   │   │   └── UserController.php
│   │   ├── Exception/
│   │   │   ├── BusinessException.php
│   │   │   ├── Handler/
│   │   │   │   ├── AppExceptionHandler.php
│   │   │   │   ├── AppServiceExceptionHandler.php
│   │   │   │   └── RateLimitExceptionHandler.php
│   │   │   └── ServiceException.php
│   │   ├── JsonRpc/
│   │   │   ├── FileRpcServiceInterface.php
│   │   │   ├── OrderRpcServiceInterface.php
│   │   │   └── UserRpcServiceInterface.php
│   │   ├── Kernel/
│   │   │   └── Functions.php
│   │   ├── Listener/
│   │   │   ├── DbQueryExecutedListener.php
│   │   │   └── QueueHandleListener.php
│   │   ├── Log.php
│   │   ├── Middleware/
│   │   │   └── UserAuthMiddleware.php
│   │   ├── Model/
│   │   │   └── Model.php
│   │   ├── Process/
│   │   │   └── AsyncQueueConsumer.php
│   │   └── Services/
│   │       ├── AuthService.php
│   │       ├── FileService.php
│   │       ├── OrderService.php
│   │       └── UserService.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── async_queue.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── exceptions.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── rate_limit.php
│   │   │   ├── redis.php
│   │   │   ├── server.php
│   │   │   ├── services.php
│   │   │   ├── tracer.php
│   │   │   └── watcher.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
├── doc/
│   ├── DEPLOY_ONE.md
│   └── DEPLOY_TWO.md
├── docker-compose.yaml
├── file-srv/
│   ├── .github/
│   │   └── workflows/
│   │       ├── Dockerfile
│   │       ├── build.yml
│   │       └── release.yml
│   ├── .gitignore
│   ├── .watcher.php
│   ├── app/
│   │   ├── Constants/
│   │   │   └── ErrorCode.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   └── IndexController.php
│   │   ├── Exception/
│   │   │   ├── BusinessException.php
│   │   │   ├── Handler/
│   │   │   │   └── AppExceptionHandler.php
│   │   │   └── JsonRpcException.php
│   │   ├── JsonRpc/
│   │   │   ├── FileRpcService.php
│   │   │   └── FileRpcServiceInterface.php
│   │   ├── Listener/
│   │   │   ├── DbQueryExecutedListener.php
│   │   │   └── ResumeExitCoordinatorListener.php
│   │   ├── Log.php
│   │   ├── Model/
│   │   │   └── Model.php
│   │   └── Services/
│   │       └── FileService.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── exceptions.php
│   │   │   ├── file.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── redis.php
│   │   │   ├── server.php
│   │   │   └── services.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   ├── public/
│   │   └── uploads/
│   │       └── Pp7jmGorNbHecq50.xlsx
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
├── order-srv/
│   ├── app/
│   │   ├── Amqp/
│   │   │   └── Producer/
│   │   │       └── OrderProducer.php
│   │   ├── Constants/
│   │   │   ├── ErrorCode.php
│   │   │   └── ResponseCode.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   └── SagaController.php
│   │   ├── Exception/
│   │   │   ├── Handler/
│   │   │   │   ├── DtmExceptionHandler.php
│   │   │   │   └── JsonRpcExceptionHandler.php
│   │   │   ├── JsonRpcException.php
│   │   │   └── ServiceException.php
│   │   ├── JsonRpc/
│   │   │   ├── OrderRpcService.php
│   │   │   ├── OrderRpcServiceInterface.php
│   │   │   └── UserRpcServiceInterface.php
│   │   ├── Kernel/
│   │   │   └── Functions.php
│   │   ├── Listener/
│   │   │   └── DbQueryExecutedListener.php
│   │   ├── Log.php
│   │   ├── Model/
│   │   │   ├── Order.php
│   │   │   └── OrderGoods.php
│   │   └── Services/
│   │       └── OrderService.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── amqp.php
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── dtm.php
│   │   │   ├── exceptions.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── redis.php
│   │   │   ├── server.php
│   │   │   ├── services.php
│   │   │   ├── tracer.php
│   │   │   └── watcher.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   ├── migrations/
│   │   ├── 2022_06_08_061612_create_order_table.php
│   │   └── 2022_06_08_063020_create_order_goods_table.php
│   ├── seeders/
│   │   ├── order_goods_seeder.php
│   │   └── order_seeder.php
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
├── task-srv/
│   ├── .github/
│   │   └── workflows/
│   │       ├── Dockerfile
│   │       ├── build.yml
│   │       └── release.yml
│   ├── .gitignore
│   ├── app/
│   │   ├── Amqp/
│   │   │   └── Consumer/
│   │   │       ├── OrderConsumer.php
│   │   │       └── UserConsumer.php
│   │   ├── Command/
│   │   │   └── TestCommand.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   └── IndexController.php
│   │   ├── Exception/
│   │   │   └── Handler/
│   │   │       └── AppExceptionHandler.php
│   │   ├── Listener/
│   │   │   ├── DbQueryExecutedListener.php
│   │   │   └── QueueHandleListener.php
│   │   ├── Log.php
│   │   ├── Model/
│   │   │   └── Model.php
│   │   └── Process/
│   │       └── AsyncQueueConsumer.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── amqp.php
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── async_queue.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── crontab.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── exceptions.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── redis.php
│   │   │   └── server.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
└── user-srv/
    ├── app/
    │   ├── Amqp/
    │   │   └── Producer/
    │   │       └── UserProducer.php
    │   ├── Constants/
    │   │   ├── ErrorCode.php
    │   │   └── ResponseCode.php
    │   ├── Controller/
    │   │   ├── AbstractController.php
    │   │   └── SagaController.php
    │   ├── Exception/
    │   │   ├── Handler/
    │   │   │   ├── DtmExceptionHandler.php
    │   │   │   └── JsonRpcExceptionHandler.php
    │   │   ├── JsonRpcException.php
    │   │   └── ServiceException.php
    │   ├── JsonRpc/
    │   │   ├── UserRpcService.php
    │   │   └── UserRpcServiceInterface.php
    │   ├── Kernel/
    │   │   └── Functions.php
    │   ├── Listener/
    │   │   └── DbQueryExecutedListener.php
    │   ├── Log.php
    │   ├── Model/
    │   │   ├── User.php
    │   │   ├── UserBonusLog.php
    │   │   └── UserStoredLog.php
    │   └── Services/
    │       ├── AuthService.php
    │       └── UserService.php
    ├── bin/
    │   └── hyperf.php
    ├── composer.json
    ├── config/
    │   ├── autoload/
    │   │   ├── amqp.php
    │   │   ├── annotations.php
    │   │   ├── aspects.php
    │   │   ├── auth.php
    │   │   ├── cache.php
    │   │   ├── commands.php
    │   │   ├── config_center.php
    │   │   ├── databases.php
    │   │   ├── dependencies.php
    │   │   ├── devtool.php
    │   │   ├── dtm.php
    │   │   ├── exceptions.php
    │   │   ├── listeners.php
    │   │   ├── logger.php
    │   │   ├── middlewares.php
    │   │   ├── nacos.php
    │   │   ├── opentracing.php
    │   │   ├── processes.php
    │   │   ├── redis.php
    │   │   ├── server.php
    │   │   ├── services.php
    │   │   ├── tracer.php
    │   │   └── watcher.php
    │   ├── config.php
    │   ├── container.php
    │   └── routes.php
    ├── migrations/
    │   ├── 2022_06_08_072031_create_user_table.php
    │   ├── 2022_06_08_072120_create_user_bonus_log_table.php
    │   └── 2022_06_08_072134_create_user_stored_log_table.php
    ├── seeders/
    │   ├── user_bonus_log_seeder.php
    │   ├── user_seeder.php
    │   └── user_stored_log_seeder.php
    └── test/
        ├── Cases/
        │   └── ExampleTest.php
        ├── HttpTestCase.php
        └── bootstrap.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*/.buildpath
*/.settings/
*/.project
*/*.patch
*/.idea/
.idea/
*/.git/
.git/
*/runtime/
*/vendor/
*/.phpintel/
*/.env
*/.DS_Store
*/.phpunit*
*/*.cache
*/watch
*/composer.lock


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Double-Jin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README-CN.md
================================================
[English](./README.md) | [中文]

# 介绍

Jin-microservices是基于 php 语言 + hyperf 微服务 框架的完整微服务demo。

github:https://github.com/Double-Jin/jin-microservices

gitee:https://gitee.com/ljj96/jin-microservices

# 关于 JM

作为php、go双修的开发者, go 语言的微服务体系已经基本掌握,go 语言相关的微服务的文章、开源项目在网上搜索一搜一大堆,这让会 go 语言的开发者能容易地上手并实现微服务,毕竟go语言是除java外最合适做微服务的语言这一。

php语言的优势在于web生态,开发的应用绝大多数为单体应用架构。近年来随着基于 swoole 扩展的 hyperf框架的出现,让php也能开发微服务架构,这里要感谢开源工作者。但用 "php + 微服务 "作为关键词时,搜索出来的文章、开源项目都是一些简单的案例,开发者并不能通过这些简单的案例来了解微服务,这让我有了想写本项目的原始动力。

# 前言

JM 是一款基于 php 语言 + hyperf 微服务 框架编写的完整微服务demo,与网上能找到的单一功能点简单实现的文章不同,JM从实际项目需求出发,力求做到git clone 项目下来后对着文件就能帮你构建微服务完整的知识体系,让你实际用hyperf开发微服务项目时能粘贴复制本项目的代码。

微服务架构并不是比单体架构先进的架构,只是在项目体量、项目开发者人数达到一定量级后的一种选择。切勿盲目鼓吹微服务,在团队开发、运维能力不足的情况下强行推进微服务架构恐怕会适得其反。

下面提到的组件并不是微服务架构才能使用,如elk、nacos、dtm这些,在单体应用里面也有合适的场景用到,取其精华来满足业务上的需要。如在生产上用到这些组件最好选择编译安装或购买云服务

## 功能亮点

* 完整微服务架构
* JsonRpc调用
* JWT认证
* 文件上传
* 统一异常处理
* 服务注册与服务发现
* 消息队列
* 链接追踪
* 配置中心
* 服务限流
* 服务降级
* 分布式日志
* 分布式事务

# 准备
微服务是把单体应用进行分拆后的架构,通过引用第三方组件来解决分拆后带来的问题,安装部署这些组件的时候你将会遇到很多奇奇怪怪的问题。为减低难度,本项目大部分组件采用docker来安装,整体流程我已在不同的电脑上验证数遍,即便如此还是会存在如composer、github、http/tcp访问、端口、内存、docker版本等问题,同样的操作换了台电脑就可能出问题,这需要你跟据报错内容查找相关资料自行解决。

- 8核16G电脑
- 熟悉docker
- 了解网络协议
- 基本的运维能力

# 安装

- docker安装
  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_ONE.md)
  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_ONE.md)
- docker-compose安装
  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_TWO.md)
  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_TWO.md)

# 使用

* 目录结构
  ```
    |-- api-gateway //网关服务项目代码 
    |-- order-srv //订单服务项目代码
    |-- fIle-srv //文件服务项目代码
    |-- user-srv // 用户服务项目代码
    |-- task-srv // 定时任务、队列消费服务项目代码
    |-- doc // 文档目录
    |-- README.md //英文说明
    |-- README-CN.md //中文说明
  ```

* 完整微服务架构
  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/zfxnraiUJx.png!large)

* JsonRpc调用
  - `GET http://127.0.0.1:9501/User/UserInfo` 通讯单一服务
  - `GET http://127.0.0.1:9501/User/UserBonusList` 通讯单一服务
  - `GET http://127.0.0.1:9501/User/UserStoredList` 通讯单一服务
  - `GET http://127.0.0.1:9501/Order/OrderList` 通讯多个服务

* JWT认证
  - `GET http://127.0.0.1:9501/Auth/Login` 用户登录
  - `GET http://127.0.0.1:9501/Auth/Logout
    Authorization : 	Bearer {{token}}` 用户退出登录


* 文件上传
  - 微服务中rpc是轻量级通信框架,擅长传输字符串。对于文本文件传输不太友好,
  而对于文件如果强行都成String,就会是一堆乱码。因此,大致的解决思路是,不管文件类型,统统转化成二进制,再将二进制进行Base64编码成String,传输编码后的String到RPC服务,RPC服务按照Base64解码还原成二进制,通过二进制构造File对象即可。
  - `POST http://127.0.0.1:9501/File/UploadFile` 文件转为base64字符串通过json-rpc传输
  - `file-srv.app.JsonRpc.FileRpcService.uploadFile` 通过json-rpc接收base64字符串生成文件


* 统一异常处理
  - 封装AppServiceExceptionHandler.php 统一处理http请求异常
  - 封装RateLimitExceptionHandler.php 统一处理限流异常
  - 封装JsonRpcExceptionHandler.php 统一处理JsonPrc通讯异常
  - 封装DtmExceptionHandler.php 统一处理DTM事务中间件异常

* 服务注册与服务发现
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/03VknWhiB6.png!large)

* 消息队列
  - `GET http://127.0.0.1:9501/User/UserRabbitMQ` 调用投递用户消息队列接口
  - `GET http://127.0.0.1:9501/Order/OrderRabbitMQ` 调用投递订单消息队列接口
  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/0BU5P5RHTL.jpeg!large)
  
* 链接追踪
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/PaiIwXUVrr.png!large)

* 配置中心
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/SfiKibJ55r.png!large)
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/K4Zf5zlBhq.png!large)

* 服务限流
  `GET http://127.0.0.1:9501/RateLimit/Test`
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/QpZmGG31WD.png!large)

* 服务降级
  `GET http://127.0.0.1:9501/CircuitBreaker/Test`
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/bpVBwAgOKl.png!large)

* 分布式日志
  
  当系统变为集群后,应用日志在数十台甚至是上百台不同的服务器上,能实现日志的统一查找、分析和归档等功能便可称为分布式日志系统。
  
  生产上方案会有很多,如将日志直接输出来Elasticsearch,如使用云服务商提供的日志收集。本案例采用的是通过filebeat将日志同步到ELK中。
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/qFqXMfcYu2.png!large)


* 分布式事务
  
  数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。但对分布式系统来说,数据的操作来自多个不同的数据库,单个数据库事务的成功或失败不代表整个系统的数据一致性是对的,只能够通过分布式事务来解决。
  
  分布式事务就是指事务的发起者、资源及资源管理器和事务协调者分别位于分布式系统的不同节点之上。行业上常用的有二阶段提交、SAGA、TCC等方案,当了解原理后,你自行用http/tcp也能实现二阶段提交、SAGA、TCC。
  
  下面的接口通过DTM调度实现在一个SAGA案例。
  `POST http://127.0.0.1:9501/Order/CreateOrder` 分布式事务
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/7tiJcnKiXi.png!large)
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/a5v6AdYVT2.png!large)
  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/txAseIwfVr.png!large)
  
# 不足
* 不支持gRpc的服务注册与服务发现
* 配置中心组件只支持config调用,无法做到env的动态写入与框架重启,但可通过k8s实现


# 感谢
- hyperf:https://hyperf.wiki/2.2/#/README
- dtm:https://en.dtm.pub/
- nacos:https://nacos.io/zh-cn/docs/what-is-nacos.html
- elk:https://www.elastic.co/cn/what-is/elk-stack 

================================================
FILE: README.md
================================================
English | [中文](./README-CN.md)

# Introduction

Jin microservices is a complete microservice demo based on PHP language + hyperf microservices framework

github:https://github.com/Double-Jin/jin-microservices

gitee:https://gitee.com/ljj96/jin-microservices

# About JM

As 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.

The 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.

# Foreword

JM 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.

The 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.

The 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

## Feature

* Complete microservice architecture
* JsonRpc call
* Jwt authority authentication
* Upload the file
* Unified exception handling
* Service Registration and Service Discovery
* Message queue
* Link tracking
* Configuration Center
* Service current limit
* Service downgrade
* Distributed log
* Distributed transaction

# Prepare
Microservices 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.

- 8 core 16G computer
- familiar with docker
- Learn about network protocols
- Basic operation and maintenance capabilities

# Install

- docker install
  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_ONE.md)
  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_ONE.md)
- docker-compose install
  - [github](https://github.com/Double-Jin/jin-microservices/blob/main/doc/DEPLOY_TWO.md)
  - [gitee](https://gitee.com/ljj96/jin-microservices/blob/main/doc/DEPLOY_TWO.md)

# Use

* Directory Structure
  ```
    |-- api-gateway //Gateway service project code 
    |-- order-srv //Order service project code
    |-- user-srv // User service project code
    |-- task-srv // Timed task and queue service project code
    |-- doc // Documentation directory
    |-- README.md //English description
    |-- README-CN.md //Chinese description
  ```

* Complete microservice architecture
  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/zfxnraiUJx.png!large)

* JsonRpc call
  - `GET http://127.0.0.1:9501/User/UserInfo` Communication single service
  - `GET http://127.0.0.1:9501/User/UserBonusList` Communication single service
  - `GET http://127.0.0.1:9501/User/UserStoredList` Communication single service
  - `GET http://127.0.0.1:9501/Order/OrderList` Communication multiple services

* Jwt authority authentication
  - `GET http://127.0.0.1:9501/Auth/Login` User login
  - `GET http://127.0.0.1:9501/Auth/Logout
    Authorization : 	Bearer {{token}}` User logged out


* Upload the file
  - RPC in microservices is a lightweight communication framework that is good at transporting strings. Not very friendly for text file transfers,
    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, 
  - 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.
  - `POST http://127.0.0.1:9501/File/UploadFile` The file is converted to a base64 string and transferred via json-rpc
  - `file-srv.app.JsonRpc.FileRpcService.uploadFile` Generate a file by receiving a base64 string via json-rpc


* Unified exception handling
  - Encapsulate AppServiceExceptionHandler.php http request exceptions
  - Encapsulate RateLimitExceptionHandler.php current limiting exceptions
  - Encapsulate JsonRpcExceptionHandler.php JsonPrc exceptions
  - Encapsulate DtmExceptionHandler.php DTM Distributed transaction exceptions

* Service Registration and Service Discovery
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/03VknWhiB6.png!large)

* Message queue
  - `GET http://127.0.0.1:9501/User/UserRabbitMQ` Call the delivery user message queue interface
  - `GET http://127.0.0.1:9501/Order/OrderRabbitMQ` Call the delivery order message queue interface
  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/0BU5P5RHTL.jpeg!large)
  
* Link tracking
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/PaiIwXUVrr.png!large)

* Configuration Center
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/SfiKibJ55r.png!large)
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/K4Zf5zlBhq.png!large)

* Service current limit
  `GET http://127.0.0.1:9501/RateLimit/Test`
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/QpZmGG31WD.png!large)

* Service downgrade
  `GET http://127.0.0.1:9501/CircuitBreaker/Test`
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/bpVBwAgOKl.png!large)

* Distributed log

  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.

  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.
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/qFqXMfcYu2.png!large)


* Distributed transaction

  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.

  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.

  The following interface is implemented in a SAGA case via DTM scheduling.
  
  `POST http://127.0.0.1:9501/Order/CreateOrder` Distributed transaction
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/7tiJcnKiXi.png!large)
  ![带你走进微服务](https://cdn.learnku.com/uploads/images/202205/31/36324/a5v6AdYVT2.png!large)
  ![完整的php微服务案例](https://cdn.learnku.com/uploads/images/202206/15/36324/txAseIwfVr.png!large)
  
# Question
* Service registration and service discovery without gRpc support
* 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

# Thank
- hyperf:https://hyperf.wiki/2.2/#/README
- dtm:https://en.dtm.pub/
- nacos:https://nacos.io/zh-cn/docs/what-is-nacos.html
- elk:https://www.elastic.co/cn/what-is/elk-stack 

================================================
FILE: api-gateway/app/Constants/ErrorCode.php
================================================
<?php

declare(strict_types=1);

namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

/**
 * @Constants
 */
class ErrorCode extends AbstractConstants
{
    /**
     * @Message("Server Error!")
     */
    const SERVER_ERROR = 500;
}


================================================
FILE: api-gateway/app/Constants/ResponseCode.php
================================================
<?php


namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

/**
 * @Constants
 */
class ResponseCode extends AbstractConstants
{
    /**
     * @Message("请求错误");
     */
    const ERROR = 0;

    /**
     * @Message("成功");
     */
    const SUCCESS = 200;

    /**
     * @Message("创建成功");
     */
    const CREATE_ED = 201;

    /**
     * 请求成功但服务器未处理,响应中包含指示信息
     * @Message("请求成功");
     */
    const ACCEPT_ED = 202;

    /**
     * 请求成功,但是没有响应内容
     * @Message("请求成功");
     */
    const NO_CONTENT = 204;

    /**
     * 请求成功,缓存生效
     * @Message("NO_TMODIFIED");
     */
    const NO_TMODIFIED = 302;

    /**
     * 请求错误,无法解析请求体
     * @Message("请求错误");
     */
    const BAD_REQUEST = 400;

    /**
     * 认证失败
     * @Message("请登录");
     */
    const UNAUTHORIZED = 401;

    /**
     * 服务器已经接受到请求,但拒绝执行
     * @Message("FORBIDDEN");
     */
    const FORBIDDEN = 403;

    /**
     * 找不到请求的资源
     * @Message("找不到请求的资源");
     */
    const  NOT_FOUND = 404;

    /**
     * 方法不允许当前用户访问
     * @Message("METHOD_NOT_ALLOWED");
     */
    const  METHOD_NOT_ALLOWED = 405;

    /**
     * 请求资源已过期
     * @Message("GONE");
     */
    const  GONE = 410;

    /**
     * 请求体内的类型错误
     * @Message("MEDIA_TYPE");
     */
    const  MEDIA_TYPE = 405;

    /**
     * 验证失败
     * @Message("验证失败");
     */
    const  UNPROCESSABLE = 422;


    /**
     * 请求频繁
     * @Message("请求频繁");
     */
    const  MAX_REQUEST = 429;

    /**
     * RPC调用失败
     * @Message("RPC调用失败");
     */
    const  RPC_ERROR = 430;

}

================================================
FILE: api-gateway/app/Controller/AbstractController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;

abstract class AbstractController
{
    #[Inject]
    protected ContainerInterface $container;

    #[Inject]
    protected RequestInterface $request;

    #[Inject]
    protected ResponseInterface $response;
}


================================================
FILE: api-gateway/app/Controller/AuthController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Middleware\UserAuthMiddleware;
use App\Services\AuthService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Contract\RequestInterface;

/**
 * 用户权限控制器
 * Class UserController
 * @package App\Controller
 */
#[Controller(prefix: '/Auth')]
class AuthController extends CommonController
{
    /**
     * 注入AuthService
     * @var AuthService
     */
    #[Inject]
    protected AuthService $authService;

    /**
     * 用户登录
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'Login')]
    public function Login(RequestInterface $request)
    {
        //调用authService.getRpcUserLogin
        $res = $this->authService->getRpcUserLogin('1358888888');

        return $this->success($res);
    }

    /**
     * 用户退出
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'Logout')]
    #[Middleware(UserAuthMiddleware::class)]
    public function Logout(RequestInterface $request)
    {
        //调用authService.getRpcUserLogout
        $res = $this->authService->getRpcUserLogout(getBearerToken($request->header('Authorization')));

        return $this->success($res);
    }
}


================================================
FILE: api-gateway/app/Controller/CircuitBreakerController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Services\UserService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\CircuitBreaker\Annotation\CircuitBreaker;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;

/**
 * 服务降级控制器
 * Class CircuitBreakerController
 * @package App\Controller
 */
#[Controller(prefix: '/CircuitBreaker')]
class CircuitBreakerController extends CommonController
{

    /**
     * 注入UserService
     * @var UserService
     */
    #[Inject]
    protected UserService $userService;

    /**
     * 测试服务降级
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'Test')]
    #[CircuitBreaker(options:["timeout"=>0.05],failCounter:1, successCounter:1, fallback:"App\Controller\CircuitBreakerController::circuitBreakerFallback")]
    public function test()
    {
        $this->userService->testCircuitBreaker();

        return $this->success('这是服务降级');
    }

    /**
     * 服务降级异常返回方法
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function circuitBreakerFallback()
    {
        return $this->success('服务降级啦~');
    }

}


================================================
FILE: api-gateway/app/Controller/CommonController.php
================================================
<?php

namespace App\Controller;

/**
 * 通用控制器
 * Class CommonController
 * @package App\Controller
 */
class CommonController extends AbstractController
{
    public function success($data = [])
    {
        return $this->response->json(responseSuccess(200, '', $data));
    }

}

================================================
FILE: api-gateway/app/Controller/ConfigController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Contract\RequestInterface;

/**
 * 配置控制器
 * Class ConfigController
 * @package App\Controller
 */
#[Controller(prefix: '/Config')]
class ConfigController extends CommonController
{

    /**
     * 测试配置中心数据获取
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'Test')]
    public function test(RequestInterface $request)
    {
        //获取nacos中的配置
        $config = config('nacos_config');

        return $this->success($config);
    }

}


================================================
FILE: api-gateway/app/Controller/FileController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Services\FileService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\HttpServer\Contract\RequestInterface;

/**
 * 文件控制器
 * Class FileController
 * @package App\Controller
 */
#[Controller(prefix: '/File')]
class FileController extends CommonController
{
    /**
     * 注入FileService
     * @var FileService
     */
    #[Inject]
    protected FileService $fileService;

    /**
     * 上传文件
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[PostMapping(path: 'UploadFile')]
    public function uploadFile(RequestInterface $request)
    {
        $res = $this->fileService->getRpcUploadFile($request->file('file'));

        return $this->success($res);
    }

}


================================================
FILE: api-gateway/app/Controller/OrderController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Services\OrderService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\HttpServer\Contract\RequestInterface;

/**
 * 订单控制器
 * Class OrderController
 * @package App\Controller
 */
#[Controller(prefix: '/Order')]
class OrderController extends CommonController
{
    /**
     * 注入OrderService
     * @var OrderService
     */
    #[Inject]
    protected OrderService $orderService;

    /**
     * 用户订单列表
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'OrderList')]
    public function orderList(RequestInterface $request)
    {
        //调用orderService.getRpcOrderList方法
        $res = $this->orderService->getRpcOrderList(1);

        return $this->success($res);
    }

    /**
     * 创建订单
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[PostMapping(path: 'CreateOrder')]
    public function createOrder(RequestInterface $request)
    {
        //调用orderService.rpcCreateOrder方法
        $res = $this->orderService->rpcCreateOrder([
            'user_id' => 1,
            'coupon_id' => 0,
            'order_money' => '100',
            'order_discount' => '100',
            'order_fact_money' => '100',
            'consume_number' => 1,
            'payment' => 1,
            'goods' => [
                [
                    'goods_id' => 1,
                    'goods_sn' => 'JIN02',
                    'sku_id' => 1,
                    'user_id' => 1,
                    'goods_name' => '测试商品',
                    'number' => 1,
                    'goods_tag_price' => '100',
                    'goods_real_price' => '100',
                    'goods_discount' => '100',
                    'goods_fact_money' => '100'
                ]
            ]
        ]);

        return $this->success($res);
    }

    /**
     * 投递订单消息到RabbitMQ
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'OrderRabbitMQ')]
    public function orderRabbitMQ(RequestInterface $request)
    {
        //调用orderService.getRpcUserStoredList方法
        $res = $this->orderService->getRpcOrderRabbitMQ();

        return $this->success($res);
    }
}


================================================
FILE: api-gateway/app/Controller/RateLimitController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\RateLimit\Annotation\RateLimit;

/**
 * 限流控制器
 * Class RateLimitController
 * @package App\Controller
 */
#[Controller(prefix: '/RateLimit')]
class RateLimitController extends CommonController
{

    /**
     * 测试限流
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'Test')]
    #[RateLimit(create:1,consume:1, capacity:1,waitTimeout:1)]
    public function test()
    {
        return $this->success('这是测试限流');
    }

}


================================================
FILE: api-gateway/app/Controller/UserController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Services\UserService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Contract\RequestInterface;

/**
 * 用户控制器
 * Class UserController
 * @package App\Controller
 */
#[Controller(prefix: '/User')]
class UserController extends CommonController
{
    /**
     * 注入UserService
     * @var UserService
     */
    #[Inject]
    protected UserService $userService;

    /**
     * 用户信息
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'UserInfo')]
    public function userInfo(RequestInterface $request)
    {
        //调用userService.getRpcUserInfo方法
        $res = $this->userService->getRpcUserInfo(1);

        return $this->success($res);
    }

    /**
     * 用户积分列表
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'UserBonusList')]
    public function userBonusList(RequestInterface $request)
    {
        //调用userService.getRpcUserBonusList方法
        $res = $this->userService->getRpcUserBonusList(1,15);

        return $this->success($res);
    }

    /**
     * 用户储值列表
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'UserStoredList')]
    public function userStoredList(RequestInterface $request)
    {
        //调用userService.getRpcUserStoredList方法
        $res = $this->userService->getRpcUserStoredList(1,15);

        return $this->success($res);
    }

    /**
     * 投递用户消息到RabbitMQ
     * @param RequestInterface $request
     * @return \Psr\Http\Message\ResponseInterface
     */
    #[GetMapping(path: 'UserRabbitMQ')]
    public function userRabbitMQ(RequestInterface $request)
    {
        //调用userService.getRpcUserStoredList方法
        $res = $this->userService->getRpcUserRabbitMQ();

        return $this->success($res);
    }
}


================================================
FILE: api-gateway/app/Exception/BusinessException.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;

class BusinessException extends ServerException
{
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}


================================================
FILE: api-gateway/app/Exception/Handler/AppExceptionHandler.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception\Handler;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class AppExceptionHandler extends ExceptionHandler
{
    /**
     * @var StdoutLoggerInterface
     */
    protected $logger;

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}


================================================
FILE: api-gateway/app/Exception/Handler/AppServiceExceptionHandler.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Exception\ServiceException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

/**
 * app异常处理
 * Class AppServiceExceptionHandler
 * @package App\Exception\Handler
 */
class AppServiceExceptionHandler extends ExceptionHandler
{
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        if ($throwable instanceof ServiceException) {

            //阻止异常冒泡
            $this->stopPropagation();

            //返回自定义错误数据
            $result = responseError($throwable->getCode(), $throwable->getMessage());

            return $response->withStatus($throwable->getCode())
                ->withAddedHeader('content-type', 'application/json')
                ->withBody(new SwooleStream(json_encode($result, JSON_UNESCAPED_UNICODE)));
        }

        // 交给下一个异常处理器
        return $response;
    }

    /**
     *
     * @param Throwable $throwable 抛出的异常
     * @return bool 该异常处理器是否处理该异常
     */
    public function isValid(Throwable $throwable): bool
    {
        //当前的异常是否属于业务异常
        return true;
    }
}

================================================
FILE: api-gateway/app/Exception/Handler/RateLimitExceptionHandler.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Exception\ServiceException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\RateLimit\Exception\RateLimitException;
use Psr\Http\Message\ResponseInterface;
use Throwable;

/**
 * 限流器异常处理
 * Class RateLimitExceptionHandler
 * @package App\Exception\Handler
 */
class RateLimitExceptionHandler extends ExceptionHandler
{
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        if ($throwable instanceof RateLimitException) {
            //阻止异常冒泡
            $this->stopPropagation();

            //返回自定义错误数据
            $result = responseError($throwable->getCode(), '您被限流啦');

            return $response->withStatus($throwable->getCode())
                ->withAddedHeader('content-type', 'application/json')
                ->withBody(new SwooleStream(json_encode($result, JSON_UNESCAPED_UNICODE)));
        }

        // 交给下一个异常处理器
        return $response;
    }

    /**
     *
     * @param Throwable $throwable 抛出的异常
     * @return bool 该异常处理器是否处理该异常
     */
    public function isValid(Throwable $throwable): bool
    {
        //当前的异常是否属于业务异常
        return true;
    }
}

================================================
FILE: api-gateway/app/Exception/ServiceException.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception;

use App\Constants\ResponseCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;

class ServiceException extends ServerException
{
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ResponseCode::getMessage($code);
        }
        parent::__construct($message, $code, $previous);
    }
}

================================================
FILE: api-gateway/app/JsonRpc/FileRpcServiceInterface.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/12/20
 * @create: 09:31
 */

namespace App\JsonRpc;

interface FileRpcServiceInterface
{

    public function uploadFile(string $type, string $base64string, string $fileName): array;

}

================================================
FILE: api-gateway/app/JsonRpc/OrderRpcServiceInterface.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:31
 */

namespace App\JsonRpc;

interface OrderRpcServiceInterface
{

    public function orderList(int $userId) : array;

    public function createOrder(array $data) : array;

    public function orderRabbitMQ(): array;

}

================================================
FILE: api-gateway/app/JsonRpc/UserRpcServiceInterface.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:31
 */

namespace App\JsonRpc;

interface UserRpcServiceInterface
{

    public function userInfo(int $userId): array;

    public function userBonusList(int $page, int $pageSize): array;

    public function userStoredList(int $page, int $pageSize): array;

    public function userRabbitMQ(): array;

    public function userLogin(string $phone): array;

    public function userLogout(string $token): array;

    public function userCheckToken(string $token): array;

}

================================================
FILE: api-gateway/app/Kernel/Functions.php
================================================
<?php

declare(strict_types=1);

/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 */

use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Redis\Redis;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;

/**
 * 获取Container
 */
if (!function_exists('di')) {
    /**
     * Finds an entry of the container by its identifier and returns it.
     * @param null|mixed $id
     * @return mixed|\Psr\Container\ContainerInterface
     */
    function di($id = null)
    {
        $container = ApplicationContext::getContainer();
        if ($id) {
            return $container->get($id);
        }
        return $container;
    }
}

/**
 * 控制台日志
 */
if (!function_exists('stdLog')) {
    function stdLog()
    {
        return di()->get(StdoutLoggerInterface::class);
    }
}

/**
 * 文件日志
 */
if (!function_exists('logger')) {
    function logger($name = 'log', $group = 'default')
    {
        return di()->get(LoggerFactory::class)->get($name, $group);
    }
}

/**
 * redis 客户端实例
 */
if (!function_exists('redis')) {
    function redis()
    {
        return di()->get(Redis::class);
    }
}

/**
 * 缓存实例 简单的缓存
 */
if (!function_exists('cache')) {
    function cache()
    {
        return di()->get(\Psr\SimpleCache\CacheInterface::class);
    }
}

if (!function_exists('format_throwable')) {
    /**
     * Format a throwable to string.
     * @param Throwable $throwable
     * @return string
     */
    function format_throwable(Throwable $throwable): string
    {
        return di()->get(FormatterInterface::class)->format($throwable);
    }
}


if (!function_exists('responseSuccess')) {
    function responseSuccess($code, $message = '', $data = [])
    {
        $content = ['code' => $code];
        $message ? $content['msg'] = $message : $content['msg'] = \App\Constants\ResponseCode::getMessage($code);
        $data ? $content['data'] = $data : $content['data'] = [];
        return $content;
    }
}

if (!function_exists('responseError')) {
    function responseError($code, $message = '', $data = [])
    {
        $content = ['code' => $code];
        $message ? $content['msg'] = $message : $content['msg'] = \App\Constants\ResponseCode::getMessage($code);
        $data ? $content['data'] = $data : $content['data'] = [];
        return $content;
    }
}


/**
 * 判读字符串是否为json
 */
if (!function_exists('isJson')) {
    /**
     * Finds an entry of the container by its identifier and returns it.
     * @param string $string
     */
    function isJson($string)
    {
        json_decode($string);
        return (json_last_error() == JSON_ERROR_NONE);
    }
}

/**
 * 容器实例
 */
if (!function_exists('container')) {
    function container()
    {
        return ApplicationContext::getContainer();
    }
}

/**
 * 获取BearerToken
 */
if (!function_exists('getBearerToken')) {
    function getBearerToken($Authorization)
    {
        if (\Hyperf\Utils\Str::startsWith($Authorization, 'Bearer ')) {
            return \Hyperf\Utils\Str::substr($Authorization, 7);
        }

        return null;
    }
}





================================================
FILE: api-gateway/app/Listener/DbQueryExecutedListener.php
================================================
<?php

declare(strict_types=1);

namespace App\Listener;

use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;

/**
 * @Listener
 */
class DbQueryExecutedListener implements ListenerInterface
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(ContainerInterface $container)
    {
        $this->logger = $container->get(LoggerFactory::class)->get('sql');
    }

    public function listen(): array
    {
        return [
            QueryExecuted::class,
        ];
    }

    /**
     * @param QueryExecuted $event
     */
    public function process(object $event) : void
    {
        if ($event instanceof QueryExecuted) {
            $sql = $event->sql;
            if (! Arr::isAssoc($event->bindings)) {
                foreach ($event->bindings as $key => $value) {
                    $sql = Str::replaceFirst('?', "'{$value}'", $sql);
                }
            }

            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));
        }

        return;
    }
}


================================================
FILE: api-gateway/app/Listener/QueueHandleListener.php
================================================
<?php

declare(strict_types=1);

namespace App\Listener;

use Hyperf\AsyncQueue\AnnotationJob;
use Hyperf\AsyncQueue\Event\AfterHandle;
use Hyperf\AsyncQueue\Event\BeforeHandle;
use Hyperf\AsyncQueue\Event\Event;
use Hyperf\AsyncQueue\Event\FailedHandle;
use Hyperf\AsyncQueue\Event\RetryHandle;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
use Hyperf\Logger\LoggerFactory;

/**
 * @Listener
 */
class QueueHandleListener implements ListenerInterface
{
    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * @var FormatterInterface
     */
    protected $formatter;

    public function __construct(LoggerFactory $loggerFactory, FormatterInterface $formatter)
    {
        $this->logger = $loggerFactory->get('queue');
        $this->formatter = $formatter;
    }

    public function listen(): array
    {
        return [
            AfterHandle::class,
            BeforeHandle::class,
            FailedHandle::class,
            RetryHandle::class,
        ];
    }

    public function process(object $event) : void
    {
        if ($event instanceof Event && $event->message->job()) {
            $job = $event->message->job();
            $jobClass = get_class($job);
            if ($job instanceof AnnotationJob) {
                $jobClass = sprintf('Job[%s@%s]', $job->class, $job->method);
            }
            $date = date('Y-m-d H:i:s');

            switch (true) {
                case $event instanceof BeforeHandle:
                    $this->logger->info(sprintf('[%s] Processing %s.', $date, $jobClass));
                    break;
                case $event instanceof AfterHandle:
                    $this->logger->info(sprintf('[%s] Processed %s.', $date, $jobClass));
                    break;
                case $event instanceof FailedHandle:
                    $this->logger->error(sprintf('[%s] Failed %s.', $date, $jobClass));
                    $this->logger->error($this->formatter->format($event->getThrowable()));
                    break;
                case $event instanceof RetryHandle:
                    $this->logger->warning(sprintf('[%s] Retried %s.', $date, $jobClass));
                    break;
            }
        }
    }
}


================================================
FILE: api-gateway/app/Log.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/26
 * @create: 14:54
 */

namespace App;

use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;

class Log
{
    public static function get(string $name = 'app')
    {
        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);
    }
}

================================================
FILE: api-gateway/app/Middleware/UserAuthMiddleware.php
================================================
<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Exception\ServiceException;
use App\Services\AuthService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Throwable;

class UserAuthMiddleware implements MiddlewareInterface
{

    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var RequestInterface
     */
    protected $request;

    /**
     * @var HttpResponse
     */
    protected $response;

    /**
     * 注入AuthService
     * @var AuthService
     */
    #[Inject]
    protected AuthService $authService;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $token = $this->getBearerToken($request);

        if (empty($token)){
            throw new ServiceException(422,'token不存在');
        }

        //调用authService.getRpcUserCheckToken方法
        $this->authService->getRpcUserCheckToken($token);

        return $handler->handle($request);

    }

    public function getBearerToken($request)
    {
        $Authorization = $this->request->header('Authorization');

        return getBearerToken($Authorization);
    }
}

================================================
FILE: api-gateway/app/Model/Model.php
================================================
<?php

declare (strict_types=1);

namespace App\Model;

use Hyperf\DbConnection\Model\Model as BaseModel;
use Hyperf\ModelCache\Cacheable;
use Hyperf\ModelCache\CacheableInterface;
abstract class Model extends BaseModel implements CacheableInterface
{
    use Cacheable;
}

================================================
FILE: api-gateway/app/Process/AsyncQueueConsumer.php
================================================
<?php

declare(strict_types=1);

namespace App\Process;

use Hyperf\AsyncQueue\Process\ConsumerProcess;
use Hyperf\Process\Annotation\Process;

/**
 * @Process
 */
class AsyncQueueConsumer extends ConsumerProcess
{
}


================================================
FILE: api-gateway/app/Services/AuthService.php
================================================
<?php


namespace App\Services;

use App\Exception\ServiceException;
use App\JsonRpc\UserRpcServiceInterface;
use App\Log;
use Hyperf\Di\Annotation\Inject;
use Swoole\Coroutine;

/**
 * 用户权限service
 * Class AuthService
 * @package App\Services
 */
class AuthService
{

    /**
     * 注入UserRpcServiceInterface
     * @var UserRpcServiceInterface
     */
    #[Inject]
    protected UserRpcServiceInterface $userRpcServiceInterface;

    /**
     * 用户登录
     * @param int $page
     * @param int $pageSize
     * @return mixed
     */
    public function getRpcUserLogin(string $phone)
    {
        Log::get()->info("调用getRpcUserLogin");

        try {
            //调用用户服务中的用户登录方法
            $res = $this->userRpcServiceInterface->userLogin($phone);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 用户退出
     * @param string $token
     * @return mixed
     */
    public function getRpcUserLogout(string $token)
    {
        Log::get()->info("调用getRpcUserLogout");

        try {
            //调用用户服务中的用户退出方法
            $res = $this->userRpcServiceInterface->userLogout($token);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 检查用户token
     * @param string $token
     * @return mixed
     */
    public function getRpcUserCheckToken(string $token)
    {
        Log::get()->info("调用getRpcUserLogout");

        try {
            //调用用户服务中的检查用户token方法
            $res = $this->userRpcServiceInterface->userCheckToken($token);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430,'token已过期');
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430,'token已过期');
        }

        return $res['data'];
    }

}

================================================
FILE: api-gateway/app/Services/FileService.php
================================================
<?php


namespace App\Services;

use App\Exception\ServiceException;
use App\JsonRpc\FileRpcServiceInterface;
use App\Log;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Str;

/**
 * 文件service
 * Class UserService
 * @package App\Services
 */
class FileService
{

    /**
     * 注入FileRpcServiceInterface
     * @var FileRpcServiceInterface
     */
    #[Inject]
    protected FileRpcServiceInterface $fileRpcServiceInterface;

    /**
     * 上传文件
     * @param $file
     * @return mixed
     */
    public function getRpcUploadFile($file)
    {
        Log::get()->info("调用uploadFile");

        $type =$file->getExtension(); //获取文件类型

        $fileData = file_get_contents($file->getRealPath()); //获取文件二进制流

        $base64String = 'data:' . $type . ';base64,' . chunk_split(base64_encode($fileData));

        $fileName = Str::random(16) . '.' . $type;

        try {
            //调用文件服务中的文件上传方法
            $res = $this->fileRpcServiceInterface->uploadFile($type,$base64String,$fileName);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];

    }

}

================================================
FILE: api-gateway/app/Services/OrderService.php
================================================
<?php


namespace App\Services;

use App\Exception\ServiceException;
use App\JsonRpc\OrderRpcServiceInterface;
use App\Log;
use Hyperf\Di\Annotation\Inject;

/**
 * 订单service
 * Class OrderService
 * @package App\Services
 */
class OrderService
{

    /**
     * 注入OrderRpcServiceInterface
     * @var OrderRpcServiceInterface
     */
    #[Inject]
    protected OrderRpcServiceInterface $orderRpcServiceInterface;

    /**
     * 订单列表
     * @param $userId
     * @return mixed
     */
    public function getRpcOrderList(int $userId)
    {
        Log::get()->info("调用getRpcOrderList");

        try {
            //调用订单服务中的订单列表方法
            $res = $this->orderRpcServiceInterface->orderList($userId);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 创建列表
     * @param $data
     * @return mixed
     */
    public function rpcCreateOrder(array $data)
    {
        Log::get()->info("调用rpcCreateOrder");

        try {
            //调用订单服务中的创建订单方法
            $res = $this->orderRpcServiceInterface->createOrder($data);

        } catch (\Throwable $ex) {

            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 投递用户消息到RabbitMQ
     * @return mixed
     */
    public function getRpcOrderRabbitMQ()
    {
        Log::get()->info("调用getRpcUserRabbitMQ");

        try {
            //调用订单服务中的投递订单消息到RabbitMQ方法
            $res = $this->orderRpcServiceInterface->orderRabbitMQ();

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

}

================================================
FILE: api-gateway/app/Services/UserService.php
================================================
<?php


namespace App\Services;

use App\Exception\ServiceException;
use App\JsonRpc\UserRpcServiceInterface;
use App\Log;
use Hyperf\Di\Annotation\Inject;
use Swoole\Coroutine;

/**
 * 用户service
 * Class UserService
 * @package App\Services
 */
class UserService
{

    /**
     * 注入UserRpcServiceInterface
     * @var UserRpcServiceInterface
     */
    #[Inject]
    protected UserRpcServiceInterface $userRpcServiceInterface;

    /**
     * 用户信息
     * @param $userId
     * @return mixed
     */
    public function getRpcUserInfo($userId)
    {
        Log::get()->info("调用getRpcUserInfo");

        try {

            //调用用户服务中的用户详情方法
            $res = $this->userRpcServiceInterface->userInfo($userId);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 用户积分列表
     * @param int $page
     * @param int $pageSize
     * @return mixed
     */
    public function getRpcUserBonusList(int $page, int $pageSize)
    {
        Log::get()->info("调用getRpcUserBonusList");

        try {
            //调用用户服务中的用户积分列表方法
            $res = $this->userRpcServiceInterface->userBonusList($page, $pageSize);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 用户储值列表
     * @param int $page
     * @param int $pageSize
     * @return mixed
     */
    public function getRpcUserStoredList(int $page, int $pageSize)
    {
        Log::get()->info("调用getRpcUserStoredList");

        try {
            //调用用户服务中的用户储值列表方法
            $res = $this->userRpcServiceInterface->userStoredList($page, $pageSize);

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

    /**
     * 测试服务降级
     */
    public function testCircuitBreaker()
    {

        Log::get()->info("调用testCircuitBreaker");

        Coroutine::sleep(2);
    }

    /**
     * 投递用户消息到RabbitMQ
     * @param int $page
     * @param int $pageSize
     * @return mixed
     */
    public function getRpcUserRabbitMQ()
    {
        Log::get()->info("调用getRpcUserRabbitMQ");

        try {
            //调用用户服务中的投递用户消息到RabbitMQ方法
            $res = $this->userRpcServiceInterface->userRabbitMQ();

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败", [
                'code' => $ex->getCode(),
                'file' => $ex->getFile(),
                'message' => $ex->getMessage(),
            ]);

            throw new ServiceException(430);
        }

        if ($res['code'] !== 200) {
            Log::get()->info("rpc调用失败", [
                'code' => $res['code'],
                'file' => '',
                'message' => $res['message']
            ]);

            throw new ServiceException(430);
        }

        return $res['data'];
    }

}

================================================
FILE: api-gateway/bin/hyperf.php
================================================
#!/usr/bin/env php
<?php

ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');
ini_set('memory_limit', '1G');

error_reporting(E_ALL);

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

require BASE_PATH . '/vendor/autoload.php';

// Self-called anonymous function that creates its own scope and keep the global namespace clean.
(function () {
    Hyperf\Di\ClassLoader::init();
    /** @var Psr\Container\ContainerInterface $container */
    $container = require BASE_PATH . '/config/container.php';

    $application = $container->get(Hyperf\Contract\ApplicationInterface::class);
    $application->run();
})();


================================================
FILE: api-gateway/composer.json
================================================
{
    "name": "hyperf/hyperf-skeleton",
    "type": "project",
    "keywords": [
        "php",
        "swoole",
        "framework",
        "hyperf",
        "microservice",
        "middleware"
    ],
    "description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.",
    "license": "Apache-2.0",
    "require": {
        "php": ">=8.0",
        "hyperf/async-queue": "3.0.*",
        "hyperf/cache": "3.0.*",
        "hyperf/circuit-breaker": "3.0.*",
        "hyperf/code-generator": "^0.3.3",
        "hyperf/command": "3.0.*",
        "hyperf/config": "3.0.*",
        "hyperf/config-nacos": "3.0.*",
        "hyperf/constants": "3.0.*",
        "hyperf/database": "3.0.*",
        "hyperf/db-connection": "3.0.*",
        "hyperf/framework": "3.0.*",
        "hyperf/guzzle": "3.0.*",
        "hyperf/http-server": "3.0.*",
        "hyperf/json-rpc": "3.0.*",
        "hyperf/logger": "3.0.*",
        "hyperf/memory": "3.0.*",
        "hyperf/model-cache": "3.0.*",
        "hyperf/process": "3.0.*",
        "hyperf/rate-limit": "3.0.*",
        "hyperf/redis": "3.0.*",
        "hyperf/rpc": "3.0.*",
        "hyperf/rpc-client": "3.0.*",
        "hyperf/rpc-server": "3.0.*",
        "hyperf/service-governance": "3.0.*",
        "hyperf/service-governance-nacos": "3.0.*",
        "hyperf/tracer": "3.0.*"
    },
    "require-dev": {
        "friendsofphp/php-cs-fixer": "^3.0",
        "hyperf/devtool": "3.0.*",
        "hyperf/ide-helper": "3.0.*",
        "hyperf/testing": "3.0.*",
        "hyperf/watcher": "3.0.*",
        "mockery/mockery": "^1.0",
        "phpstan/phpstan": "^0.12",
        "swoole/ide-helper": "^4.5"
    },
    "suggest": {
        "ext-openssl": "Required to use HTTPS.",
        "ext-json": "Required to use JSON.",
        "ext-pdo": "Required to use MySQL Client.",
        "ext-pdo_mysql": "Required to use MySQL Client.",
        "ext-redis": "Required to use Redis Client."
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/Kernel/Functions.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "HyperfTest\\": "./test/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "optimize-autoloader": true,
        "sort-packages": true
    },
    "extra": [],
    "scripts": {
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-autoload-dump": [
            "rm -rf runtime/container"
        ],
        "test": "co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always",
        "cs-fix": "php-cs-fixer fix $1",
        "analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config",
        "start": [
            "Composer\\Config::disableProcessTimeout",
            "php ./bin/hyperf.php start"
        ]
    }
}


================================================
FILE: api-gateway/config/autoload/annotations.php
================================================
<?php

declare(strict_types=1);

return [
    'scan' => [
        'paths' => [
            BASE_PATH . '/app',
        ],
        'ignore_annotations' => [
            'mixin',
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/aspects.php
================================================
<?php

declare(strict_types=1);

return [
    Hyperf\Tracer\Aspect\JsonRpcAspect::class,
];


================================================
FILE: api-gateway/config/autoload/async_queue.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'driver' => Hyperf\AsyncQueue\Driver\RedisDriver::class,
        'redis' => [
            'pool' => 'default',
        ],
        'channel' => '{queue}',
        'timeout' => 2,
        'retry_seconds' => 5,
        'handle_timeout' => 10,
        'processes' => 1,
        'concurrent' => [
            'limit' => 10,
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/cache.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'driver' => Hyperf\Cache\Driver\RedisDriver::class,
        'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
        'prefix' => 'c:',
    ],
];


================================================
FILE: api-gateway/config/autoload/commands.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: api-gateway/config/autoload/config_center.php
================================================
<?php

declare(strict_types=1);

use Hyperf\ConfigCenter\Mode;

return [
    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),
    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),
    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),
    'drivers' => [
        'nacos' => [
            'driver' => Hyperf\ConfigNacos\NacosDriver::class,
            'merge_mode' => Hyperf\ConfigNacos\Constants::CONFIG_MERGE_OVERWRITE,
            'interval' => 3,
            'default_key' => 'nacos_config',
            'listener_config' => [
                // dataId, group, tenant, type, content
                'nacos_config' => [
                    // 命名空间/ID
                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId
                    // DataID
                    'data_id' => env('NACOS_DATA_ID'),
                    // 组名
                    'group' => 'DEFAULT_GROUP',
                    'type' => 'json',
                ],
            ],
            'client' => [
                // 客户端
                'host' => env('NACOS_HOST'),
                'port' => env('NACOS_PORT'),
                'username' => env('NACOS_USERNAME'),
                'password' => env('NACOS_PASSWORD'),
                'guzzle' => [
                    'config' => null,
                ],
            ],
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/databases.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'driver' => env('DB_DRIVER', 'mysql'),
        'host' => env('DB_HOST', 'localhost'),
        'port' => env('DB_PORT', 3306),
        'database' => env('DB_DATABASE', 'hyperf'),
        'username' => env('DB_USERNAME', 'root'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => env('DB_CHARSET', 'utf8mb4'),
        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
        'prefix' => env('DB_PREFIX', ''),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
        ],
        'cache' => [
            'handler' => Hyperf\ModelCache\Handler\RedisHandler::class,
            'cache_key' => '{mc:%s:m:%s}:%s:%s',
            'prefix' => 'default',
            'ttl' => 3600 * 24,
            'empty_model_ttl' => 600,
            'load_script' => true,
        ],
        'commands' => [
            'gen:model' => [
                'path' => 'app/Model',
                'force_casts' => true,
                'inheritance' => 'Model',
                'uses' => '',
                'table_mapping' => [],
            ],
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/dependencies.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: api-gateway/config/autoload/devtool.php
================================================
<?php

declare(strict_types=1);

return [
    'generator' => [
        'amqp' => [
            'consumer' => [
                'namespace' => 'App\\Amqp\\Consumer',
            ],
            'producer' => [
                'namespace' => 'App\\Amqp\\Producer',
            ],
        ],
        'aspect' => [
            'namespace' => 'App\\Aspect',
        ],
        'command' => [
            'namespace' => 'App\\Command',
        ],
        'controller' => [
            'namespace' => 'App\\Controller',
        ],
        'job' => [
            'namespace' => 'App\\Job',
        ],
        'listener' => [
            'namespace' => 'App\\Listener',
        ],
        'middleware' => [
            'namespace' => 'App\\Middleware',
        ],
        'Process' => [
            'namespace' => 'App\\Processes',
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/exceptions.php
================================================
<?php

declare(strict_types=1);

return [
    'handler' => [
        'http' => [
            Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
            App\Exception\Handler\AppExceptionHandler::class,
            App\Exception\Handler\AppServiceExceptionHandler::class,
            App\Exception\Handler\RateLimitExceptionHandler::class,
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/listeners.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: api-gateway/config/autoload/logger.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'handler' => [
            'class' => Monolog\Handler\RotatingFileHandler::class,
            'constructor' => [
                'filename' => BASE_PATH . '/runtime/logs/hyperf.log',
                'level' => Monolog\Logger::DEBUG,
            ],
        ],
        'formatter' => [
            'class' => Monolog\Formatter\LineFormatter::class,
            'constructor' => [
                'format' => null,
                'dateFormat' => 'Y-m-d H:i:s',
                'allowInlineLineBreaks' => true,
            ],
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/middlewares.php
================================================
<?php

declare(strict_types=1);

return [
    'http' => [
        \Hyperf\Tracer\Middleware\TraceMiddleware::class,
//        \App\Exception\Handler\AppServiceExceptionHandler::class,
    ],
    'jsonrpc-http' => [
        \Hyperf\Tracer\Middleware\TraceMiddleware::class,
    ],
];


================================================
FILE: api-gateway/config/autoload/nacos.php
================================================
<?php

declare(strict_types=1);

return [
    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port
    // 'url' => '',
    // The nacos host info
    'host' => env('NACOS_HOST'),
    'port' => env('NACOS_PORT'),
    // The nacos account info
    'username' => env('NACOS_USERNAME'),
    'password' => env('NACOS_PASSWORD'),
    'guzzle' => [
        'config' => null,
    ],
];


================================================
FILE: api-gateway/config/autoload/opentracing.php
================================================
<?php

declare(strict_types=1);

use Zipkin\Samplers\BinarySampler;

return [
    'default' => env('TRACER_DRIVER', 'zipkin'),
    'enable' => [
        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),
        'redis' => env('TRACER_ENABLE_REDIS', false),
        'db' => env('TRACER_ENABLE_DB', false),
        'method' => env('TRACER_ENABLE_METHOD', false),
    ],
    'tracer' => [
        'zipkin' => [
            'driver' => \Hyperf\Tracer\Adapter\ZipkinTracerFactory::class,
            'app' => [
                'name' => env('APP_NAME', 'skeleton'),
                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null
                'ipv4' => '127.0.0.1',
                'ipv6' => null,
                'port' => 9501,
            ],
            'options' => [
                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),
                'timeout' => env('ZIPKIN_TIMEOUT', 1),
            ],
            'sampler' => BinarySampler::createAsAlwaysSample(),
        ],
        'jaeger' => [
            'driver' => \Hyperf\Tracer\Adapter\JaegerTracerFactory::class,
            'name' => env('APP_NAME', 'skeleton'),
            'options' => [
                'local_agent' => [
                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),
                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),
                ],
            ],
        ],
    ],
    'tags' => [
        // HTTP 客户端 (Guzzle)
        'http_client' => [
            'http.url' => 'http.url',
            'http.method' => 'http.method',
            'http.status_code' => 'http.status_code',
        ],
        // Redis 客户端
        'redis' => [
            'arguments' => 'arguments',
            'result' => 'result',
        ],
        // 数据库客户端 (hyperf/database)
        'db' => [
            'db.query' => 'db.query',
            'db.statement' => 'db.statement',
            'db.query_time' => 'db.query_time',
        ],
    ]
];


================================================
FILE: api-gateway/config/autoload/processes.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: api-gateway/config/autoload/rate_limit.php
================================================
<?php

declare(strict_types=1);

return [
    'create' => 1,
    'consume' => 1,
    'capacity' => 1,
    'limitCallback' => [],
    'waitTimeout' => 1,
];


================================================
FILE: api-gateway/config/autoload/redis.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'host' => env('REDIS_HOST', 'localhost'),
        'auth' => env('REDIS_AUTH', null),
        'port' => (int) env('REDIS_PORT', 6379),
        'db' => (int) env('REDIS_DB', 0),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
        ],
    ],
];


================================================
FILE: api-gateway/config/autoload/server.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Server\Event;
use Hyperf\Server\Server;
use Swoole\Constant;

return [
    'mode' => SWOOLE_PROCESS,
    'servers' => [
        [
            'name' => 'http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9501,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
            ],
        ],
    ],
    'settings' => [
        Constant::OPTION_ENABLE_COROUTINE => true,
        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),
        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',
        Constant::OPTION_OPEN_TCP_NODELAY => true,
        Constant::OPTION_MAX_COROUTINE => 100000,
        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,
        Constant::OPTION_MAX_REQUEST => 100000,
        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,
        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,
    ],
    'callbacks' => [
        Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
        Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
        Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
    ],
];


================================================
FILE: api-gateway/config/autoload/services.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:35
 */

// 这个是nacos服务的端口和地址
$registry = [
    'protocol' => 'nacos',
    'address' => 'http://'.env('NACOS_HOST').':'.env('NACOS_PORT'),
];

// 这里配置需要用的rpc服务
$services = [
    [
        'name' => 'OrderRpcService',
        'service' => \App\JsonRpc\OrderRpcServiceInterface::class
    ],
    [
        'name' => 'UserRpcService',
        'service' => \App\JsonRpc\UserRpcServiceInterface::class
    ],
    [
        'name' => 'FileRpcService',
        'service' => \App\JsonRpc\FileRpcServiceInterface::class
    ]
];

return [
    'enable' => [
        // 开启服务发现
        'discovery' => true,
        // 开启服务注册
        'register' => true,
    ],
    // 服务消费者相关配置
    'consumers' => value(function () use ($services, $registry) {
        // 循环生成rpc消费端
        $consumers = [];
        foreach ($services as $value) {
            $consumers[] = [
                'name' => $value['name'],
                'service' => $value['service'],
                'registry' => $registry
            ];
        }
        return $consumers;
    }),
    // 服务提供者相关配置
    'providers' => [],
    // 服务驱动相关配置
    'drivers' => [
        // nacos 配置,当前使用
        'nacos' => [
            // The nacos host info
            'host' => env('NACOS_HOST'),
            'port' => env('NACOS_PORT'),
            // nacos 账号密码信息
            'username' => env('NACOS_USERNAME'),
            'password' => env('NACOS_PASSWORD'),
            'guzzle' => [
                'config' => null,
            ],
            // 命名空间,public为默认系统空间
            'group_name' => 'api',
            // 命名空间ID
             'namespace_id' => env('NACOS_TENANT'),
            // 心跳检查秒数
            'heartbeat' => 5,
            'ephemeral' => true, // 是否注册临时实例
        ],
    ],
];

================================================
FILE: api-gateway/config/autoload/tracer.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/25
 * @create: 11:29
 */

return [
    // 选择默认的 Tracer
    'default' => env('TRACER_DRIVER', 'jaeger'),

    // 这里的代码演示不对 enable 内的配置进行展开
    'enable' => [],

    'tracer' => [
        // Zipkin 驱动配置
        'zipkin' => [
            // 当前应用的配置
            'app' => [
                'name' => env('APP_NAME', 'skeleton'),
                // 如果 ipv6 和 ipv6 为空组件会自动从 Server 中检测
                'ipv4' => '127.0.0.1',
                'ipv6' => null,
                'port' => 9501,
            ],
            'driver' => \Hyperf\Tracer\Adapter\ZipkinTracerFactory::class,
            'options' => [
                // Zipkin 服务的 endpoint 地址
                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),
                // 请求超时秒数
                'timeout' => env('ZIPKIN_TIMEOUT', 1),
            ],
            // 采样器,默认为所有请求的都追踪
            'sampler' => \Zipkin\Samplers\BinarySampler::createAsAlwaysSample(),
        ],
    ],
];

================================================
FILE: api-gateway/config/autoload/watcher.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Watcher\Driver\ScanFileDriver;

return [
    'driver' => ScanFileDriver::class,
    'bin' => 'php',
    'watch' => [
        'dir' => ['app', 'config'],
        'file' => ['.env'],
        'scan_interval' => 2000,
    ],
];


================================================
FILE: api-gateway/config/config.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Contract\StdoutLoggerInterface;
use Psr\Log\LogLevel;

return [
    'app_name' => env('APP_NAME', 'skeleton'),
    'app_env' => env('APP_ENV', 'dev'),
    'scan_cacheable' => env('SCAN_CACHEABLE', false),
    StdoutLoggerInterface::class => [
        'log_level' => [
            LogLevel::ALERT,
            LogLevel::CRITICAL,
//            LogLevel::DEBUG,
            LogLevel::EMERGENCY,
            LogLevel::ERROR,
            LogLevel::INFO,
            LogLevel::NOTICE,
            LogLevel::WARNING,
        ],
    ],
];


================================================
FILE: api-gateway/config/container.php
================================================
<?php
/**
 * Initialize a dependency injection container that implemented PSR-11 and return the container.
 */

declare(strict_types=1);

use Hyperf\Di\Container;
use Hyperf\Di\Definition\DefinitionSourceFactory;
use Hyperf\Utils\ApplicationContext;

$container = new Container((new DefinitionSourceFactory(true))());

if (! $container instanceof \Psr\Container\ContainerInterface) {
    throw new RuntimeException('The dependency injection container is invalid.');
}
return ApplicationContext::setContainer($container);


================================================
FILE: api-gateway/config/routes.php
================================================
<?php

declare(strict_types=1);

use Hyperf\HttpServer\Router\Router;

Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\UserController@userInfo');

Router::get('/favicon.ico', function () {
    return '';
});


================================================
FILE: api-gateway/test/Cases/ExampleTest.php
================================================
<?php

declare(strict_types=1);

namespace HyperfTest\Cases;

use HyperfTest\HttpTestCase;

/**
 * @internal
 * @coversNothing
 */
class ExampleTest extends HttpTestCase
{
    public function testExample()
    {
        $this->assertTrue(true);
        $this->assertTrue(is_array($this->get('/')));
    }
}


================================================
FILE: api-gateway/test/HttpTestCase.php
================================================
<?php

declare(strict_types=1);

namespace HyperfTest;

use Hyperf\Testing\Client;
use PHPUnit\Framework\TestCase;

/**
 * Class HttpTestCase.
 * @method get($uri, $data = [], $headers = [])
 * @method post($uri, $data = [], $headers = [])
 * @method json($uri, $data = [], $headers = [])
 * @method file($uri, $data = [], $headers = [])
 * @method request($method, $path, $options = [])
 */
abstract class HttpTestCase extends TestCase
{
    /**
     * @var Client
     */
    protected $client;

    public function __construct($name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);
        $this->client = make(Client::class);
    }

    public function __call($name, $arguments)
    {
        return $this->client->{$name}(...$arguments);
    }
}


================================================
FILE: api-gateway/test/bootstrap.php
================================================
<?php

declare(strict_types=1);

ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');

error_reporting(E_ALL);
date_default_timezone_set('Asia/Shanghai');

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

Swoole\Runtime::enableCoroutine(true);

require BASE_PATH . '/vendor/autoload.php';

Hyperf\Di\ClassLoader::init();

$container = require BASE_PATH . '/config/container.php';

$container->get(Hyperf\Contract\ApplicationInterface::class);


================================================
FILE: doc/DEPLOY_ONE.md
================================================
# docker安装

Mysql

  ```bash  
  1.安装 - 略
  2.新建order-srv数据库
  3.新建user-srv数据库
```

Redis
 ```bash  
  1.安装 - 略
```

Nacos
 ```bash  
  1.docker run --name nacos-standalone -e MODE=standalone \
  -e JVM_XMS=512m -e JVM_XMN=256m -p 8848:8848 -d
  nacos/nacos-server:v2.1.0
  2.访问http://127.0.0.1:8848/nacos/#/login
  3.用户名密码: nacos/nacos
  4.命名空间->新建命名空间->增加空间 `dev`
  5.配置管理->配置列表->dev->导入配置->/jin-microservices/doc/nacos_config.zip
```

Rabbitmq
 ```bash  
  1.docker run -d  --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3.9.2
  2.docker exec -it rabbit /bin/bash
  3.rabbitmq-plugins enable rabbitmq_management
  4.访问http://127.0.0.1:15672 
  5.用户名密码: guest/guest
```

ELK

 ```bash  
  1.vi /etc/sysctl.conf
    #末尾添加一行
    vm.max_map_count=262144
    #查看结果
    sysctl -p
  2.docker run -p 5601:5601 -p 9200:9200 -p 5044:5044 -itd --name elk sebp/elk:7.17.1
  3.docker exec -it elk bin/bash
  4.cd /etc/logstash/conf.d
  5.vim logstash.conf
		  input {
			  beats {
				port => 5044
				codec => plain { charset => "UTF-8" }
			  }
		  }
			# 格式化日志
		  filter {
			  grok {
				  match => [ "message","\[%{TIMESTAMP_ISO8601:logtime}\] %{WORD:env}\.(?<level>[A-Z]{4,5})\: %{GREEDYDATA:msg}}" ]
				  }
		   }
		   output {
				elasticsearch {
					 action => "index"
					 hosts => ["localhost"]
					 index => "jm-log"
				 }
			}
  6.rm 02-beats-input.conf  10-syslog.conf  11-nginx.conf  30-output.conf
  7.docker restart elk
  8.测试http://127.0.0.1:9200
  9.访问http://127.0.0.1:5601/app/kibana
```

Filebeat
 ```bash 
 1.wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.13.3-linux-x86_64.tar.gz
 2.tar -xvf filebeat-7.13.3-linux-x86_64.tar.gz
 3.vi filebeat.yml
    filebeat.inputs:
      - type: log
        paths:
          - /jin-microservices/*/runtime/logs/*.log
        multiline.pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
        multiline.negate: true
        multiline.match: after
        multiline.timeout: 5s
        scan_frequency: 5s
    output:
      # 输出到logstash中,logstash更换为自己的ip
      logstash:
        hosts: ["127.0.0.1:5044"]
 4. ./filebeat-7.13.3-linux-x86_64/filebeat -e -c filebeat.yml 
 ```

Zipkin

 ```bash  
  1.docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin
  2.访问 http://127.0.0.1:9411/zipkin/ 
```

DTM

 ```bash  
  1.docker run -itd  --name dtm -p 36789:36789 -p 36790:36790  yedf/dtm:1.14
  2.访问http://127.0.0.1:36789
```

项目代码
  ```bash  
 1.docker run --name hyperf \
-v /workspace/skeleton:/data/project \
-p 9501:9501 -p 9502:9502  -p 9503:9503  -it  -p 9507:9507  -it \
--privileged -u root \
--entrypoint /bin/sh \
hyperf/hyperf:8.1-alpine-v3.15-swoole-v5
2.docker exec -it hyperf /bin/bash
3.cd /data/project/
4.git clone https://github.com/Double-Jin/jin-microservices.git
5.cd jin-microservices/api-gateway/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php start
6.cd jin-microservices/user-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php migrate
    php bin/hyperf.php db:seed
    php bin/hyperf.php start
7.cd jin-microservices/order-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php migrate
    php bin/hyperf.php db:seed
    php bin/hyperf.php start
8.cd jin-microservices/task-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php start
9.cd jin-microservices/file-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php start
``` 


================================================
FILE: doc/DEPLOY_TWO.md
================================================
# docker-composer安装

docker-compose

```bash  
 1.vi /etc/sysctl.conf
    #末尾添加一行
    vm.max_map_count=262144
    #查看结果
    sysctl -p
 2.修改docker-composer.services.hyperf.volumes目录映射地址
 3.docker-compose up
 4.docker exec -it rabbit /bin/bash
 5.rabbitmq-plugins enable rabbitmq_management
 6.docker exec -it elk bin/bash
 7.cd /etc/logstash/conf.d
 8.vim logstash.conf
		  input {
			  beats {
				port => 5044
				codec => plain { charset => "UTF-8" }
			  }
		  }
			# 格式化日志
		  filter {
			  grok {
				  match => [ "message","\[%{TIMESTAMP_ISO8601:logtime}\] %{WORD:env}\.(?<level>[A-Z]{4,5})\: %{GREEDYDATA:msg}}" ]
				  }
		   }
		   output {
				elasticsearch {
					 action => "index"
					 hosts => ["localhost"]
					 index => "jm-log"
				 }
			}
 9.rm 02-beats-input.conf  10-syslog.conf  11-nginx.conf  30-output.conf
 10.docker restart elk
 11.连接mysql
 12.新建order-srv数据库
 13.新建user-srv数据库
 14.访问http://127.0.0.1:8848/nacos/#/login
 15.用户名密码: nacos/nacos
 16.命名空间->新建命名空间->增加空间 `dev`
 17.配置管理->配置列表->dev->导入配置->/jin-microservices/doc/nacos_config.zip
```

Filebeat
 ```bash 
 1.wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.13.3-linux-x86_64.tar.gz
 2.tar -xvf filebeat-7.13.3-linux-x86_64.tar.gz
 3.vi filebeat.yml
    filebeat.inputs:
      - type: log
        paths:
          - /jin-microservices/*/runtime/logs/*.log
        multiline.pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
        multiline.negate: true
        multiline.match: after
        multiline.timeout: 5s
        scan_frequency: 5s
    output:
      # 输出到logstash中,logstash更换为自己的ip
      logstash:
        hosts: ["127.0.0.1:5044"]
 4. ./filebeat-7.13.3-linux-x86_64/filebeat -e -c filebeat.yml 
 ```

验证
```bash
 1.访问http://127.0.0.1:8848/nacos/#/login 用户名密码: nacos/nacos
 2.访问http://127.0.0.1:15672 用户名密码: guest/guest
 2.访问http://127.0.0.1:9200
 3.访问http://127.0.0.1:5601/app/kibana
 4.访问http://127.0.0.1:9411/zipkin/ 
 5.访问http://127.0.0.1:36789
```

启动服务
```bash
1.docker exec -it hyperf /bin/bash
2.cd /data/project/
3.git clone https://github.com/Double-Jin/jin-microservices.git
4.cd jin-microservices/api-gateway/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php start
5.cd jin-microservices/user-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php migrate
    php bin/hyperf.php db:seed
    php bin/hyperf.php start
6.cd jin-microservices/order-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php migrate
    php bin/hyperf.php db:seed
    php bin/hyperf.php start
7.cd jin-microservices/task-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php start
8.cd jin-microservices/file-srv/
    composer update
    复制.env.example为.env配置
    php bin/hyperf.php start
```



================================================
FILE: docker-compose.yaml
================================================
version: '3.9'
services:
  hyperf:
    container_name: hyperf
    image: hyperf/hyperf:8.1-alpine-v3.15-swoole-v5
    hostname: hyperf
    restart: always
    privileged: true
    ports:
      - 9501:9501
      - 9502:9502
      - 9503:9503
      - 9507:9507
    volumes:
      - /Users/linjinjin/Documents/dnmp/www:/data/www
    tty: true
    networks:
      - hyperf_networks

  nacos:
    container_name: nacos
    image: nacos/nacos-server:v2.1.0
    environment:
      - MODE=standalone
      - JVM_XMS=512m
      - JVM_XMN=256m
    hostname: nacos
    restart: always
    ports:
      - 8848:8848
    networks:
      - hyperf_networks

  rabbitmq:
    container_name: rabbit
    image: rabbitmq:3.9.2
    hostname: rabbit
    restart: always
    ports:
      - 15672:15672
      - 5672:5672
    networks:
      - hyperf_networks

  redis:
    container_name: redis
    image: redis:7.0
    restart: always
    hostname: redis
    ports:
      - 6379:6379
    networks:
      - hyperf_networks

  elk:
    container_name: elk
    image: sebp/elk:7.17.1
    restart: always
    hostname: elk
    ports:
      - 5601:5601
      - 9200:9200
      - 5044:5044
    networks:
      - hyperf_networks

  dtm:
    image: yedf/dtm:1.14
    container_name: dtm
    hostname: dtm
    restart: always
    ports:
      - "36789:36789"
      - "36790:36790"
    networks:
      - hyperf_networks

  zipkin:
    image: openzipkin/zipkin:2
    container_name: zipkin
    hostname: zipkin
    restart: always
    ports:
      - "9411:9411"
    networks:
      - hyperf_networks

networks:
  hyperf_networks:

================================================
FILE: file-srv/.github/workflows/Dockerfile
================================================
# Default Dockerfile
#
# @link     https://www.hyperf.io
# @document https://hyperf.wiki
# @contact  group@hyperf.io
# @license  https://github.com/hyperf/hyperf/blob/master/LICENSE

FROM hyperf/hyperf:8.0-alpine-v3.16-swoole
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf"

##
# ---------- env settings ----------
##
# --build-arg timezone=Asia/Shanghai
ARG timezone

ENV TIMEZONE=${timezone:-"Asia/Shanghai"} \
    APP_ENV=prod \
    SCAN_CACHEABLE=(true)

# update
RUN set -ex \
    # show php version and extensions
    && php -v \
    && php -m \
    && php --ri swoole \
    #  ---------- some config ----------
    && cd /etc/php* \
    # - config PHP
    && { \
        echo "upload_max_filesize=128M"; \
        echo "post_max_size=128M"; \
        echo "memory_limit=1G"; \
        echo "date.timezone=${TIMEZONE}"; \
    } | tee conf.d/99_overrides.ini \
    # - config timezone
    && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
    && echo "${TIMEZONE}" > /etc/timezone \
    # ---------- clear works ----------
    && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \
    && echo -e "\033[42;37m Build Completed :).\033[0m\n"

WORKDIR /opt/www

# Composer Cache
# COPY ./composer.* /opt/www/
# RUN composer install --no-dev --no-scripts

COPY . /opt/www
RUN print "\n" | composer install -o && php bin/hyperf.php

EXPOSE 9501

ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]


================================================
FILE: file-srv/.github/workflows/build.yml
================================================
name: Build Docker

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Build
        run: cp -rf .github/workflows/Dockerfile . && docker build -t hyperf .


================================================
FILE: file-srv/.github/workflows/release.yml
================================================
on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

name: Release

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false


================================================
FILE: file-srv/.gitignore
================================================
.buildpath
.settings/
.project
*.patch
.idea/
.git/
runtime/
vendor/
.phpintel/
.env
.DS_Store
.phpunit*
*.cache


================================================
FILE: file-srv/.watcher.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
use Hyperf\Watcher\Driver\ScanFileDriver;

return [
    'driver' => ScanFileDriver::class,
    'bin' => 'php',
    'watch' => [
        'dir' => ['app', 'config'],
        'file' => ['.env'],
        'scan_interval' => 2000,
    ],
];


================================================
FILE: file-srv/app/Constants/ErrorCode.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

#[Constants]
class ErrorCode extends AbstractConstants
{
    /**
     * @Message("Server Error!")
     */
    public const SERVER_ERROR = 500;
}


================================================
FILE: file-srv/app/Controller/AbstractController.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Controller;

use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;

abstract class AbstractController
{
    #[Inject]
    protected ContainerInterface $container;

    #[Inject]
    protected RequestInterface $request;

    #[Inject]
    protected ResponseInterface $response;
}


================================================
FILE: file-srv/app/Controller/IndexController.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Controller;

class IndexController extends AbstractController
{
    public function index()
    {
        $user = $this->request->input('user', 'Hyperf');
        $method = $this->request->getMethod();

        return [
            'method' => $method,
            'message' => "Hello {$user}.",
        ];
    }
}


================================================
FILE: file-srv/app/Exception/BusinessException.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;

class BusinessException extends ServerException
{
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}


================================================
FILE: file-srv/app/Exception/Handler/AppExceptionHandler.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Exception\Handler;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class AppExceptionHandler extends ExceptionHandler
{
    public function __construct(protected StdoutLoggerInterface $logger)
    {
    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
        $this->logger->error($throwable->getTraceAsString());
        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}


================================================
FILE: file-srv/app/Exception/JsonRpcException.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;

class JsonRpcException extends ServerException
{
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}


================================================
FILE: file-srv/app/JsonRpc/FileRpcService.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:31
 */

namespace App\JsonRpc;

use App\Services\AuthService;
use App\Services\FileService;
use Hyperf\RpcServer\Annotation\RpcService;
use App\Services\UserService;
use Hyperf\Di\Annotation\Inject;

/**
 * 文件rpc服务
 * Class OrderRpcService
 * @package App\JsonRpc
 */
#[RpcService(name: "FileRpcService", protocol: "jsonrpc-http", server: "jsonrpc-http", publishTo: "nacos")]
class FileRpcService implements FileRpcServiceInterface
{
    #[Inject]
    protected FileService $fileService;

    /**
     * 上传文件
     * @param string $type
     * @param string $base64string
     * @param string $fileName
     * @return array
     */
    public function uploadFile(string $type,string $base64string,string $fileName): array
    {
        return [
            'code' => 200,
            'data' => $this->fileService->uploadFile($type,$base64string,$fileName)
        ];
    }

}

================================================
FILE: file-srv/app/JsonRpc/FileRpcServiceInterface.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/12/20
 * @create: 09:31
 */

namespace App\JsonRpc;

interface FileRpcServiceInterface
{

    public function uploadFile(string $type, string $base64string, string $fileName): array;

}

================================================
FILE: file-srv/app/Listener/DbQueryExecutedListener.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Listener;

use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;

#[Listener]
class DbQueryExecutedListener implements ListenerInterface
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(ContainerInterface $container)
    {
        $this->logger = $container->get(LoggerFactory::class)->get('sql');
    }

    public function listen(): array
    {
        return [
            QueryExecuted::class,
        ];
    }

    /**
     * @param QueryExecuted $event
     */
    public function process(object $event): void
    {
        if ($event instanceof QueryExecuted) {
            $sql = $event->sql;
            if (! Arr::isAssoc($event->bindings)) {
                $position = 0;
                foreach ($event->bindings as $value) {
                    $position = strpos($sql, '?', $position);
                    if ($position === false) {
                        break;
                    }
                    $value = "'{$value}'";
                    $sql = substr_replace($sql, $value, $position, 1);
                    $position += strlen($value);
                }
            }

            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));
        }
    }
}


================================================
FILE: file-srv/app/Listener/ResumeExitCoordinatorListener.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Listener;

use Hyperf\Command\Event\AfterExecute;
use Hyperf\Coordinator\Constants;
use Hyperf\Coordinator\CoordinatorManager;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;

#[Listener]
class ResumeExitCoordinatorListener implements ListenerInterface
{
    public function listen(): array
    {
        return [
            AfterExecute::class,
        ];
    }

    public function process(object $event): void
    {
        CoordinatorManager::until(Constants::WORKER_EXIT)->resume();
    }
}


================================================
FILE: file-srv/app/Log.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/26
 * @create: 14:54
 */

namespace App;

use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;

class Log
{
    public static function get(string $name = 'app')
    {
        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);
    }
}

================================================
FILE: file-srv/app/Model/Model.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Model;

use Hyperf\DbConnection\Model\Model as BaseModel;
use Hyperf\ModelCache\Cacheable;
use Hyperf\ModelCache\CacheableInterface;

abstract class Model extends BaseModel implements CacheableInterface
{
    use Cacheable;
}


================================================
FILE: file-srv/app/Services/FileService.php
================================================
<?php


namespace App\Services;

use App\Exception\JsonRpcException;
use App\Log;

/**
 * 文件service
 * Class UserService
 * @package App\Services
 */
class FileService
{

    /**
     * 上传文件
     * @param $type 文件类型
     * @param $base64string base64数据
     * @param $fileName 文件名
     * @return array|mixed[]
     */
    public function uploadFile(string $type,string $base64string,string $fileName)
    {
        Log::get()->info("调用uploadFile");

        try {

            if (!file_exists(config('file.storage.local.root'))){
                @mkdir(config('file.storage.local.root'), 0755, true);
            }

            $filePath = config('file.storage.local.root').'/'.$fileName;

            //base64转换成文件
            $baseFile = str_replace( 'data:' . $type . ';base64,', '', $base64string);
            $newFile = fopen( $filePath, "wb" );
            fwrite( $newFile, base64_decode( $baseFile) );
            fclose( $newFile );

        } catch (\Throwable $ex) {

            Log::get()->info("rpc调用失败");

            throw new JsonRpcException(430);
        }

        return [
            'file_name' => $fileName,
            'file_path' => $filePath
        ];

    }

}

================================================
FILE: file-srv/bin/hyperf.php
================================================
#!/usr/bin/env php
<?php
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');
ini_set('memory_limit', '1G');

error_reporting(E_ALL);

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

require BASE_PATH . '/vendor/autoload.php';

// Self-called anonymous function that creates its own scope and keep the global namespace clean.
(function () {
    Hyperf\Di\ClassLoader::init();
    /** @var Psr\Container\ContainerInterface $container */
    $container = require BASE_PATH . '/config/container.php';

    $application = $container->get(Hyperf\Contract\ApplicationInterface::class);
    $application->run();
})();


================================================
FILE: file-srv/composer.json
================================================
{
    "name": "hyperf/hyperf-skeleton",
    "type": "project",
    "keywords": [
        "php",
        "swoole",
        "framework",
        "hyperf",
        "microservice",
        "middleware"
    ],
    "description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.",
    "license": "Apache-2.0",
    "require": {
        "php": ">=8.0",
        "hyperf/cache": "3.0.*",
        "hyperf/command": "3.0.*",
        "hyperf/config": "3.0.*",
        "hyperf/config-nacos": "3.0.*",
        "hyperf/constants": "3.0.*",
        "hyperf/database": "3.0.*",
        "hyperf/db-connection": "3.0.*",
        "hyperf/filesystem": "3.0.*",
        "hyperf/framework": "3.0.*",
        "hyperf/guzzle": "3.0.*",
        "hyperf/http-server": "3.0.*",
        "hyperf/json-rpc": "3.0.*",
        "hyperf/logger": "3.0.*",
        "hyperf/memory": "3.0.*",
        "hyperf/model-cache": "3.0.*",
        "hyperf/process": "3.0.*",
        "hyperf/redis": "3.0.*",
        "hyperf/rpc": "3.0.*",
        "hyperf/rpc-client": "3.0.*",
        "hyperf/rpc-server": "3.0.*",
        "hyperf/service-governance": "3.0.*",
        "hyperf/service-governance-nacos": "3.0.*",
        "hyperf/tracer": "3.0.*"
    },
    "require-dev": {
        "friendsofphp/php-cs-fixer": "^3.0",
        "hyperf/devtool": "3.0.*",
        "hyperf/testing": "3.0.*",
        "mockery/mockery": "^1.0",
        "phpstan/phpstan": "^1.0",
        "swoole/ide-helper": "^5.0",
        "hyperf/watcher": "3.0.*"
    },
    "suggest": {
        "ext-openssl": "Required to use HTTPS.",
        "ext-json": "Required to use JSON.",
        "ext-pdo": "Required to use MySQL Client.",
        "ext-pdo_mysql": "Required to use MySQL Client.",
        "ext-redis": "Required to use Redis Client."
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "files": []
    },
    "autoload-dev": {
        "psr-4": {
            "HyperfTest\\": "./test/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "optimize-autoloader": true,
        "sort-packages": true
    },
    "extra": [],
    "scripts": {
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-autoload-dump": [
            "rm -rf runtime/container"
        ],
        "test": "co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always",
        "cs-fix": "php-cs-fixer fix $1",
        "analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config",
        "start": [
            "Composer\\Config::disableProcessTimeout",
            "php ./bin/hyperf.php start"
        ]
    }
}


================================================
FILE: file-srv/config/autoload/annotations.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'scan' => [
        'paths' => [
            BASE_PATH . '/app',
        ],
        'ignore_annotations' => [
            'mixin',
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/aspects.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
];


================================================
FILE: file-srv/config/autoload/cache.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'default' => [
        'driver' => Hyperf\Cache\Driver\RedisDriver::class,
        'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
        'prefix' => 'c:',
    ],
];


================================================
FILE: file-srv/config/autoload/commands.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
];


================================================
FILE: file-srv/config/autoload/config_center.php
================================================
<?php

declare(strict_types=1);

use Hyperf\ConfigCenter\Mode;

return [
    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),
    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),
    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),
    'drivers' => [
        'nacos' => [
            'driver' => Hyperf\ConfigNacos\NacosDriver::class,
            'merge_mode' => Hyperf\ConfigNacos\Constants::CONFIG_MERGE_OVERWRITE,
            'interval' => 3,
            'default_key' => 'nacos_config',
            'listener_config' => [
                // dataId, group, tenant, type, content
                'nacos_config' => [
                    // 命名空间/ID
                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId
                    // DataID
                    'data_id' => env('NACOS_DATA_ID'),
                    // 组名
                    'group' => 'DEFAULT_GROUP',
                    'type' => 'json',
                ],
            ],
            'client' => [
                // 客户端
                'host' => env('NACOS_HOST'),
                'port' => env('NACOS_PORT'),
                'username' => env('NACOS_USERNAME'),
                'password' => env('NACOS_PASSWORD'),
                'guzzle' => [
                    'config' => null,
                ],
            ],
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/databases.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'default' => [
        'driver' => env('DB_DRIVER', 'mysql'),
        'host' => env('DB_HOST', 'localhost'),
        'port' => env('DB_PORT', 3306),
        'database' => env('DB_DATABASE', 'hyperf'),
        'username' => env('DB_USERNAME', 'root'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => env('DB_CHARSET', 'utf8mb4'),
        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
        'prefix' => env('DB_PREFIX', ''),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
        ],
        'cache' => [
            'handler' => Hyperf\ModelCache\Handler\RedisHandler::class,
            'cache_key' => '{mc:%s:m:%s}:%s:%s',
            'prefix' => 'default',
            'ttl' => 3600 * 24,
            'empty_model_ttl' => 600,
            'load_script' => true,
        ],
        'commands' => [
            'gen:model' => [
                'path' => 'app/Model',
                'force_casts' => true,
                'inheritance' => 'Model',
                'uses' => '',
                'table_mapping' => [],
            ],
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/dependencies.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
];


================================================
FILE: file-srv/config/autoload/devtool.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'generator' => [
        'amqp' => [
            'consumer' => [
                'namespace' => 'App\\Amqp\\Consumer',
            ],
            'producer' => [
                'namespace' => 'App\\Amqp\\Producer',
            ],
        ],
        'aspect' => [
            'namespace' => 'App\\Aspect',
        ],
        'command' => [
            'namespace' => 'App\\Command',
        ],
        'controller' => [
            'namespace' => 'App\\Controller',
        ],
        'job' => [
            'namespace' => 'App\\Job',
        ],
        'listener' => [
            'namespace' => 'App\\Listener',
        ],
        'middleware' => [
            'namespace' => 'App\\Middleware',
        ],
        'Process' => [
            'namespace' => 'App\\Processes',
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/exceptions.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'handler' => [
        'http' => [
            Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
            App\Exception\Handler\AppExceptionHandler::class,
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/file.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'default' => 'local',
    'storage' => [
        'local' => [
            'driver' => \Hyperf\Filesystem\Adapter\LocalAdapterFactory::class,
            'root' => __DIR__ . '/../../public/uploads/',
        ],
        'ftp' => [
            'driver' => \Hyperf\Filesystem\Adapter\FtpAdapterFactory::class,
            'host' => 'ftp.example.com',
            'username' => 'username',
            'password' => 'password',
            // 'port' => 21,
            // 'root' => '/path/to/root',
            // 'passive' => true,
            // 'ssl' => true,
            // 'timeout' => 30,
            // 'ignorePassiveAddress' => false,
            // 'timestampsOnUnixListingsEnabled' => true,
        ],
        'memory' => [
            'driver' => \Hyperf\Filesystem\Adapter\MemoryAdapterFactory::class,
        ],
        's3' => [
            'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
            'credentials' => [
                'key' => env('S3_KEY'),
                'secret' => env('S3_SECRET'),
            ],
            'region' => env('S3_REGION'),
            'version' => 'latest',
            'bucket_endpoint' => false,
            'use_path_style_endpoint' => false,
            'endpoint' => env('S3_ENDPOINT'),
            'bucket_name' => env('S3_BUCKET'),
        ],
        'minio' => [
            'driver' => \Hyperf\Filesystem\Adapter\S3AdapterFactory::class,
            'credentials' => [
                'key' => env('S3_KEY'),
                'secret' => env('S3_SECRET'),
            ],
            'region' => env('S3_REGION'),
            'version' => 'latest',
            'bucket_endpoint' => false,
            'use_path_style_endpoint' => true,
            'endpoint' => env('S3_ENDPOINT'),
            'bucket_name' => env('S3_BUCKET'),
        ],
        'oss' => [
            'driver' => \Hyperf\Filesystem\Adapter\AliyunOssAdapterFactory::class,
            'accessId' => env('OSS_ACCESS_ID'),
            'accessSecret' => env('OSS_ACCESS_SECRET'),
            'bucket' => env('OSS_BUCKET'),
            'endpoint' => env('OSS_ENDPOINT'),
            // 'timeout' => 3600,
            // 'connectTimeout' => 10,
            // 'isCName' => false,
            // 'token' => null,
            // 'proxy' => null,
        ],
        'qiniu' => [
            'driver' => \Hyperf\Filesystem\Adapter\QiniuAdapterFactory::class,
            'accessKey' => env('QINIU_ACCESS_KEY'),
            'secretKey' => env('QINIU_SECRET_KEY'),
            'bucket' => env('QINIU_BUCKET'),
            'domain' => env('QINBIU_DOMAIN'),
        ],
        'cos' => [
            'driver' => \Hyperf\Filesystem\Adapter\CosAdapterFactory::class,
            'region' => env('COS_REGION'),
            'app_id' => env('COS_APPID'),
            'secret_id' => env('COS_SECRET_ID'),
            'secret_key' => env('COS_SECRET_KEY'),
            // 可选,如果 bucket 为私有访问请打开此项
            // 'signed_url' => false,
            'bucket' => env('COS_BUCKET'),
            'read_from_cdn' => false,
            // 'timeout' => 60,
            // 'connect_timeout' => 60,
            // 'cdn' => '',
            // 'scheme' => 'https',
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/listeners.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class,
    Hyperf\Command\Listener\FailToHandleListener::class,
];


================================================
FILE: file-srv/config/autoload/logger.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'default' => [
        'handler' => [
            'class' => Monolog\Handler\StreamHandler::class,
            'constructor' => [
                'stream' => BASE_PATH . '/runtime/logs/hyperf.log',
                'level' => Monolog\Logger::DEBUG,
            ],
        ],
        'formatter' => [
            'class' => Monolog\Formatter\LineFormatter::class,
            'constructor' => [
                'format' => null,
                'dateFormat' => 'Y-m-d H:i:s',
                'allowInlineLineBreaks' => true,
            ],
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/middlewares.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'http' => [
    ],
];


================================================
FILE: file-srv/config/autoload/nacos.php
================================================
<?php

declare(strict_types=1);

return [
    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port
    // 'url' => '',
    // The nacos host info
    'host' => env('NACOS_HOST'),
    'port' => env('NACOS_PORT'),
    // The nacos account info
    'username' => env('NACOS_USERNAME'),
    'password' => env('NACOS_PASSWORD'),
    'guzzle' => [
        'config' => null,
    ],
];


================================================
FILE: file-srv/config/autoload/opentracing.php
================================================
<?php

declare(strict_types=1);

use Zipkin\Samplers\BinarySampler;

return [
    'default' => env('TRACER_DRIVER', 'zipkin'),
    'enable' => [
        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),
        'redis' => env('TRACER_ENABLE_REDIS', false),
        'db' => env('TRACER_ENABLE_DB', false),
        'method' => env('TRACER_ENABLE_METHOD', false),
    ],
    'tracer' => [
        'zipkin' => [
            'driver' => \Hyperf\Tracer\Adapter\ZipkinTracerFactory::class,
            'app' => [
                'name' => env('APP_NAME', 'skeleton'),
                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null
                'ipv4' => '127.0.0.1',
                'ipv6' => null,
                'port' => 9501,
            ],
            'options' => [
                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),
                'timeout' => env('ZIPKIN_TIMEOUT', 1),
            ],
            'sampler' => BinarySampler::createAsAlwaysSample(),
        ],
        'jaeger' => [
            'driver' => \Hyperf\Tracer\Adapter\JaegerTracerFactory::class,
            'name' => env('APP_NAME', 'skeleton'),
            'options' => [
                'local_agent' => [
                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),
                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),
                ],
            ],
        ],
    ],
    'tags' => [
        // HTTP 客户端 (Guzzle)
        'http_client' => [
            'http.url' => 'http.url',
            'http.method' => 'http.method',
            'http.status_code' => 'http.status_code',
        ],
        // Redis 客户端
        'redis' => [
            'arguments' => 'arguments',
            'result' => 'result',
        ],
        // 数据库客户端 (hyperf/database)
        'db' => [
            'db.query' => 'db.query',
            'db.statement' => 'db.statement',
            'db.query_time' => 'db.query_time',
        ],
    ]
];


================================================
FILE: file-srv/config/autoload/processes.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
];


================================================
FILE: file-srv/config/autoload/redis.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'default' => [
        'host' => env('REDIS_HOST', 'localhost'),
        'auth' => env('REDIS_AUTH', null),
        'port' => (int) env('REDIS_PORT', 6379),
        'db' => (int) env('REDIS_DB', 0),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
        ],
    ],
];


================================================
FILE: file-srv/config/autoload/server.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
use Hyperf\Server\Event;
use Hyperf\Server\Server;
use Swoole\Constant;

return [
    'mode' => SWOOLE_PROCESS,
    'servers' => [
        [
            'name' => 'jsonrpc-http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9507,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
            ],
            'settings' => [
                'open_length_check' => true,
                'package_length_type' => 'N',
                'package_length_offset' => 0,
                'package_body_offset' => 4,
                'package_max_length' => 1024 * 1024 * 20,
            ],
        ],
    ],
    'settings' => [
        Constant::OPTION_ENABLE_COROUTINE => true,
        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),
        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',
        Constant::OPTION_OPEN_TCP_NODELAY => true,
        Constant::OPTION_MAX_COROUTINE => 100000,
        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,
        Constant::OPTION_MAX_REQUEST => 100000,
        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,
        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,
    ],
    'callbacks' => [
        Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
        Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
        Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
    ],
];


================================================
FILE: file-srv/config/autoload/services.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:35
 */


return [
    'enable' => [
        // 开启服务发现
        'discovery' => true,
        // 开启服务注册
        'register' => true,
    ],
    // 服务消费者相关配置
    'consumers' => [],
    // 服务提供者相关配置
    'providers' => [],
    // 服务驱动相关配置
    'drivers' => [
        // nacos 配置,当前使用
        'nacos' => [
            // The nacos host info
            'host' => env('NACOS_HOST'),
            'port' => env('NACOS_PORT'),
            // nacos 账号密码信息
            'username' => env('NACOS_USERNAME'),
            'password' => env('NACOS_PASSWORD'),
            'guzzle' => [
                'config' => null,
            ],
            // 命名空间,public为默认系统空间
            'group_name' => 'api',
            // 命名空间ID
            'namespace_id' => env('NACOS_TENANT'),
            // 心跳检查秒数
            'heartbeat' => 5,
            'ephemeral' => true, // 是否注册临时实例
        ],
    ],
];

================================================
FILE: file-srv/config/config.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
use Hyperf\Contract\StdoutLoggerInterface;
use Psr\Log\LogLevel;

return [
    'app_name' => env('APP_NAME', 'skeleton'),
    'app_env' => env('APP_ENV', 'dev'),
    'scan_cacheable' => env('SCAN_CACHEABLE', false),
    StdoutLoggerInterface::class => [
        'log_level' => [
            LogLevel::ALERT,
            LogLevel::CRITICAL,
//            LogLevel::DEBUG,
            LogLevel::EMERGENCY,
            LogLevel::ERROR,
            LogLevel::INFO,
            LogLevel::NOTICE,
            LogLevel::WARNING,
        ],
    ],
];


================================================
FILE: file-srv/config/container.php
================================================
<?php
/**
 * Initialize a dependency injection container that implemented PSR-11 and return the container.
 */

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
use Hyperf\Di\Container;
use Hyperf\Di\Definition\DefinitionSourceFactory;
use Hyperf\Utils\ApplicationContext;

$container = new Container((new DefinitionSourceFactory())());

return ApplicationContext::setContainer($container);


================================================
FILE: file-srv/config/routes.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
use Hyperf\HttpServer\Router\Router;

Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');

Router::get('/favicon.ico', function () {
    return '';
});


================================================
FILE: file-srv/test/Cases/ExampleTest.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace HyperfTest\Cases;

use HyperfTest\HttpTestCase;

/**
 * @internal
 * @coversNothing
 */
class ExampleTest extends HttpTestCase
{
    public function testExample()
    {
        $this->assertTrue(true);
        $this->assertTrue(is_array($this->get('/')));
    }
}


================================================
FILE: file-srv/test/HttpTestCase.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace HyperfTest;

use Hyperf\Testing\Client;
use PHPUnit\Framework\TestCase;

/**
 * Class HttpTestCase.
 * @method get($uri, $data = [], $headers = [])
 * @method post($uri, $data = [], $headers = [])
 * @method json($uri, $data = [], $headers = [])
 * @method file($uri, $data = [], $headers = [])
 * @method request($method, $path, $options = [])
 */
abstract class HttpTestCase extends TestCase
{
    /**
     * @var Client
     */
    protected $client;

    public function __construct($name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);
        $this->client = make(Client::class);
    }

    public function __call($name, $arguments)
    {
        return $this->client->{$name}(...$arguments);
    }
}


================================================
FILE: file-srv/test/bootstrap.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');

error_reporting(E_ALL);
date_default_timezone_set('Asia/Shanghai');

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

Swoole\Runtime::enableCoroutine(true);

require BASE_PATH . '/vendor/autoload.php';

Hyperf\Di\ClassLoader::init();

$container = require BASE_PATH . '/config/container.php';

$container->get(Hyperf\Contract\ApplicationInterface::class);


================================================
FILE: order-srv/app/Amqp/Producer/OrderProducer.php
================================================
<?php

declare(strict_types=1);

namespace App\Amqp\Producer;

use Hyperf\Amqp\Annotation\Producer;
use Hyperf\Amqp\Message\ProducerMessage;

/**
 * 订单订阅消息生产者
 * Class OrderProducer
 * @package App\Amqp\Producer
 */
#[Producer(exchange: 'order', routingKey: 'order')]
class OrderProducer extends ProducerMessage
{
    public function __construct($data)
    {
        $this->payload = $data;
    }
}


================================================
FILE: order-srv/app/Constants/ErrorCode.php
================================================
<?php

declare (strict_types=1);

namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

#[Constants]
class ErrorCode extends AbstractConstants
{
    /**
     * @Message("Server Error!")
     */
    const SERVER_ERROR = 500;
}

================================================
FILE: order-srv/app/Constants/ResponseCode.php
================================================
<?php

namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

#[Constants]
class ResponseCode extends AbstractConstants
{
    /**
     * @Message("请求错误");
     */
    const ERROR = 0;
    /**
     * @Message("成功");
     */
    const SUCCESS = 200;
    /**
     * @Message("创建成功");
     */
    const CREATE_ED = 201;
    /**
     * 请求成功但服务器未处理,响应中包含指示信息
     * @Message("请求成功");
     */
    const ACCEPT_ED = 202;
    /**
     * 请求成功,但是没有响应内容
     * @Message("请求成功");
     */
    const NO_CONTENT = 204;
    /**
     * 请求成功,缓存生效
     * @Message("NO_TMODIFIED");
     */
    const NO_TMODIFIED = 302;
    /**
     * 请求错误,无法解析请求体
     * @Message("请求错误");
     */
    const BAD_REQUEST = 400;
    /**
     * 认证失败
     * @Message("请登录");
     */
    const UNAUTHORIZED = 401;
    /**
     * 服务器已经接受到请求,但拒绝执行
     * @Message("FORBIDDEN");
     */
    const FORBIDDEN = 403;
    /**
     * 找不到请求的资源
     * @Message("找不到请求的资源");
     */
    const NOT_FOUND = 404;
    /**
     * 方法不允许当前用户访问
     * @Message("METHOD_NOT_ALLOWED");
     */
    const METHOD_NOT_ALLOWED = 405;
    /**
     * 请求资源已过期
     * @Message("GONE");
     */
    const GONE = 410;
    /**
     * 请求体内的类型错误
     * @Message("MEDIA_TYPE");
     */
    const MEDIA_TYPE = 405;
    /**
     * 验证失败
     * @Message("验证失败");
     */
    const UNPROCESSABLE = 422;
    /**
     * 请求频繁
     * @Message("请求频繁");
     */
    const MAX_REQUEST = 429;
}

================================================
FILE: order-srv/app/Controller/AbstractController.php
================================================
<?php

declare (strict_types=1);

namespace App\Controller;

use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;

abstract class AbstractController
{
    
    #[Inject]
    protected ContainerInterface $container;
    
    #[Inject]
    protected RequestInterface $request;
    
    #[Inject]
    protected ResponseInterface $response;
}

================================================
FILE: order-srv/app/Controller/SagaController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Services\OrderService;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\Di\Annotation\Inject;

/**
 * DTM.SAGA回调控制器
 * Class SagaController
 * @package App\Controller
 */
#[Controller(prefix: '/saga')]
class SagaController extends AbstractController
{
    /**
     * 注入OrderService
     * @var OrderService
     */
    #[Inject]
    protected OrderService $orderService;

    /**
     * 订单创建成功
     * @param RequestInterface $request
     * @return string[]
     */
    #[PostMapping(path: 'sageCreateOrder')]
    public function sageCreateOrder(RequestInterface $request): array
    {
        //调用orderService.sageCreateOrder方法
        $this->orderService->sageCreateOrder($request->all());

        return [
            'dtm_result' => 'SUCCESS',
        ];
    }

    /**
     * 订单创建成功补偿
     * @param RequestInterface $request
     * @return string[]
     */
    #[PostMapping(path: 'sageCreateOrderCompensate')]
    public function sageCreateOrderCompensate(RequestInterface $request): array
    {
        //调用orderService.sageCreateOrderCompensate方法
        $this->orderService->sageCreateOrderCompensate($request->all());

        return [
            'dtm_result' => 'SUCCESS',
        ];
    }

}


================================================
FILE: order-srv/app/Exception/Handler/DtmExceptionHandler.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception\Handler;

use App\Exception\JsonRpcException;
use App\Exception\ServiceException;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Utils\Context;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

/**
 * DTM异常处理
 * Class JsonRpcExceptionHandler
 * @package App\Exception\Handler
 */
class DtmExceptionHandler extends ExceptionHandler
{
    /**
     * @var StdoutLoggerInterface
     */
    protected $logger;

    public function handle(Throwable $throwable, ResponseInterface $response)
    {

        if ($throwable instanceof ServiceException) {

            //阻止异常冒泡
            $this->stopPropagation();

            return $response->withStatus(409);
        }

        // 交给下一个异常处理器
        return $response;
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}


================================================
FILE: order-srv/app/Exception/Handler/JsonRpcExceptionHandler.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception\Handler;

use App\Exception\JsonRpcException;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Context\Context;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

/**
 * jsonRpc异常处理
 * Class JsonRpcExceptionHandler
 * @package App\Exception\Handler
 */
class JsonRpcExceptionHandler extends ExceptionHandler
{
    /**
     * @var StdoutLoggerInterface
     */
    protected $logger;

    public function handle(Throwable $throwable, ResponseInterface $response)
    {

        if ($throwable instanceof JsonRpcException) {


            //阻止异常冒泡
            $this->stopPropagation();

            $request =  Context::get(ServerRequestInterface::class);
            $jsonRpcTreaty = $request->getAttribute('data');
            //返回自定义错误数据
//            return di(ResponseBuilder::class)->buildResponse($request,$response);
            $result = responseError($throwable->getCode(), $throwable->getMessage());

            $jsonRpc = [
                "jsonrpc" => $jsonRpcTreaty['jsonrpc'],
                "id" => $jsonRpcTreaty['id'],
                "result" => $result,
                "context" => ''
            ];

            return $response->withStatus($throwable->getCode())
                ->withAddedHeader('content-type', 'application/json; charset=utf-8')
                ->withBody(new SwooleStream(json_encode($jsonRpc, JSON_UNESCAPED_UNICODE)));
        }

        // 交给下一个异常处理器
        return $response;
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}


================================================
FILE: order-srv/app/Exception/JsonRpcException.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;

class JsonRpcException extends ServerException
{
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}


================================================
FILE: order-srv/app/Exception/ServiceException.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;

class ServiceException extends ServerException
{
    public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}


================================================
FILE: order-srv/app/JsonRpc/OrderRpcService.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:31
 */

namespace App\JsonRpc;

use Hyperf\RpcServer\Annotation\RpcService;
use App\Services\OrderService;
use Hyperf\Di\Annotation\Inject;

/**
 * 订单rpc服务
 * Class OrderRpcService
 * @package App\JsonRpc
 */
#[RpcService(name:"OrderRpcService", protocol:"jsonrpc-http", server:"jsonrpc-http", publishTo:"nacos")]
class OrderRpcService implements OrderRpcServiceInterface
{
    /**
     * 注入OrderService
     * @var OrderService
     */
    #[Inject]
    protected OrderService $orderService;

    /**
     * 订单列表
     * @param int $userId
     * @return array
     */
    public function orderList(int $userId): array
    {
        return [
            'code' => 200,
            'data' => $this->orderService->orderList($userId)
        ];
    }

    /**
     * 创建订单
     * @param array $data
     * @return array
     */
    public function createOrder(array $data): array
    {
        return [
            'code' => 200,
            'data' => $this->orderService->createOrder($data)
        ];
    }

    /**
     * 投递订单消息到RabbitMQ
     * @return array
     */
    public function orderRabbitMQ() : array
    {
        return [
            'code' => 200,
            'data' => $this->orderService->orderRabbitMQ()
        ];
    }
}

================================================
FILE: order-srv/app/JsonRpc/OrderRpcServiceInterface.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:31
 */

namespace App\JsonRpc;

interface OrderRpcServiceInterface
{

    public function orderList(int $userId): array;

    public function createOrder(array $data): array;

    public function orderRabbitMQ(): array;

}

================================================
FILE: order-srv/app/JsonRpc/UserRpcServiceInterface.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:31
 */

namespace App\JsonRpc;

interface UserRpcServiceInterface
{

    public function userInfo(int $userId): array;
    
    public function userBonusList(int $page, int $pageSize): array;

    public function userStoredList(int $page, int $pageSize): array;

    public function userRabbitMQ(): array;

    public function userLogin(string $phone): array;

    public function userLogout(string $token): array;


}

================================================
FILE: order-srv/app/Kernel/Functions.php
================================================
<?php

declare(strict_types=1);

/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 */

use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Redis\Redis;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;

/**
 * 获取Container
 */
if (!function_exists('di')) {
    /**
     * Finds an entry of the container by its identifier and returns it.
     * @param null|mixed $id
     * @return mixed|\Psr\Container\ContainerInterface
     */
    function di($id = null)
    {
        $container = ApplicationContext::getContainer();
        if ($id) {
            return $container->get($id);
        }
        return $container;
    }
}

/**
 * 控制台日志
 */
if (!function_exists('stdLog')) {
    function stdLog()
    {
        return di()->get(StdoutLoggerInterface::class);
    }
}

/**
 * 文件日志
 */
if (!function_exists('logger')) {
    function logger($name = 'log', $group = 'default')
    {
        return di()->get(LoggerFactory::class)->get($name, $group);
    }
}

/**
 * redis 客户端实例
 */
if (!function_exists('redis')) {
    function redis()
    {
        return di()->get(Redis::class);
    }
}

/**
 * 缓存实例 简单的缓存
 */
if (!function_exists('cache')) {
    function cache()
    {
        return di()->get(\Psr\SimpleCache\CacheInterface::class);
    }
}

if (!function_exists('format_throwable')) {
    /**
     * Format a throwable to string.
     * @param Throwable $throwable
     * @return string
     */
    function format_throwable(Throwable $throwable): string
    {
        return di()->get(FormatterInterface::class)->format($throwable);
    }
}


if (!function_exists('responseSuccess')) {
    function responseSuccess($code, $message = '', $data = [])
    {
        $content = ['code' => $code];
        $message ? $content['msg'] = $message : $content['msg'] = \App\Constants\ResponseCode::getMessage($code);
        $data ? $content['data'] = $data : $content['data'] = [];
        return $content;
    }
}

if (!function_exists('responseError')) {
    function responseError($code, $message = '', $data = [])
    {
        $content = ['code' => $code];
        $data ? $content['data'] = $data : $content['data'] = [];
        return $content;
    }
}


/**
 * 判读字符串是否为json
 */
if (!function_exists('isJson')) {
    /**
     * Finds an entry of the container by its identifier and returns it.
     * @param string $string
     */
    function isJson($string)
    {
        json_decode($string);
        return (json_last_error() == JSON_ERROR_NONE);
    }
}


/**
 * 返回jsonRpc结构
 */
if (!function_exists('successJsonRpc')) {
    function successJsonRpc($code, $data)
    {
        return [
            'code' => $code,
            'data' => $data
        ];
    }
}




================================================
FILE: order-srv/app/Listener/DbQueryExecutedListener.php
================================================
<?php

declare (strict_types=1);

namespace App\Listener;

use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;

#[Listener]
class DbQueryExecutedListener implements ListenerInterface
{
    /**
     * @var LoggerInterface
     */
    private $logger;
    
    public function __construct(ContainerInterface $container)
    {
        $this->logger = $container->get(LoggerFactory::class)->get('sql');
    }
    
    public function listen() : array
    {
        return [QueryExecuted::class];
    }
    /**
     * @param QueryExecuted $event
     */
    public function process(object $event) : void
    {
        if ($event instanceof QueryExecuted) {
            $sql = $event->sql;
            if (!Arr::isAssoc($event->bindings)) {
                foreach ($event->bindings as $key => $value) {
                    $sql = Str::replaceFirst('?', "'{$value}'", $sql);
                }
            }
            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));
        }
    }
}

================================================
FILE: order-srv/app/Log.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/26
 * @create: 14:54
 */

namespace App;

use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;

class Log
{
    public static function get(string $name = 'app')
    {
        return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);
    }
}

================================================
FILE: order-srv/app/Model/Order.php
================================================
<?php

declare (strict_types=1);
namespace App\Model;

use Hyperf\DbConnection\Model\Model;
class Order extends Model
{
    const CREATED_AT = 'create_time';
    const UPDATED_AT = 'update_time';

    protected ?string $dateFormat = 'U';
    /**
     * The table associated with the model.
     *
     */
    protected ?string $table = 'order';
    /**
     * The attributes that are mass assignable.
     *
     */
    protected array $fillable = ['order_no', 'user_id', 'coupon_id', 'order_money', 'order_discount', 'order_fact_money', 'consume_number', 'order_status', 'payment'];
    /**
     * The attributes that should be cast to native types.
     *
     */
    protected array $casts = ['id' => 'integer'];

    public function orderGoods()
    {
        return $this->hasMany(OrderGoods::class, 'order_no', 'order_no');
    }
}

================================================
FILE: order-srv/app/Model/OrderGoods.php
================================================
<?php

declare (strict_types=1);
namespace App\Model;

use Hyperf\DbConnection\Model\Model;
class OrderGoods extends Model
{
    const CREATED_AT = 'create_time';
    const UPDATED_AT = 'update_time';

    protected ?string $dateFormat = 'U';
    /**
     * The table associated with the model.
     *
     */
    protected ?string $table = 'order_goods';
    /**
     * The attributes that are mass assignable.
     *
     */
    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'];
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected array $casts = ['id' => 'integer'];
}

================================================
FILE: order-srv/app/Services/OrderService.php
================================================
<?php


namespace App\Services;

use App\Amqp\Producer\OrderProducer;
use App\JsonRpc\UserRpcServiceInterface;
use App\Model\OrderGoods;
use DtmClient\Saga;
use DtmClient\TransContext;
use App\Exception\JsonRpcException;
use App\Exception\ServiceException;
use App\Log;
use App\Model\Order;
use Hyperf\Amqp\Producer;
use Hyperf\Di\Annotation\Inject;

/**
 * 订单service
 * Class OrderService
 * @package App\Services
 */
class OrderService
{
    /**
     * 注入DTM.SAGA
     * @var Saga
     */
    #[Inject]
    protected Saga $saga;

    /**
     * 注入UserRpcServiceInterface
     * @var UserRpcServiceInterface
     */
    #[Inject]
    protected UserRpcServiceInterface $userRpcServiceInterface;

    /**
     * 订单列表
     * @param $userId
     * @return mixed[]
     */
    public function orderList($userId)
    {
        Log::get()->info("调用orderList");

        $list = Order::query()
            ->where('user_id', $userId)
            ->get();

        if (empty($list)) {
            Log::get()->info("订单为空");

            throw new JsonRpcException(10001);
        }

        //调用用户服务拿到用户信息
        foreach ($list as $item) {
            try {
                //调用用户服务中的用户详情方法
                $res = $this->userRpcServiceInterface->userInfo($item->user_id);

            } catch (\Throwable $ex) {
                Log::get()->info("rpc调用失败");

                throw new JsonRpcException(430);
            }

            if ($res['code'] !== 200) {
                Log::get()->info("rpc调用失败");

                throw new JsonRpcException(430);
            }

            //拼装数据
            $item->user = $res['data'];
        }

        return $list->toArray();

    }

    /**
     * 创建订单
     * @param $data
     * @return string
     */
    public function createOrder($data)
    {
        Log::get()->info("调用createOrder");

        try {
            //分布式事务
            $data['order_no'] = date("YmdHis");

            //获取用户储值
            //todo

            //判断商品库存
            //todo

            $this->saga->init();
            //创建订单
            $this->saga->add(
                env('DTM_ORDER_URL') . '/saga/sageCreateOrder',
                env('DTM_ORDER_URL') . '/saga/sageCreateOrderCompensate',
                $data
            );
            //扣用户余额
            $this->saga->add(
                env('DTM_USER_URL') . '/saga/changeStored',
                env('DTM_USER_URL'). '/saga/changeStoredCompensate',
                ['order_no'=>$data['order_no'] ,'user_id'=>$data['user_id'],'amount'=>-$data['order_fact_money']]
            );

            // 提交 Saga 事务
            $this->saga->submit();

        } catch (\Throwable $ex) {
            Log::get()->info("rpc调用失败");

            throw new JsonRpcException(430);
        }

        return TransContext::getGid();

    }

    /**
     * SAGA订单创建成功
     * @param $data
     * @return string
     */
    public function sageCreateOrder($data)
    {
        Log::get()->info("分布式事务-sageCreateOrder",$data);

        //分布式事务
        try {
            Order::create([
                'order_no' => $data['order_no'],
                'user_id' => $data['user_id'],
                'coupon_id' => $data['coupon_id'],
                'order_money' => $data['order_money'],
                'order_discount' => $data['order_fact_money'],
                'consume_number' => $data['consume_number'],
                'order_status' => 0,
                'payment' => $data['payment'],
            ]);

            foreach ($data['goods'] as $item) {
                OrderGoods::create([
                    'order_no' => $data['order_no'],
                    'goods_id' => $item['goods_id'],
                    'goods_sn' => $item['goods_sn'],
                    'sku_id' => $item['sku_id'],
                    'user_id' => $item['user_id'],
                    'goods_name' => $item['goods_name'],
                    'number' => $item['number'],
                    'goods_tag_price' => $item['goods_tag_price'],
                    'goods_real_price' => $item['goods_real_price'],
                    'goods_discount' => $item['goods_fact_money'],
                ]);
            }

        } catch (\Throwable $e) {
            Log::get()->info("分布式事务-sageCreateOrder-调用失败");

            throw new ServiceException();
        }

        return true;
    }


    /**
     * SAGA订单创建补偿
     * @param $data
     * @return string
     */
    public function sageCreateOrderCompensate($data)
    {
        Log::get()->info("分布式事务-sageCreateOrderCompensate",$data);

        //分布式事务
        try {
            Order::query()
                ->where('order_no',$data['order_no'])
                ->where('user_id',$data['user_id'])
                ->delete();

            OrderGoods::query()
                ->where('order_no',$data['order_no'])
                ->where('user_id',$data['user_id'])
                ->delete();

        } catch (\Throwable $e) {
            Log::get()->info("分布式事务-sageCreateOrderCompensate-调用失败");

            throw new ServiceException();
        }

        return true;

    }

    /**
     * 投递订单消息到RabbitMQ
     */
    public function orderRabbitMQ()
    {

        //拼装数据
        $message = new OrderProducer([
            'id' => 1
        ]);

        $producer = di()->get(Producer::class);

        //投递消息
        $result = $producer->produce($message);

        //投递消息失败
        if ($result != true){
            throw new JsonRpcException(430);
        }

    }


}

================================================
FILE: order-srv/bin/hyperf.php
================================================
#!/usr/bin/env php
<?php

ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');
ini_set('memory_limit', '1G');

error_reporting(E_ALL);

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

require BASE_PATH . '/vendor/autoload.php';

// Self-called anonymous function that creates its own scope and keep the global namespace clean.
(function () {
    Hyperf\Di\ClassLoader::init();
    /** @var Psr\Container\ContainerInterface $container */
    $container = require BASE_PATH . '/config/container.php';

    $application = $container->get(Hyperf\Contract\ApplicationInterface::class);
    $application->run();
})();


================================================
FILE: order-srv/composer.json
================================================
{
    "name": "hyperf/hyperf-skeleton",
    "type": "project",
    "keywords": [
        "php",
        "swoole",
        "framework",
        "hyperf",
        "microservice",
        "middleware"
    ],
    "description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.",
    "license": "Apache-2.0",
    "require": {
        "php": ">=8.0",
        "dtm/dtm-client": "^0.3.0",
        "hyperf/amqp": "3.0.*",
        "hyperf/cache": "3.0.*",
        "hyperf/command": "3.0.*",
        "hyperf/config": "3.0.*",
        "hyperf/config-nacos": "3.0.*",
        "hyperf/constants": "3.0.*",
        "hyperf/database": "3.0.*",
        "hyperf/db-connection": "3.0.*",
        "hyperf/framework": "3.0.*",
        "hyperf/guzzle": "3.0.*",
        "hyperf/http-server": "3.0.*",
        "hyperf/json-rpc": "3.0.*",
        "hyperf/logger": "3.0.*",
        "hyperf/memory": "3.0.*",
        "hyperf/model-cache": "3.0.*",
        "hyperf/paginator": "3.0.*",
        "hyperf/process": "3.0.*",
        "hyperf/redis": "3.0.*",
        "hyperf/rpc": "3.0.*",
        "hyperf/rpc-client": "3.0.*",
        "hyperf/rpc-server": "3.0.*",
        "hyperf/service-governance": "3.0.*",
        "hyperf/service-governance-nacos": "3.0.*",
        "hyperf/tracer": "3.0.*"
    },
    "require-dev": {
        "friendsofphp/php-cs-fixer": "^3.0",
        "hyperf/devtool": "3.0.*",
        "hyperf/ide-helper": "3.0.*",
        "hyperf/testing": "3.0.*",
        "hyperf/watcher": "3.0.*",
        "mockery/mockery": "^1.0",
        "phpstan/phpstan": "^0.12",
        "swoole/ide-helper": "^4.5"
    },
    "suggest": {
        "ext-openssl": "Required to use HTTPS.",
        "ext-json": "Required to use JSON.",
        "ext-pdo": "Required to use MySQL Client.",
        "ext-pdo_mysql": "Required to use MySQL Client.",
        "ext-redis": "Required to use Redis Client."
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/Kernel/Functions.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "HyperfTest\\": "./test/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "optimize-autoloader": true,
        "sort-packages": true
    },
    "extra": [],
    "scripts": {
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-autoload-dump": [
            "rm -rf runtime/container"
        ],
        "test": "co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always",
        "cs-fix": "php-cs-fixer fix $1",
        "analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config",
        "start": [
            "Composer\\Config::disableProcessTimeout",
            "php ./bin/hyperf.php start"
        ]
    }
}


================================================
FILE: order-srv/config/autoload/amqp.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'host' => env('AMQP_HOST', 'localhost'),
        'port' => (int) env('AMQP_PORT', 5672),
        'user' => env('AMQP_USER', 'guest'),
        'password' => env('AMQP_PASSWORD', 'guest'),
        'vhost' => env('AMQP_VHOST', '/'),
        'open_ssl' => false,
        'concurrent' => [
            'limit' => 1,
        ],
        'pool' => [
            'connections' => 2,
        ],
        'params' => [
            'insist' => false,
            'login_method' => 'AMQPLAIN',
            'login_response' => null,
            'locale' => 'en_US',
            'connection_timeout' => 3,
            'read_write_timeout' => 6,
            'context' => null,
            'keepalive' => true,
            'heartbeat' => 3,
            'channel_rpc_timeout' => 0.0,
            'close_on_destruct' => false,
            'max_idle_channels' => 10,
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/annotations.php
================================================
<?php

declare(strict_types=1);

return [
    'scan' => [
        'paths' => [
            BASE_PATH . '/app',
        ],
        'ignore_annotations' => [
            'mixin',
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/aspects.php
================================================
<?php

declare(strict_types=1);

return [
    Hyperf\Tracer\Aspect\JsonRpcAspect::class,
];


================================================
FILE: order-srv/config/autoload/cache.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'driver' => Hyperf\Cache\Driver\RedisDriver::class,
        'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
        'prefix' => 'c:',
    ],
];


================================================
FILE: order-srv/config/autoload/commands.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: order-srv/config/autoload/config_center.php
================================================
<?php

declare(strict_types=1);

use Hyperf\ConfigCenter\Mode;

return [
    'enable' => (bool) env('CONFIG_CENTER_ENABLE', true),
    'driver' => env('CONFIG_CENTER_DRIVER', 'nacos'),
    'mode' => env('CONFIG_CENTER_MODE', Mode::PROCESS),
    'drivers' => [
        'nacos' => [
            'driver' => Hyperf\ConfigNacos\NacosDriver::class,
            'merge_mode' => Hyperf\ConfigNacos\Constants::CONFIG_MERGE_OVERWRITE,
            'interval' => 3,
            'default_key' => 'nacos_config',
            'listener_config' => [
                // dataId, group, tenant, type, content
                'nacos_config' => [
                    // 命名空间/ID
                    'tenant' => env('NACOS_TENANT'), // corresponding with service.namespaceId
                    // DataID
                    'data_id' => env('NACOS_DATA_ID'),
                    // 组名
                    'group' => 'DEFAULT_GROUP',
                    'type' => 'json',
                ],
            ],
            'client' => [
                // 客户端
                'host' => env('NACOS_HOST'),
                'port' => env('NACOS_PORT'),
                'username' => env('NACOS_USERNAME'),
                'password' => env('NACOS_PASSWORD'),
                'guzzle' => [
                    'config' => null,
                ],
            ],
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/databases.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'driver' => env('DB_DRIVER', 'mysql'),
        'host' => env('DB_HOST', 'localhost'),
        'port' => env('DB_PORT', 3306),
        'database' => env('DB_DATABASE', 'hyperf'),
        'username' => env('DB_USERNAME', 'root'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => env('DB_CHARSET', 'utf8mb4'),
        'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
        'prefix' => env('DB_PREFIX', ''),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
        ],
//        'cache' => [
//            'handler' => Hyperf\ModelCache\Handler\RedisHandler::class,
//            'cache_key' => '{mc:%s:m:%s}:%s:%s',
//            'prefix' => 'default',
//            'ttl' => 3600 * 24,
//            'empty_model_ttl' => 600,
//            'load_script' => true,
//        ],
        'commands' => [
            'gen:model' => [
                'path' => 'app/Model',
                'force_casts' => true,
                'inheritance' => 'Model',
                'uses' => '',
                'table_mapping' => [],
            ],
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/dependencies.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: order-srv/config/autoload/devtool.php
================================================
<?php

declare(strict_types=1);

return [
    'generator' => [
        'amqp' => [
            'consumer' => [
                'namespace' => 'App\\Amqp\\Consumer',
            ],
            'producer' => [
                'namespace' => 'App\\Amqp\\Producer',
            ],
        ],
        'aspect' => [
            'namespace' => 'App\\Aspect',
        ],
        'command' => [
            'namespace' => 'App\\Command',
        ],
        'controller' => [
            'namespace' => 'App\\Controller',
        ],
        'job' => [
            'namespace' => 'App\\Job',
        ],
        'listener' => [
            'namespace' => 'App\\Listener',
        ],
        'middleware' => [
            'namespace' => 'App\\Middleware',
        ],
        'Process' => [
            'namespace' => 'App\\Processes',
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/dtm.php
================================================
<?php

declare(strict_types=1);
/**
 * This file is part of DTM-PHP.
 *
 * @license  https://github.com/dtm-php/dtm-client/blob/master/LICENSE
 */
use DtmClient\Constants\Protocol;
use DtmClient\Constants\DbType;

return [
    'protocol' => Protocol::HTTP,
    'server' => env('DTM_HOST'),
    'port' => [
        'http' => 36789,
        'grpc' => 36790,
    ],
    'barrier' => [
        // DB 模式下的子事务屏障配置
        'db' => [
            'type' => DbType::MySQL
        ],
        // Redis 模式下的子事务屏障配置
        'redis' => [
            // 子事务屏障记录的超时时间
            'expire_seconds' => 7 * 86400,
        ],
        'apply' => [],
    ],
    'guzzle' => [
        'options' => [],
    ],
];


================================================
FILE: order-srv/config/autoload/exceptions.php
================================================
<?php

declare(strict_types=1);

return [
    'handler' => [
        'http' => [
            Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
            App\Exception\Handler\DtmExceptionHandler::class,
        ],
        'jsonrpc-http' => [
            App\Exception\Handler\JsonRpcExceptionHandler::class,
        ]
    ],
];


================================================
FILE: order-srv/config/autoload/listeners.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: order-srv/config/autoload/logger.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'handler' => [
            'class' => Monolog\Handler\RotatingFileHandler::class,
            'constructor' => [
                'filename' => BASE_PATH . '/runtime/logs/hyperf.log',
                'level' => Monolog\Logger::DEBUG,
            ],
        ],
        'formatter' => [
            'class' => Monolog\Formatter\LineFormatter::class,
            'constructor' => [
                'format' => null,
                'dateFormat' => 'Y-m-d H:i:s',
                'allowInlineLineBreaks' => true,
            ],
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/middlewares.php
================================================
<?php

declare(strict_types=1);

return [
    'http' => [
        \DtmClient\Middleware\DtmMiddleware::class,
    ],
    'jsonrpc-http' => [
        \Hyperf\Tracer\Middleware\TraceMiddleware::class,
        \DtmClient\Middleware\DtmMiddleware::class,
    ],
];


================================================
FILE: order-srv/config/autoload/nacos.php
================================================
<?php

declare(strict_types=1);

return [
    // nacos server url like https://nacos.hyperf.io, Priority is higher than host:port
    // 'url' => '',
    // The nacos host info
    'host' => env('NACOS_HOST'),
    'port' => env('NACOS_PORT'),
    // The nacos account info
    'username' => env('NACOS_USERNAME'),
    'password' => env('NACOS_PASSWORD'),
    'guzzle' => [
        'config' => null,
    ],
];


================================================
FILE: order-srv/config/autoload/opentracing.php
================================================
<?php

declare(strict_types=1);

use Zipkin\Samplers\BinarySampler;

return [
    'default' => env('TRACER_DRIVER', 'zipkin'),
    'enable' => [
        'guzzle' => env('TRACER_ENABLE_GUZZLE', false),
        'redis' => env('TRACER_ENABLE_REDIS', false),
        'db' => env('TRACER_ENABLE_DB', false),
        'method' => env('TRACER_ENABLE_METHOD', false),
    ],
    'tracer' => [
        'zipkin' => [
            'driver' => \Hyperf\Tracer\Adapter\ZipkinTracerFactory::class,
            'app' => [
                'name' => env('APP_NAME', 'skeleton'),
                // Hyperf will detect the system info automatically as the value if ipv4, ipv6, port is null
                'ipv4' => '127.0.0.1',
                'ipv6' => null,
                'port' => 9501,
            ],
            'options' => [
                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),
                'timeout' => env('ZIPKIN_TIMEOUT', 1),
            ],
            'sampler' => BinarySampler::createAsAlwaysSample(),
        ],
        'jaeger' => [
            'driver' => \Hyperf\Tracer\Adapter\JaegerTracerFactory::class,
            'name' => env('APP_NAME', 'skeleton'),
            'options' => [
                'local_agent' => [
                    'reporting_host' => env('JAEGER_REPORTING_HOST', 'localhost'),
                    'reporting_port' => env('JAEGER_REPORTING_PORT', 5775),
                ],
            ],
        ],
    ],
    'tags' => [
        // HTTP 客户端 (Guzzle)
        'http_client' => [
            'http.url' => 'http.url',
            'http.method' => 'http.method',
            'http.status_code' => 'http.status_code',
        ],
        // Redis 客户端
        'redis' => [
            'arguments' => 'arguments',
            'result' => 'result',
        ],
        // 数据库客户端 (hyperf/database)
        'db' => [
            'db.query' => 'db.query',
            'db.statement' => 'db.statement',
            'db.query_time' => 'db.query_time',
        ],
    ]
];


================================================
FILE: order-srv/config/autoload/processes.php
================================================
<?php

declare(strict_types=1);

return [
];


================================================
FILE: order-srv/config/autoload/redis.php
================================================
<?php

declare(strict_types=1);

return [
    'default' => [
        'host' => env('REDIS_HOST', 'localhost'),
        'auth' => env('REDIS_AUTH', null),
        'port' => (int) env('REDIS_PORT', 6379),
        'db' => (int) env('REDIS_DB', 0),
        'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
        ],
    ],
];


================================================
FILE: order-srv/config/autoload/server.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Server\Event;
use Hyperf\Server\Server;
use Swoole\Constant;

return [
    'mode' => SWOOLE_PROCESS,
    'servers' => [
        [
            'name' => 'http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9502,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
            ],
        ],
        [
            'name' => 'jsonrpc-http',
            'type' => Server::SERVER_HTTP,
            'host' => '0.0.0.0',
            'port' => 9505,
            'sock_type' => SWOOLE_SOCK_TCP,
            'callbacks' => [
                Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
            ],
        ],
    ],
    'settings' => [
        Constant::OPTION_ENABLE_COROUTINE => true,
        Constant::OPTION_WORKER_NUM => swoole_cpu_num(),
        Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',
        Constant::OPTION_OPEN_TCP_NODELAY => true,
        Constant::OPTION_MAX_COROUTINE => 100000,
        Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,
        Constant::OPTION_MAX_REQUEST => 100000,
        Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,
        Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,
    ],
    'callbacks' => [
        Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
        Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
        Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
    ],
];


================================================
FILE: order-srv/config/autoload/services.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/24
 * @create: 09:35
 */

// 这个是nacos服务的端口和地址
$registry = [
    'protocol' => 'nacos',
    'address' => 'http://'.env('NACOS_HOST').':'.env('NACOS_PORT'),
];

// 这里配置需要用的rpc服务
$services = [
    [
        'name' => 'UserRpcService',
        'service' => \App\JsonRpc\UserRpcServiceInterface::class
    ]
];

return [
    'enable' => [
        // 开启服务发现
        'discovery' => true,
        // 开启服务注册
        'register' => true,
    ],
    // 服务消费者相关配置
    'consumers' => value(function () use ($services, $registry) {
        // 循环生成rpc消费端
        $consumers = [];
        foreach ($services as $value) {
            $consumers[] = [
                'name' => $value['name'],
                'service' => $value['service'],
                'registry' => $registry
            ];
        }
        return $consumers;
    }),
    // 服务提供者相关配置
    'providers' => [],
    // 服务驱动相关配置
    'drivers' => [
        // nacos 配置,当前使用
        'nacos' => [
            // The nacos host info
            'host' => env('NACOS_HOST'),
            'port' => env('NACOS_PORT'),
            // nacos 账号密码信息
            'username' => env('NACOS_USERNAME'),
            'password' => env('NACOS_PASSWORD'),
            'guzzle' => [
                'config' => null,
            ],
            // 命名空间,public为默认系统空间
            'group_name' => 'api',
            // 命名空间ID
             'namespace_id' => env('NACOS_TENANT'),
            // 心跳检查秒数
            'heartbeat' => 5,
            'ephemeral' => true, // 是否注册临时实例
        ],
    ],
];

================================================
FILE: order-srv/config/autoload/tracer.php
================================================
<?php
/**
 * @user: DoubleJin
 * @date: 2022/5/25
 * @create: 11:29
 */


return [
    // 选择默认的 Tracer
    'default' => env('TRACER_DRIVER', 'jaeger'),

    // 这里的代码演示不对 enable 内的配置进行展开
    'enable' => [],

    'tracer' => [
        // Zipkin 驱动配置
        'zipkin' => [
            // 当前应用的配置
            'app' => [
                'name' => env('APP_NAME', 'skeleton'),
                // 如果 ipv6 和 ipv6 为空组件会自动从 Server 中检测
                'ipv4' => '127.0.0.1',
                'ipv6' => null,
                'port' => 9501,
            ],
            'driver' => \Hyperf\Tracer\Adapter\ZipkinTracerFactory::class,
            'options' => [
                // Zipkin 服务的 endpoint 地址
                'endpoint_url' => env('ZIPKIN_ENDPOINT_URL', 'http://localhost:9411/api/v2/spans'),
                // 请求超时秒数
                'timeout' => env('ZIPKIN_TIMEOUT', 1),
            ],
            // 采样器,默认为所有请求的都追踪
            'sampler' => \Zipkin\Samplers\BinarySampler::createAsAlwaysSample(),
        ],
    ],
];

================================================
FILE: order-srv/config/autoload/watcher.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Watcher\Driver\ScanFileDriver;

return [
    'driver' => ScanFileDriver::class,
    'bin' => 'php',
    'watch' => [
        'dir' => ['app', 'config'],
        'file' => ['.env'],
        'scan_interval' => 2000,
    ],
];


================================================
FILE: order-srv/config/config.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Contract\StdoutLoggerInterface;
use Psr\Log\LogLevel;

return [
    'app_name' => env('APP_NAME', 'skeleton'),
    'app_env' => env('APP_ENV', 'dev'),
    'scan_cacheable' => env('SCAN_CACHEABLE', false),
    StdoutLoggerInterface::class => [
        'log_level' => [
            LogLevel::ALERT,
            LogLevel::CRITICAL,
//            LogLevel::DEBUG,
            LogLevel::EMERGENCY,
            LogLevel::ERROR,
            LogLevel::INFO,
            LogLevel::NOTICE,
            LogLevel::WARNING,
        ],
    ],
];


================================================
FILE: order-srv/config/container.php
================================================
<?php
/**
 * Initialize a dependency injection container that implemented PSR-11 and return the container.
 */

declare(strict_types=1);

use Hyperf\Di\Container;
use Hyperf\Di\Definition\DefinitionSourceFactory;
use Hyperf\Utils\ApplicationContext;

$container = new Container((new DefinitionSourceFactory(true))());

if (! $container instanceof \Psr\Container\ContainerInterface) {
    throw new RuntimeException('The dependency injection container is invalid.');
}
return ApplicationContext::setContainer($container);


================================================
FILE: order-srv/config/routes.php
================================================
<?php

declare(strict_types=1);

use Hyperf\HttpServer\Router\Router;

Router::get('/favicon.ico', function () {
    return '';
});

================================================
FILE: order-srv/migrations/2022_06_08_061612_create_order_table.php
================================================
<?php

use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;

class CreateOrderTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('order', function (Blueprint $table) {
            $table->bigIncrements('id');

            $table->string('order_no')->nullable()->comment('订单编号');

            $table->integer('user_id')->default(0)->comment('线下订单编号');
            $table->integer('coupon_id')->default(0)->comment('会员优惠券id');

            $table->decimal('order_money',10,2)->default(0)->comment('订单金额');
            $table->decimal('order_discount',10,2)->default(0)->comment('订单折扣');
            $table->decimal('order_fact_money',10,2)->default(0)->comment('订单实际金额');

            $table->integer('consume_number')->default(0)->comment('商品数量');

            $table->tinyInteger('order_status')->default(0)->comment('订单状态, -1 已关闭 0 待支付 1 支付成功 2 已发货 3 退款处理  4 已完成');
            $table->tinyInteger('payment')->default(1)->comment('支付方式 1储值 2微信');

            $table->integer('create_time')->default(0)->comment('创建时间');
            $table->integer('update_time')->default(0)->comment('更新时间');

            $table->comment('订单表');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('order');
    }
}


================================================
FILE: order-srv/migrations/2022_06_08_063020_create_order_goods_table.php
================================================
<?php

use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;

class CreateOrderGoodsTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('order_goods', function (Blueprint $table) {

            $table->bigIncrements('id');

            $table->string('order_no',35)->nullable()->comment('订单编号');
            $table->integer('goods_id')->default(0)->comment('商品id');
            $table->string('goods_sn',35)->nullable()->comment('商品编号');
            $table->integer('sku_id')->default(0)->comment('skuid');
            $table->integer('user_id')->default(0)->comment('用户id');
            $table->string('goods_name',35)->nullable()->comment('商品名');
            $table->integer('number')->default(0)->comment('商品个数');

            $table->decimal('goods_tag_price',10,2)->default(0)->comment('吊牌价');
            $table->decimal('goods_real_price',10,2)->default(0)->comment('实际价');
            $table->decimal('goods_discount',10,2)->default(0)->comment('商户折扣');
            $table->decimal('goods_fact_money',10,2)->default(0)->comment('商品实际金额');

            $table->integer('create_time')->default(0)->comment('创建时间');
            $table->integer('update_time')->default(0)->comment('更新时间');

            $table->comment('订单商品表');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('order_goods');
    }
}


================================================
FILE: order-srv/seeders/order_goods_seeder.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Database\Seeders\Seeder;

class OrderGoodsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        \Hyperf\DbConnection\Db::table('order_goods')->insert([
            'order_no' => '20220527',
            'goods_id' => 2,
            'goods_sn' => 'AS12',
            'sku_id' => 10,
            'user_id' => 1,
            'goods_name' => '测试商品',
            'number' => 1,
            'goods_tag_price' => 100.00,
            'goods_real_price' => 100.00,
            'goods_discount' => 100.00,
            'goods_fact_money' => 100.00,
            'create_time' =>time(),
            'update_time' =>time(),
        ]);
    }
}


================================================
FILE: order-srv/seeders/order_seeder.php
================================================
<?php

declare(strict_types=1);

use Hyperf\Database\Seeders\Seeder;

class OrderSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        \Hyperf\DbConnection\Db::table('order')->insert([
            'order_no' => '20220527',
            'user_id' => 1,
            'coupon_id' => 0,
            'order_money' => 100.00,
            'order_discount' => 100.00,
            'order_fact_money' => 100.00,
            'consume_number' => 1,
            'order_status' => 1,
            'payment' => 1,
            'create_time' =>time(),
            'update_time' =>time(),
        ]);

    }
}


================================================
FILE: order-srv/test/Cases/ExampleTest.php
================================================
<?php

declare(strict_types=1);

namespace HyperfTest\Cases;

use HyperfTest\HttpTestCase;

/**
 * @internal
 * @coversNothing
 */
class ExampleTest extends HttpTestCase
{
    public function testExample()
    {
        $this->assertTrue(true);
        $this->assertTrue(is_array($this->get('/')));
    }
}


================================================
FILE: order-srv/test/HttpTestCase.php
================================================
<?php

declare(strict_types=1);

namespace HyperfTest;

use Hyperf\Testing\Client;
use PHPUnit\Framework\TestCase;

/**
 * Class HttpTestCase.
 * @method get($uri, $data = [], $headers = [])
 * @method post($uri, $data = [], $headers = [])
 * @method json($uri, $data = [], $headers = [])
 * @method file($uri, $data = [], $headers = [])
 * @method request($method, $path, $options = [])
 */
abstract class HttpTestCase extends TestCase
{
    /**
     * @var Client
     */
    protected $client;

    public function __construct($name = null, array $data = [], $dataName = '')
    {
        parent::__construct($name, $data, $dataName);
        $this->client = make(Client::class);
    }

    public function __call($name, $arguments)
    {
        return $this->client->{$name}(...$arguments);
    }
}


================================================
FILE: order-srv/test/bootstrap.php
================================================
<?php

declare(strict_types=1);

ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');

error_reporting(E_ALL);
date_default_timezone_set('Asia/Shanghai');

! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);

Swoole\Runtime::enableCoroutine(true);

require BASE_PATH . '/vendor/autoload.php';

Hyperf\Di\ClassLoader::init();

$container = require BASE_PATH . '/config/container.php';

$container->get(Hyperf\Contract\ApplicationInterface::class);


================================================
FILE: task-srv/.github/workflows/Dockerfile
================================================
# Default Dockerfile
#
# @link     https://www.hyperf.io
# @document https://hyperf.wiki
# @contact  group@hyperf.io
# @license  https://github.com/hyperf/hyperf/blob/master/LICENSE

FROM hyperf/hyperf:8.0-alpine-v3.15-swoole
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf"

##
# ---------- env settings ----------
##
# --build-arg timezone=Asia/Shanghai
ARG timezone

ENV TIMEZONE=${timezone:-"Asia/Shanghai"} \
    APP_ENV=prod \
    SCAN_CACHEABLE=(true)

# update
RUN set -ex \
    # show php version and extensions
    && php -v \
    && php -m \
    && php --ri swoole \
    #  ---------- some config ----------
    && cd /etc/php8 \
    # - config PHP
    && { \
        echo "upload_max_filesize=128M"; \
        echo "post_max_size=128M"; \
        echo "memory_limit=1G"; \
        echo "date.timezone=${TIMEZONE}"; \
    } | tee conf.d/99_overrides.ini \
    # - config timezone
    && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
    && echo "${TIMEZONE}" > /etc/timezone \
    # ---------- clear works ----------
    && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \
    && echo -e "\033[42;37m Build Completed :).\033[0m\n"

WORKDIR /opt/www

# Composer Cache
# COPY ./composer.* /opt/www/
# RUN composer install --no-dev --no-scripts

COPY . /opt/www
RUN print "\n" | composer install -o && php bin/hyperf.php

EXPOSE 9501

ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]


================================================
FILE: task-srv/.github/workflows/build.yml
================================================
name: Build Docker

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Build
        run: cp -rf .github/workflows/Dockerfile . && docker build -t hyperf .


================================================
FILE: task-srv/.github/workflows/release.yml
================================================
on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

name: Release

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false


================================================
FILE: task-srv/.gitignore
================================================
.buildpath
.settings/
.project
*.patch
.idea/
.git/
runtime/
vendor/
.phpintel/
.env
.DS_Store
.phpunit*
*.cache


================================================
FILE: task-srv/app/Amqp/Consumer/OrderConsumer.php
================================================
<?php

declare(strict_types=1);

namespace App\Amqp\Consumer;

use App\Log;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * 订单订阅消息消费者
 * Class OrderConsumer
 * @package App\Amqp\Consumer
 */
#[Consumer(exchange: 'order', routingKey: 'order', queue: 'order', name: "OrderConsumer", nums: 1)]
class OrderConsumer extends ConsumerMessage
{
    public function consumeMessage($data, AMQPMessage $message): string
    {
        Log::get()->info("消费订单队列",$data);

        return Result::ACK;
    }
}


================================================
FILE: task-srv/app/Amqp/Consumer/UserConsumer.php
================================================
<?php

declare(strict_types=1);

namespace App\Amqp\Consumer;

use App\Log;
use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * 用户订阅消息消费者
 * Class UserConsumer
 * @package App\Amqp\Consumer
 */
#[Consumer(exchange: 'user', routingKey: 'user', queue: 'user', name: "UserConsumer", nums: 1)]
class UserConsumer extends ConsumerMessage
{
    public function consumeMessage($data, AMQPMessage $message): string
    {
        Log::get()->info("消费用户队列",$data);

        return Result::ACK;
    }
}


================================================
FILE: task-srv/app/Command/TestCommand.php
================================================
<?php

declare(strict_types=1);

namespace App\Command;

use App\Log;
use Hyperf\Command\Command as HyperfCommand;
use Psr\Container\ContainerInterface;
use Hyperf\Command\Annotation\Command;

#[Command]
class TestCommand extends HyperfCommand
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * 执行的命令行
     *
     * @var string
     */
    protected ?string $name = 'TestCommand';


    public function handle()
    {

        Log::get()->info("运行TestCommand任务:".date("Y-m-d H:i:s"));

    }
}


================================================
FILE: task-srv/app/Controller/AbstractController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;

abstract class AbstractController
{
    #[Inject]
    protected ContainerInterface $container;

    #[Inject]
    protected RequestInterface $request;

    #[Inject]
    protected ResponseInterface $response;
}


================================================
FILE: task-srv/app/Controller/IndexController.php
================================================
<?php

declare(strict_types=1);

namespace App\Controller;

class IndexController extends AbstractController
{
    public function index()
    {
        $user = $this->request->input('user', 'Hyperf');
        $method = $this->request->getMethod();

        return [
            'method' => $method,
            'message' => "Hello {$user}.",
        ];
    }
}


================================================
FILE: task-srv/app/Exception/Handler/AppExceptionHandler.php
================================================
<?php

declare(strict_types=1);

namespace App\Exception\Handler;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class AppExceptionHandler extends ExceptionHandler
{
    public function __construct(protected StdoutLoggerInterface $logger)
    {
    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
        $this->logger->error($throwable->getTraceAsString());
        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}


================================================
FILE: task-srv/app/Listener/DbQueryExecutedListener.php
================================================
<?php

declare(strict_types=1);

namespace App\Listener;

use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;

#[Listener]
class DbQueryExecutedListener implements ListenerInterface
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(ContainerInterface $container)
    {
        $this->logger = $container->get(LoggerFactory::class)->get('sql');
    }

    public function listen(): array
    {
        return [
            QueryExecuted::class,
        ];
    }

    /**
     * @param QueryExecuted $event
     */
    public function process(object $event): void
    {
        if ($event instanceof QueryExecuted) {
            $sql = $event->sql;
            if (! Arr::isAssoc($event->bindings)) {
                foreach ($event->bindings as $key => $value) {
                    $sql = Str::replaceFirst('?', "'{$value}'", $sql);
                }
            }

            $this->logger->info(sprintf('[%s] %s', $event->time, $sql));
        }
    }
}


================================================
FILE: task-srv/app/Listener/QueueHandleListener.php
================================================
<?php

declare(strict_types=1);

namespace App\Listener;

use Hyperf\AsyncQueue\AnnotationJob;
use Hyperf\AsyncQueue\Event\AfterHandle;
use Hyperf\AsyncQueue\Event\BeforeHandle;
use Hyperf\AsyncQueue\Event\Event;
use Hyperf\AsyncQueue\Event\FailedHandle;
use Hyperf\AsyncQueue\Event\RetryHandle;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
use Hyperf\Logger\LoggerFactory;
use Psr\Log\LoggerInterface;

#[Listener]
class QueueHandleListener implements ListenerInterface
{
    protected LoggerInterface $logger;

    
Download .txt
gitextract_8s8otvkg/

├── .gitignore
├── LICENSE
├── README-CN.md
├── README.md
├── api-gateway/
│   ├── app/
│   │   ├── Constants/
│   │   │   ├── ErrorCode.php
│   │   │   └── ResponseCode.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   ├── AuthController.php
│   │   │   ├── CircuitBreakerController.php
│   │   │   ├── CommonController.php
│   │   │   ├── ConfigController.php
│   │   │   ├── FileController.php
│   │   │   ├── OrderController.php
│   │   │   ├── RateLimitController.php
│   │   │   └── UserController.php
│   │   ├── Exception/
│   │   │   ├── BusinessException.php
│   │   │   ├── Handler/
│   │   │   │   ├── AppExceptionHandler.php
│   │   │   │   ├── AppServiceExceptionHandler.php
│   │   │   │   └── RateLimitExceptionHandler.php
│   │   │   └── ServiceException.php
│   │   ├── JsonRpc/
│   │   │   ├── FileRpcServiceInterface.php
│   │   │   ├── OrderRpcServiceInterface.php
│   │   │   └── UserRpcServiceInterface.php
│   │   ├── Kernel/
│   │   │   └── Functions.php
│   │   ├── Listener/
│   │   │   ├── DbQueryExecutedListener.php
│   │   │   └── QueueHandleListener.php
│   │   ├── Log.php
│   │   ├── Middleware/
│   │   │   └── UserAuthMiddleware.php
│   │   ├── Model/
│   │   │   └── Model.php
│   │   ├── Process/
│   │   │   └── AsyncQueueConsumer.php
│   │   └── Services/
│   │       ├── AuthService.php
│   │       ├── FileService.php
│   │       ├── OrderService.php
│   │       └── UserService.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── async_queue.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── exceptions.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── rate_limit.php
│   │   │   ├── redis.php
│   │   │   ├── server.php
│   │   │   ├── services.php
│   │   │   ├── tracer.php
│   │   │   └── watcher.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
├── doc/
│   ├── DEPLOY_ONE.md
│   └── DEPLOY_TWO.md
├── docker-compose.yaml
├── file-srv/
│   ├── .github/
│   │   └── workflows/
│   │       ├── Dockerfile
│   │       ├── build.yml
│   │       └── release.yml
│   ├── .gitignore
│   ├── .watcher.php
│   ├── app/
│   │   ├── Constants/
│   │   │   └── ErrorCode.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   └── IndexController.php
│   │   ├── Exception/
│   │   │   ├── BusinessException.php
│   │   │   ├── Handler/
│   │   │   │   └── AppExceptionHandler.php
│   │   │   └── JsonRpcException.php
│   │   ├── JsonRpc/
│   │   │   ├── FileRpcService.php
│   │   │   └── FileRpcServiceInterface.php
│   │   ├── Listener/
│   │   │   ├── DbQueryExecutedListener.php
│   │   │   └── ResumeExitCoordinatorListener.php
│   │   ├── Log.php
│   │   ├── Model/
│   │   │   └── Model.php
│   │   └── Services/
│   │       └── FileService.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── exceptions.php
│   │   │   ├── file.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── redis.php
│   │   │   ├── server.php
│   │   │   └── services.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   ├── public/
│   │   └── uploads/
│   │       └── Pp7jmGorNbHecq50.xlsx
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
├── order-srv/
│   ├── app/
│   │   ├── Amqp/
│   │   │   └── Producer/
│   │   │       └── OrderProducer.php
│   │   ├── Constants/
│   │   │   ├── ErrorCode.php
│   │   │   └── ResponseCode.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   └── SagaController.php
│   │   ├── Exception/
│   │   │   ├── Handler/
│   │   │   │   ├── DtmExceptionHandler.php
│   │   │   │   └── JsonRpcExceptionHandler.php
│   │   │   ├── JsonRpcException.php
│   │   │   └── ServiceException.php
│   │   ├── JsonRpc/
│   │   │   ├── OrderRpcService.php
│   │   │   ├── OrderRpcServiceInterface.php
│   │   │   └── UserRpcServiceInterface.php
│   │   ├── Kernel/
│   │   │   └── Functions.php
│   │   ├── Listener/
│   │   │   └── DbQueryExecutedListener.php
│   │   ├── Log.php
│   │   ├── Model/
│   │   │   ├── Order.php
│   │   │   └── OrderGoods.php
│   │   └── Services/
│   │       └── OrderService.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── amqp.php
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── dtm.php
│   │   │   ├── exceptions.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── redis.php
│   │   │   ├── server.php
│   │   │   ├── services.php
│   │   │   ├── tracer.php
│   │   │   └── watcher.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   ├── migrations/
│   │   ├── 2022_06_08_061612_create_order_table.php
│   │   └── 2022_06_08_063020_create_order_goods_table.php
│   ├── seeders/
│   │   ├── order_goods_seeder.php
│   │   └── order_seeder.php
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
├── task-srv/
│   ├── .github/
│   │   └── workflows/
│   │       ├── Dockerfile
│   │       ├── build.yml
│   │       └── release.yml
│   ├── .gitignore
│   ├── app/
│   │   ├── Amqp/
│   │   │   └── Consumer/
│   │   │       ├── OrderConsumer.php
│   │   │       └── UserConsumer.php
│   │   ├── Command/
│   │   │   └── TestCommand.php
│   │   ├── Controller/
│   │   │   ├── AbstractController.php
│   │   │   └── IndexController.php
│   │   ├── Exception/
│   │   │   └── Handler/
│   │   │       └── AppExceptionHandler.php
│   │   ├── Listener/
│   │   │   ├── DbQueryExecutedListener.php
│   │   │   └── QueueHandleListener.php
│   │   ├── Log.php
│   │   ├── Model/
│   │   │   └── Model.php
│   │   └── Process/
│   │       └── AsyncQueueConsumer.php
│   ├── bin/
│   │   └── hyperf.php
│   ├── composer.json
│   ├── config/
│   │   ├── autoload/
│   │   │   ├── amqp.php
│   │   │   ├── annotations.php
│   │   │   ├── aspects.php
│   │   │   ├── async_queue.php
│   │   │   ├── cache.php
│   │   │   ├── commands.php
│   │   │   ├── config_center.php
│   │   │   ├── crontab.php
│   │   │   ├── databases.php
│   │   │   ├── dependencies.php
│   │   │   ├── devtool.php
│   │   │   ├── exceptions.php
│   │   │   ├── listeners.php
│   │   │   ├── logger.php
│   │   │   ├── middlewares.php
│   │   │   ├── nacos.php
│   │   │   ├── opentracing.php
│   │   │   ├── processes.php
│   │   │   ├── redis.php
│   │   │   └── server.php
│   │   ├── config.php
│   │   ├── container.php
│   │   └── routes.php
│   └── test/
│       ├── Cases/
│       │   └── ExampleTest.php
│       ├── HttpTestCase.php
│       └── bootstrap.php
└── user-srv/
    ├── app/
    │   ├── Amqp/
    │   │   └── Producer/
    │   │       └── UserProducer.php
    │   ├── Constants/
    │   │   ├── ErrorCode.php
    │   │   └── ResponseCode.php
    │   ├── Controller/
    │   │   ├── AbstractController.php
    │   │   └── SagaController.php
    │   ├── Exception/
    │   │   ├── Handler/
    │   │   │   ├── DtmExceptionHandler.php
    │   │   │   └── JsonRpcExceptionHandler.php
    │   │   ├── JsonRpcException.php
    │   │   └── ServiceException.php
    │   ├── JsonRpc/
    │   │   ├── UserRpcService.php
    │   │   └── UserRpcServiceInterface.php
    │   ├── Kernel/
    │   │   └── Functions.php
    │   ├── Listener/
    │   │   └── DbQueryExecutedListener.php
    │   ├── Log.php
    │   ├── Model/
    │   │   ├── User.php
    │   │   ├── UserBonusLog.php
    │   │   └── UserStoredLog.php
    │   └── Services/
    │       ├── AuthService.php
    │       └── UserService.php
    ├── bin/
    │   └── hyperf.php
    ├── composer.json
    ├── config/
    │   ├── autoload/
    │   │   ├── amqp.php
    │   │   ├── annotations.php
    │   │   ├── aspects.php
    │   │   ├── auth.php
    │   │   ├── cache.php
    │   │   ├── commands.php
    │   │   ├── config_center.php
    │   │   ├── databases.php
    │   │   ├── dependencies.php
    │   │   ├── devtool.php
    │   │   ├── dtm.php
    │   │   ├── exceptions.php
    │   │   ├── listeners.php
    │   │   ├── logger.php
    │   │   ├── middlewares.php
    │   │   ├── nacos.php
    │   │   ├── opentracing.php
    │   │   ├── processes.php
    │   │   ├── redis.php
    │   │   ├── server.php
    │   │   ├── services.php
    │   │   ├── tracer.php
    │   │   └── watcher.php
    │   ├── config.php
    │   ├── container.php
    │   └── routes.php
    ├── migrations/
    │   ├── 2022_06_08_072031_create_user_table.php
    │   ├── 2022_06_08_072120_create_user_bonus_log_table.php
    │   └── 2022_06_08_072134_create_user_stored_log_table.php
    ├── seeders/
    │   ├── user_bonus_log_seeder.php
    │   ├── user_seeder.php
    │   └── user_stored_log_seeder.php
    └── test/
        ├── Cases/
        │   └── ExampleTest.php
        ├── HttpTestCase.php
        └── bootstrap.php
Download .txt
SYMBOL INDEX (323 symbols across 111 files)

FILE: api-gateway/app/Constants/ErrorCode.php
  class ErrorCode (line 13) | class ErrorCode extends AbstractConstants

FILE: api-gateway/app/Constants/ResponseCode.php
  class ResponseCode (line 12) | class ResponseCode extends AbstractConstants

FILE: api-gateway/app/Controller/AbstractController.php
  class AbstractController (line 12) | abstract class AbstractController

FILE: api-gateway/app/Controller/AuthController.php
  class AuthController (line 20) | #[Controller(prefix: '/Auth')]
    method Login (line 35) | #[GetMapping(path: 'Login')]
    method Logout (line 49) | #[GetMapping(path: 'Logout')]

FILE: api-gateway/app/Controller/CircuitBreakerController.php
  class CircuitBreakerController (line 18) | #[Controller(prefix: '/CircuitBreaker')]
    method test (line 33) | #[GetMapping(path: 'Test')]
    method circuitBreakerFallback (line 46) | public function circuitBreakerFallback()

FILE: api-gateway/app/Controller/CommonController.php
  class CommonController (line 10) | class CommonController extends AbstractController
    method success (line 12) | public function success($data = [])

FILE: api-gateway/app/Controller/ConfigController.php
  class ConfigController (line 16) | #[Controller(prefix: '/Config')]
    method test (line 25) | #[GetMapping(path: 'Test')]

FILE: api-gateway/app/Controller/FileController.php
  class FileController (line 18) | #[Controller(prefix: '/File')]
    method uploadFile (line 33) | #[PostMapping(path: 'UploadFile')]

FILE: api-gateway/app/Controller/OrderController.php
  class OrderController (line 19) | #[Controller(prefix: '/Order')]
    method orderList (line 34) | #[GetMapping(path: 'OrderList')]
    method createOrder (line 48) | #[PostMapping(path: 'CreateOrder')]
    method orderRabbitMQ (line 84) | #[GetMapping(path: 'OrderRabbitMQ')]

FILE: api-gateway/app/Controller/RateLimitController.php
  class RateLimitController (line 16) | #[Controller(prefix: '/RateLimit')]
    method test (line 24) | #[GetMapping(path: 'Test')]

FILE: api-gateway/app/Controller/UserController.php
  class UserController (line 18) | #[Controller(prefix: '/User')]
    method userInfo (line 33) | #[GetMapping(path: 'UserInfo')]
    method userBonusList (line 47) | #[GetMapping(path: 'UserBonusList')]
    method userStoredList (line 61) | #[GetMapping(path: 'UserStoredList')]
    method userRabbitMQ (line 75) | #[GetMapping(path: 'UserRabbitMQ')]

FILE: api-gateway/app/Exception/BusinessException.php
  class BusinessException (line 11) | class BusinessException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: api-gateway/app/Exception/Handler/AppExceptionHandler.php
  class AppExceptionHandler (line 13) | class AppExceptionHandler extends ExceptionHandler
    method handle (line 20) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 25) | public function isValid(Throwable $throwable): bool

FILE: api-gateway/app/Exception/Handler/AppServiceExceptionHandler.php
  class AppServiceExceptionHandler (line 26) | class AppServiceExceptionHandler extends ExceptionHandler
    method handle (line 28) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 52) | public function isValid(Throwable $throwable): bool

FILE: api-gateway/app/Exception/Handler/RateLimitExceptionHandler.php
  class RateLimitExceptionHandler (line 27) | class RateLimitExceptionHandler extends ExceptionHandler
    method handle (line 29) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 52) | public function isValid(Throwable $throwable): bool

FILE: api-gateway/app/Exception/ServiceException.php
  class ServiceException (line 11) | class ServiceException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: api-gateway/app/JsonRpc/FileRpcServiceInterface.php
  type FileRpcServiceInterface (line 10) | interface FileRpcServiceInterface
    method uploadFile (line 13) | public function uploadFile(string $type, string $base64string, string ...

FILE: api-gateway/app/JsonRpc/OrderRpcServiceInterface.php
  type OrderRpcServiceInterface (line 10) | interface OrderRpcServiceInterface
    method orderList (line 13) | public function orderList(int $userId) : array;
    method createOrder (line 15) | public function createOrder(array $data) : array;
    method orderRabbitMQ (line 17) | public function orderRabbitMQ(): array;

FILE: api-gateway/app/JsonRpc/UserRpcServiceInterface.php
  type UserRpcServiceInterface (line 10) | interface UserRpcServiceInterface
    method userInfo (line 13) | public function userInfo(int $userId): array;
    method userBonusList (line 15) | public function userBonusList(int $page, int $pageSize): array;
    method userStoredList (line 17) | public function userStoredList(int $page, int $pageSize): array;
    method userRabbitMQ (line 19) | public function userRabbitMQ(): array;
    method userLogin (line 21) | public function userLogin(string $phone): array;
    method userLogout (line 23) | public function userLogout(string $token): array;
    method userCheckToken (line 25) | public function userCheckToken(string $token): array;

FILE: api-gateway/app/Kernel/Functions.php
  function di (line 29) | function di($id = null)
  function stdLog (line 43) | function stdLog()
  function logger (line 53) | function logger($name = 'log', $group = 'default')
  function redis (line 63) | function redis()
  function cache (line 73) | function cache()
  function format_throwable (line 85) | function format_throwable(Throwable $throwable): string
  function responseSuccess (line 93) | function responseSuccess($code, $message = '', $data = [])
  function responseError (line 103) | function responseError($code, $message = '', $data = [])
  function isJson (line 121) | function isJson($string)
  function container (line 132) | function container()
  function getBearerToken (line 142) | function getBearerToken($Authorization)

FILE: api-gateway/app/Listener/DbQueryExecutedListener.php
  class DbQueryExecutedListener (line 19) | class DbQueryExecutedListener implements ListenerInterface
    method __construct (line 26) | public function __construct(ContainerInterface $container)
    method listen (line 31) | public function listen(): array
    method process (line 41) | public function process(object $event) : void

FILE: api-gateway/app/Listener/QueueHandleListener.php
  class QueueHandleListener (line 21) | class QueueHandleListener implements ListenerInterface
    method __construct (line 33) | public function __construct(LoggerFactory $loggerFactory, FormatterInt...
    method listen (line 39) | public function listen(): array
    method process (line 49) | public function process(object $event) : void

FILE: api-gateway/app/Log.php
  class Log (line 13) | class Log
    method get (line 15) | public static function get(string $name = 'app')

FILE: api-gateway/app/Middleware/UserAuthMiddleware.php
  class UserAuthMiddleware (line 20) | class UserAuthMiddleware implements MiddlewareInterface
    method __construct (line 45) | public function __construct(ContainerInterface $container, HttpRespons...
    method process (line 52) | public function process(ServerRequestInterface $request, RequestHandle...
    method getBearerToken (line 67) | public function getBearerToken($request)

FILE: api-gateway/app/Model/Model.php
  class Model (line 10) | abstract class Model extends BaseModel implements CacheableInterface

FILE: api-gateway/app/Process/AsyncQueueConsumer.php
  class AsyncQueueConsumer (line 13) | class AsyncQueueConsumer extends ConsumerProcess

FILE: api-gateway/app/Services/AuthService.php
  class AuthService (line 17) | class AuthService
    method getRpcUserLogin (line 33) | public function getRpcUserLogin(string $phone)
    method getRpcUserLogout (line 69) | public function getRpcUserLogout(string $token)
    method getRpcUserCheckToken (line 105) | public function getRpcUserCheckToken(string $token)

FILE: api-gateway/app/Services/FileService.php
  class FileService (line 17) | class FileService
    method getRpcUploadFile (line 32) | public function getRpcUploadFile($file)

FILE: api-gateway/app/Services/OrderService.php
  class OrderService (line 16) | class OrderService
    method getRpcOrderList (line 31) | public function getRpcOrderList(int $userId)
    method rpcCreateOrder (line 67) | public function rpcCreateOrder(array $data)
    method getRpcOrderRabbitMQ (line 103) | public function getRpcOrderRabbitMQ()

FILE: api-gateway/app/Services/UserService.php
  class UserService (line 17) | class UserService
    method getRpcUserInfo (line 32) | public function getRpcUserInfo($userId)
    method getRpcUserBonusList (line 70) | public function getRpcUserBonusList(int $page, int $pageSize)
    method getRpcUserStoredList (line 107) | public function getRpcUserStoredList(int $page, int $pageSize)
    method testCircuitBreaker (line 141) | public function testCircuitBreaker()
    method getRpcUserRabbitMQ (line 155) | public function getRpcUserRabbitMQ()

FILE: api-gateway/test/Cases/ExampleTest.php
  class ExampleTest (line 13) | class ExampleTest extends HttpTestCase
    method testExample (line 15) | public function testExample()

FILE: api-gateway/test/HttpTestCase.php
  class HttpTestCase (line 18) | abstract class HttpTestCase extends TestCase
    method __construct (line 25) | public function __construct($name = null, array $data = [], $dataName ...
    method __call (line 31) | public function __call($name, $arguments)

FILE: file-srv/app/Constants/ErrorCode.php
  class ErrorCode (line 17) | #[Constants]

FILE: file-srv/app/Controller/AbstractController.php
  class AbstractController (line 19) | abstract class AbstractController

FILE: file-srv/app/Controller/IndexController.php
  class IndexController (line 14) | class IndexController extends AbstractController
    method index (line 16) | public function index()

FILE: file-srv/app/Exception/BusinessException.php
  class BusinessException (line 18) | class BusinessException extends ServerException
    method __construct (line 20) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: file-srv/app/Exception/Handler/AppExceptionHandler.php
  class AppExceptionHandler (line 20) | class AppExceptionHandler extends ExceptionHandler
    method __construct (line 22) | public function __construct(protected StdoutLoggerInterface $logger)
    method handle (line 26) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 33) | public function isValid(Throwable $throwable): bool

FILE: file-srv/app/Exception/JsonRpcException.php
  class JsonRpcException (line 11) | class JsonRpcException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: file-srv/app/JsonRpc/FileRpcService.php
  class FileRpcService (line 21) | #[RpcService(name: "FileRpcService", protocol: "jsonrpc-http", server: "...
    method uploadFile (line 34) | public function uploadFile(string $type,string $base64string,string $f...

FILE: file-srv/app/JsonRpc/FileRpcServiceInterface.php
  type FileRpcServiceInterface (line 10) | interface FileRpcServiceInterface
    method uploadFile (line 13) | public function uploadFile(string $type, string $base64string, string ...

FILE: file-srv/app/Listener/DbQueryExecutedListener.php
  class DbQueryExecutedListener (line 22) | #[Listener]
    method __construct (line 30) | public function __construct(ContainerInterface $container)
    method listen (line 35) | public function listen(): array
    method process (line 45) | public function process(object $event): void

FILE: file-srv/app/Listener/ResumeExitCoordinatorListener.php
  class ResumeExitCoordinatorListener (line 20) | #[Listener]
    method listen (line 23) | public function listen(): array
    method process (line 30) | public function process(object $event): void

FILE: file-srv/app/Log.php
  class Log (line 13) | class Log
    method get (line 15) | public static function get(string $name = 'app')

FILE: file-srv/app/Model/Model.php
  class Model (line 18) | abstract class Model extends BaseModel implements CacheableInterface

FILE: file-srv/app/Services/FileService.php
  class FileService (line 14) | class FileService
    method uploadFile (line 24) | public function uploadFile(string $type,string $base64string,string $f...

FILE: file-srv/test/Cases/ExampleTest.php
  class ExampleTest (line 20) | class ExampleTest extends HttpTestCase
    method testExample (line 22) | public function testExample()

FILE: file-srv/test/HttpTestCase.php
  class HttpTestCase (line 25) | abstract class HttpTestCase extends TestCase
    method __construct (line 32) | public function __construct($name = null, array $data = [], $dataName ...
    method __call (line 38) | public function __call($name, $arguments)

FILE: order-srv/app/Amqp/Producer/OrderProducer.php
  class OrderProducer (line 15) | #[Producer(exchange: 'order', routingKey: 'order')]
    method __construct (line 18) | public function __construct($data)

FILE: order-srv/app/Constants/ErrorCode.php
  class ErrorCode (line 10) | #[Constants]

FILE: order-srv/app/Constants/ResponseCode.php
  class ResponseCode (line 8) | #[Constants]

FILE: order-srv/app/Controller/AbstractController.php
  class AbstractController (line 12) | abstract class AbstractController

FILE: order-srv/app/Controller/SagaController.php
  class SagaController (line 18) | #[Controller(prefix: '/saga')]
    method sageCreateOrder (line 33) | #[PostMapping(path: 'sageCreateOrder')]
    method sageCreateOrderCompensate (line 49) | #[PostMapping(path: 'sageCreateOrderCompensate')]

FILE: order-srv/app/Exception/Handler/DtmExceptionHandler.php
  class DtmExceptionHandler (line 22) | class DtmExceptionHandler extends ExceptionHandler
    method handle (line 29) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 44) | public function isValid(Throwable $throwable): bool

FILE: order-srv/app/Exception/Handler/JsonRpcExceptionHandler.php
  class JsonRpcExceptionHandler (line 21) | class JsonRpcExceptionHandler extends ExceptionHandler
    method handle (line 28) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 59) | public function isValid(Throwable $throwable): bool

FILE: order-srv/app/Exception/JsonRpcException.php
  class JsonRpcException (line 11) | class JsonRpcException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: order-srv/app/Exception/ServiceException.php
  class ServiceException (line 11) | class ServiceException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: order-srv/app/JsonRpc/OrderRpcService.php
  class OrderRpcService (line 19) | #[RpcService(name:"OrderRpcService", protocol:"jsonrpc-http", server:"js...
    method orderList (line 34) | public function orderList(int $userId): array
    method createOrder (line 47) | public function createOrder(array $data): array
    method orderRabbitMQ (line 59) | public function orderRabbitMQ() : array

FILE: order-srv/app/JsonRpc/OrderRpcServiceInterface.php
  type OrderRpcServiceInterface (line 10) | interface OrderRpcServiceInterface
    method orderList (line 13) | public function orderList(int $userId): array;
    method createOrder (line 15) | public function createOrder(array $data): array;
    method orderRabbitMQ (line 17) | public function orderRabbitMQ(): array;

FILE: order-srv/app/JsonRpc/UserRpcServiceInterface.php
  type UserRpcServiceInterface (line 10) | interface UserRpcServiceInterface
    method userInfo (line 13) | public function userInfo(int $userId): array;
    method userBonusList (line 15) | public function userBonusList(int $page, int $pageSize): array;
    method userStoredList (line 17) | public function userStoredList(int $page, int $pageSize): array;
    method userRabbitMQ (line 19) | public function userRabbitMQ(): array;
    method userLogin (line 21) | public function userLogin(string $phone): array;
    method userLogout (line 23) | public function userLogout(string $token): array;

FILE: order-srv/app/Kernel/Functions.php
  function di (line 29) | function di($id = null)
  function stdLog (line 43) | function stdLog()
  function logger (line 53) | function logger($name = 'log', $group = 'default')
  function redis (line 63) | function redis()
  function cache (line 73) | function cache()
  function format_throwable (line 85) | function format_throwable(Throwable $throwable): string
  function responseSuccess (line 93) | function responseSuccess($code, $message = '', $data = [])
  function responseError (line 103) | function responseError($code, $message = '', $data = [])
  function isJson (line 120) | function isJson($string)
  function successJsonRpc (line 132) | function successJsonRpc($code, $data)

FILE: order-srv/app/Listener/DbQueryExecutedListener.php
  class DbQueryExecutedListener (line 16) | #[Listener]
    method __construct (line 24) | public function __construct(ContainerInterface $container)
    method listen (line 29) | public function listen() : array
    method process (line 36) | public function process(object $event) : void

FILE: order-srv/app/Log.php
  class Log (line 13) | class Log
    method get (line 15) | public static function get(string $name = 'app')

FILE: order-srv/app/Model/Order.php
  class Order (line 7) | class Order extends Model
    method orderGoods (line 29) | public function orderGoods()

FILE: order-srv/app/Model/OrderGoods.php
  class OrderGoods (line 7) | class OrderGoods extends Model

FILE: order-srv/app/Services/OrderService.php
  class OrderService (line 23) | class OrderService
    method orderList (line 44) | public function orderList($userId)
    method createOrder (line 89) | public function createOrder($data)
    method sageCreateOrder (line 135) | public function sageCreateOrder($data)
    method sageCreateOrderCompensate (line 182) | public function sageCreateOrderCompensate($data)
    method orderRabbitMQ (line 211) | public function orderRabbitMQ()

FILE: order-srv/migrations/2022_06_08_061612_create_order_table.php
  class CreateOrderTable (line 7) | class CreateOrderTable extends Migration
    method up (line 12) | public function up(): void
    method down (line 41) | public function down(): void

FILE: order-srv/migrations/2022_06_08_063020_create_order_goods_table.php
  class CreateOrderGoodsTable (line 7) | class CreateOrderGoodsTable extends Migration
    method up (line 12) | public function up(): void
    method down (line 41) | public function down(): void

FILE: order-srv/seeders/order_goods_seeder.php
  class OrderGoodsSeeder (line 7) | class OrderGoodsSeeder extends Seeder
    method run (line 14) | public function run()

FILE: order-srv/seeders/order_seeder.php
  class OrderSeeder (line 7) | class OrderSeeder extends Seeder
    method run (line 14) | public function run()

FILE: order-srv/test/Cases/ExampleTest.php
  class ExampleTest (line 13) | class ExampleTest extends HttpTestCase
    method testExample (line 15) | public function testExample()

FILE: order-srv/test/HttpTestCase.php
  class HttpTestCase (line 18) | abstract class HttpTestCase extends TestCase
    method __construct (line 25) | public function __construct($name = null, array $data = [], $dataName ...
    method __call (line 31) | public function __call($name, $arguments)

FILE: task-srv/app/Amqp/Consumer/OrderConsumer.php
  class OrderConsumer (line 18) | #[Consumer(exchange: 'order', routingKey: 'order', queue: 'order', name:...
    method consumeMessage (line 21) | public function consumeMessage($data, AMQPMessage $message): string

FILE: task-srv/app/Amqp/Consumer/UserConsumer.php
  class UserConsumer (line 18) | #[Consumer(exchange: 'user', routingKey: 'user', queue: 'user', name: "U...
    method consumeMessage (line 21) | public function consumeMessage($data, AMQPMessage $message): string

FILE: task-srv/app/Command/TestCommand.php
  class TestCommand (line 12) | #[Command]
    method handle (line 28) | public function handle()

FILE: task-srv/app/Controller/AbstractController.php
  class AbstractController (line 12) | abstract class AbstractController

FILE: task-srv/app/Controller/IndexController.php
  class IndexController (line 7) | class IndexController extends AbstractController
    method index (line 9) | public function index()

FILE: task-srv/app/Exception/Handler/AppExceptionHandler.php
  class AppExceptionHandler (line 13) | class AppExceptionHandler extends ExceptionHandler
    method __construct (line 15) | public function __construct(protected StdoutLoggerInterface $logger)
    method handle (line 19) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 26) | public function isValid(Throwable $throwable): bool

FILE: task-srv/app/Listener/DbQueryExecutedListener.php
  class DbQueryExecutedListener (line 16) | #[Listener]
    method __construct (line 24) | public function __construct(ContainerInterface $container)
    method listen (line 29) | public function listen(): array
    method process (line 39) | public function process(object $event): void

FILE: task-srv/app/Listener/QueueHandleListener.php
  class QueueHandleListener (line 19) | #[Listener]
    method __construct (line 24) | public function __construct(LoggerFactory $loggerFactory, protected Fo...
    method listen (line 29) | public function listen(): array
    method process (line 39) | public function process(object $event): void

FILE: task-srv/app/Log.php
  class Log (line 13) | class Log
    method get (line 15) | public static function get(string $name = 'app')

FILE: task-srv/app/Model/Model.php
  class Model (line 11) | abstract class Model extends BaseModel implements CacheableInterface

FILE: task-srv/app/Process/AsyncQueueConsumer.php
  class AsyncQueueConsumer (line 10) | #[Process]

FILE: task-srv/test/Cases/ExampleTest.php
  class ExampleTest (line 13) | class ExampleTest extends HttpTestCase
    method testExample (line 15) | public function testExample()

FILE: task-srv/test/HttpTestCase.php
  class HttpTestCase (line 18) | abstract class HttpTestCase extends TestCase
    method __construct (line 25) | public function __construct($name = null, array $data = [], $dataName ...
    method __call (line 31) | public function __call($name, $arguments)

FILE: user-srv/app/Amqp/Producer/UserProducer.php
  class UserProducer (line 15) | #[Producer(exchange: 'user', routingKey: 'user')]
    method __construct (line 18) | public function __construct($data)

FILE: user-srv/app/Constants/ErrorCode.php
  class ErrorCode (line 13) | class ErrorCode extends AbstractConstants

FILE: user-srv/app/Constants/ResponseCode.php
  class ResponseCode (line 12) | class ResponseCode extends AbstractConstants

FILE: user-srv/app/Controller/AbstractController.php
  class AbstractController (line 12) | abstract class AbstractController

FILE: user-srv/app/Controller/SagaController.php
  class SagaController (line 18) | #[Controller(prefix: '/saga')]
    method changeStored (line 33) | #[PostMapping(path: 'changeStored')]
    method changeStoredCompensate (line 53) | #[PostMapping(path: 'changeStoredCompensate')]

FILE: user-srv/app/Exception/Handler/DtmExceptionHandler.php
  class DtmExceptionHandler (line 22) | class DtmExceptionHandler extends ExceptionHandler
    method handle (line 29) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 44) | public function isValid(Throwable $throwable): bool

FILE: user-srv/app/Exception/Handler/JsonRpcExceptionHandler.php
  class JsonRpcExceptionHandler (line 21) | class JsonRpcExceptionHandler extends ExceptionHandler
    method handle (line 28) | public function handle(Throwable $throwable, ResponseInterface $response)
    method isValid (line 59) | public function isValid(Throwable $throwable): bool

FILE: user-srv/app/Exception/JsonRpcException.php
  class JsonRpcException (line 11) | class JsonRpcException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: user-srv/app/Exception/ServiceException.php
  class ServiceException (line 11) | class ServiceException extends ServerException
    method __construct (line 13) | public function __construct(int $code = 0, string $message = null, Thr...

FILE: user-srv/app/JsonRpc/UserRpcService.php
  class UserRpcService (line 20) | #[RpcService(name: "UserRpcService", protocol: "jsonrpc-http", server: "...
    method userInfo (line 34) | public function userInfo(int $userId): array
    method userBonusList (line 48) | public function userBonusList(int $page, int $pageSize): array
    method userStoredList (line 62) | public function userStoredList(int $page, int $pageSize): array
    method userRabbitMQ (line 74) | public function userRabbitMQ() : array
    method userLogin (line 87) | public function userLogin(string $phone): array
    method userLogout (line 100) | public function userLogout(string $token): array
    method userCheckToken (line 113) | public function userCheckToken(string $token): array

FILE: user-srv/app/JsonRpc/UserRpcServiceInterface.php
  type UserRpcServiceInterface (line 10) | interface UserRpcServiceInterface
    method userInfo (line 13) | public function userInfo(int $userId): array;
    method userBonusList (line 15) | public function userBonusList(int $page, int $pageSize): array;
    method userStoredList (line 17) | public function userStoredList(int $page, int $pageSize): array;
    method userRabbitMQ (line 19) | public function userRabbitMQ(): array;
    method userLogin (line 21) | public function userLogin(string $phone): array;
    method userLogout (line 23) | public function userLogout(string $token): array;
    method userCheckToken (line 25) | public function userCheckToken(string $token): array;

FILE: user-srv/app/Kernel/Functions.php
  function di (line 29) | function di($id = null)
  function stdLog (line 43) | function stdLog()
  function logger (line 53) | function logger($name = 'log', $group = 'default')
  function redis (line 63) | function redis()
  function cache (line 73) | function cache()
  function format_throwable (line 85) | function format_throwable(Throwable $throwable): string
  function responseSuccess (line 93) | function responseSuccess($code, $message = '', $data = [])
  function responseError (line 103) | function responseError($code, $message = '', $data = [])
  function isJson (line 120) | function isJson($string)
  function successJsonRpc (line 132) | function successJsonRpc($code, $data)

FILE: user-srv/app/Listener/DbQueryExecutedListener.php
  class DbQueryExecutedListener (line 19) | class DbQueryExecutedListener implements ListenerInterface
    method __construct (line 26) | public function __construct(ContainerInterface $container)
    method listen (line 31) | public function listen(): array
    method process (line 41) | public function process(object $event) : void

FILE: user-srv/app/Log.php
  class Log (line 13) | class Log
    method get (line 15) | public static function get(string $name = 'app')

FILE: user-srv/app/Model/User.php
  class User (line 11) | class User extends Model implements Authenticatable
    method bonus (line 45) | public function bonus()
    method stored (line 50) | public function stored()

FILE: user-srv/app/Model/UserBonusLog.php
  class UserBonusLog (line 9) | class UserBonusLog extends Model

FILE: user-srv/app/Model/UserStoredLog.php
  class UserStoredLog (line 9) | class UserStoredLog extends Model

FILE: user-srv/app/Services/AuthService.php
  class AuthService (line 18) | class AuthService
    method userLogin (line 29) | public function userLogin($phone)
    method userLogout (line 57) | public function userLogout($token)
    method userCheckToken (line 71) | public function userCheckToken($token)

FILE: user-srv/app/Services/UserService.php
  class UserService (line 20) | class UserService
    method userInfo (line 28) | public function userInfo($userId)
    method userBonusList (line 53) | public function userBonusList($page, $pageSize)
    method userStoredList (line 75) | public function userStoredList($page, $pageSize)
    method changeStored (line 97) | public function changeStored($userId, $amount, $orderNo)
    method changeStoredCompensate (line 130) | public function changeStoredCompensate($userId, $amount, $orderNo)
    method userRabbitMQ (line 157) | public function userRabbitMQ()

FILE: user-srv/migrations/2022_06_08_072031_create_user_table.php
  class CreateUserTable (line 7) | class CreateUserTable extends Migration
    method up (line 12) | public function up(): void
    method down (line 32) | public function down(): void

FILE: user-srv/migrations/2022_06_08_072120_create_user_bonus_log_table.php
  class CreateUserBonusLogTable (line 7) | class CreateUserBonusLogTable extends Migration
    method up (line 12) | public function up(): void
    method down (line 32) | public function down(): void

FILE: user-srv/migrations/2022_06_08_072134_create_user_stored_log_table.php
  class CreateUserStoredLogTable (line 7) | class CreateUserStoredLogTable extends Migration
    method up (line 12) | public function up(): void
    method down (line 32) | public function down(): void

FILE: user-srv/seeders/user_bonus_log_seeder.php
  class UserBonusLogSeeder (line 7) | class UserBonusLogSeeder extends Seeder
    method run (line 14) | public function run()

FILE: user-srv/seeders/user_seeder.php
  class UserSeeder (line 7) | class UserSeeder extends Seeder
    method run (line 14) | public function run()

FILE: user-srv/seeders/user_stored_log_seeder.php
  class UserStoredLogSeeder (line 7) | class UserStoredLogSeeder extends Seeder
    method run (line 14) | public function run()

FILE: user-srv/test/Cases/ExampleTest.php
  class ExampleTest (line 13) | class ExampleTest extends HttpTestCase
    method testExample (line 15) | public function testExample()

FILE: user-srv/test/HttpTestCase.php
  class HttpTestCase (line 18) | abstract class HttpTestCase extends TestCase
    method __construct (line 25) | public function __construct($name = null, array $data = [], $dataName ...
    method __call (line 31) | public function __call($name, $arguments)
Condensed preview — 264 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (287K chars).
[
  {
    "path": ".gitignore",
    "chars": 176,
    "preview": "*/.buildpath\n*/.settings/\n*/.project\n*/*.patch\n*/.idea/\n.idea/\n*/.git/\n.git/\n*/runtime/\n*/vendor/\n*/.phpintel/\n*/.env\n*/"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2022 Double-Jin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README-CN.md",
    "chars": 4890,
    "preview": "[English](./README.md) | [中文]\n\n# 介绍\n\nJin-microservices是基于 php 语言 + hyperf 微服务 框架的完整微服务demo。\n\ngithub:https://github.com/D"
  },
  {
    "path": "README.md",
    "chars": 9528,
    "preview": "English | [中文](./README-CN.md)\n\n# Introduction\n\nJin microservices is a complete microservice demo based on PHP language "
  },
  {
    "path": "api-gateway/app/Constants/ErrorCode.php",
    "chars": 290,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\"
  },
  {
    "path": "api-gateway/app/Constants/ResponseCode.php",
    "chars": 1578,
    "preview": "<?php\n\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n/*"
  },
  {
    "path": "api-gateway/app/Controller/AbstractController.php",
    "chars": 442,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contr"
  },
  {
    "path": "api-gateway/app/Controller/AuthController.php",
    "chars": 1423,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Middleware\\UserAuthMiddleware;\nuse App\\Services\\Auth"
  },
  {
    "path": "api-gateway/app/Controller/CircuitBreakerController.php",
    "chars": 1151,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\UserService;\nuse Hyperf\\Di\\Annotation\\Injec"
  },
  {
    "path": "api-gateway/app/Controller/CommonController.php",
    "chars": 281,
    "preview": "<?php\n\nnamespace App\\Controller;\n\n/**\n * 通用控制器\n * Class CommonController\n * @package App\\Controller\n */\nclass CommonCont"
  },
  {
    "path": "api-gateway/app/Controller/ConfigController.php",
    "chars": 683,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\Http"
  },
  {
    "path": "api-gateway/app/Controller/FileController.php",
    "chars": 873,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\FileService;\nuse Hyperf\\Di\\Annotation\\Injec"
  },
  {
    "path": "api-gateway/app/Controller/OrderController.php",
    "chars": 2446,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\OrderService;\nuse Hyperf\\Di\\Annotation\\Inje"
  },
  {
    "path": "api-gateway/app/Controller/RateLimitController.php",
    "chars": 614,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\HttpServer\\Annotation\\Controller;\nuse Hyperf\\Http"
  },
  {
    "path": "api-gateway/app/Controller/UserController.php",
    "chars": 2037,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\UserService;\nuse Hyperf\\Di\\Annotation\\Injec"
  },
  {
    "path": "api-gateway/app/Exception/BusinessException.php",
    "chars": 466,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\Serv"
  },
  {
    "path": "api-gateway/app/Exception/Handler/AppExceptionHandler.php",
    "chars": 694,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf"
  },
  {
    "path": "api-gateway/app/Exception/Handler/AppServiceExceptionHandler.php",
    "chars": 1420,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "api-gateway/app/Exception/Handler/RateLimitExceptionHandler.php",
    "chars": 1453,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "api-gateway/app/Exception/ServiceException.php",
    "chars": 469,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ResponseCode;\nuse Hyperf\\Server\\Exception\\S"
  },
  {
    "path": "api-gateway/app/JsonRpc/FileRpcServiceInterface.php",
    "chars": 230,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/12/20\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface FileRpcServi"
  },
  {
    "path": "api-gateway/app/JsonRpc/OrderRpcServiceInterface.php",
    "chars": 289,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface OrderRpcServi"
  },
  {
    "path": "api-gateway/app/JsonRpc/UserRpcServiceInterface.php",
    "chars": 537,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface UserRpcServic"
  },
  {
    "path": "api-gateway/app/Kernel/Functions.php",
    "chars": 3232,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document "
  },
  {
    "path": "api-gateway/app/Listener/DbQueryExecutedListener.php",
    "chars": 1251,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Ann"
  },
  {
    "path": "api-gateway/app/Listener/QueueHandleListener.php",
    "chars": 2324,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\AsyncQueue\\AnnotationJob;\nuse Hyperf\\AsyncQueue\\Eve"
  },
  {
    "path": "api-gateway/app/Log.php",
    "chars": 328,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory"
  },
  {
    "path": "api-gateway/app/Middleware/UserAuthMiddleware.php",
    "chars": 1740,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Middleware;\n\nuse App\\Exception\\ServiceException;\nuse App\\Services\\AuthSer"
  },
  {
    "path": "api-gateway/app/Model/Model.php",
    "chars": 272,
    "preview": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model as BaseModel;\nuse Hyperf\\Mod"
  },
  {
    "path": "api-gateway/app/Process/AsyncQueueConsumer.php",
    "chars": 217,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Process;\n\nuse Hyperf\\AsyncQueue\\Process\\ConsumerProcess;\nuse Hyperf\\Proce"
  },
  {
    "path": "api-gateway/app/Services/AuthService.php",
    "chars": 3144,
    "preview": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\UserRpcServiceInterface;\nuse App\\Lo"
  },
  {
    "path": "api-gateway/app/Services/FileService.php",
    "chars": 1585,
    "preview": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\FileRpcServiceInterface;\nuse App\\Lo"
  },
  {
    "path": "api-gateway/app/Services/OrderService.php",
    "chars": 3029,
    "preview": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\OrderRpcServiceInterface;\nuse App\\L"
  },
  {
    "path": "api-gateway/app/Services/UserService.php",
    "chars": 4265,
    "preview": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\ServiceException;\nuse App\\JsonRpc\\UserRpcServiceInterface;\nuse App\\Lo"
  },
  {
    "path": "api-gateway/bin/hyperf.php",
    "chars": 734,
    "preview": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limi"
  },
  {
    "path": "api-gateway/composer.json",
    "chars": 3006,
    "preview": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n      "
  },
  {
    "path": "api-gateway/config/autoload/annotations.php",
    "chars": 198,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ]"
  },
  {
    "path": "api-gateway/config/autoload/aspects.php",
    "chars": 92,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Tracer\\Aspect\\JsonRpcAspect::class,\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/async_queue.php",
    "chars": 409,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\AsyncQueue\\Driver\\RedisDriver::c"
  },
  {
    "path": "api-gateway/config/autoload/cache.php",
    "chars": 225,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,"
  },
  {
    "path": "api-gateway/config/autoload/commands.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/config_center.php",
    "chars": 1352,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABL"
  },
  {
    "path": "api-gateway/config/autoload/databases.php",
    "chars": 1350,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'hos"
  },
  {
    "path": "api-gateway/config/autoload/dependencies.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/devtool.php",
    "chars": 843,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n         "
  },
  {
    "path": "api-gateway/config/autoload/exceptions.php",
    "chars": 378,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception"
  },
  {
    "path": "api-gateway/config/autoload/listeners.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/logger.php",
    "chars": 613,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handl"
  },
  {
    "path": "api-gateway/config/autoload/middlewares.php",
    "chars": 283,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n        \\Hyperf\\Tracer\\Middleware\\TraceMiddleware::class,\n//  "
  },
  {
    "path": "api-gateway/config/autoload/nacos.php",
    "chars": 409,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than "
  },
  {
    "path": "api-gateway/config/autoload/opentracing.php",
    "chars": 2031,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zip"
  },
  {
    "path": "api-gateway/config/autoload/processes.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "api-gateway/config/autoload/rate_limit.php",
    "chars": 156,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'create' => 1,\n    'consume' => 1,\n    'capacity' => 1,\n    'limitCallback"
  },
  {
    "path": "api-gateway/config/autoload/redis.php",
    "chars": 535,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        '"
  },
  {
    "path": "api-gateway/config/autoload/server.php",
    "chars": 1389,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    '"
  },
  {
    "path": "api-gateway/config/autoload/services.php",
    "chars": 1799,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n// 这个是nacos服务的端口和地址\n$registry = [\n    'protocol"
  },
  {
    "path": "api-gateway/config/autoload/tracer.php",
    "chars": 1014,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/25\n * @create: 11:29\n */\n\nreturn [\n    // 选择默认的 Tracer\n    'default' => e"
  },
  {
    "path": "api-gateway/config/autoload/watcher.php",
    "chars": 268,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Watcher\\Driver\\ScanFileDriver;\n\nreturn [\n    'driver' => ScanFileDriver::cla"
  },
  {
    "path": "api-gateway/config/config.php",
    "chars": 576,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_nam"
  },
  {
    "path": "api-gateway/config/container.php",
    "chars": 521,
    "preview": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare("
  },
  {
    "path": "api-gateway/config/routes.php",
    "chars": 223,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::addRoute(['GET', 'POST', 'HEAD'], '/', 'A"
  },
  {
    "path": "api-gateway/test/Cases/ExampleTest.php",
    "chars": 307,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversN"
  },
  {
    "path": "api-gateway/test/HttpTestCase.php",
    "chars": 804,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n"
  },
  {
    "path": "api-gateway/test/bootstrap.php",
    "chars": 564,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_report"
  },
  {
    "path": "doc/DEPLOY_ONE.md",
    "chars": 3430,
    "preview": "# 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\nNac"
  },
  {
    "path": "doc/DEPLOY_TWO.md",
    "chars": 2765,
    "preview": "# docker-composer安装\n\ndocker-compose\n\n```bash  \n 1.vi /etc/sysctl.conf\n    #末尾添加一行\n    vm.max_map_count=262144\n    #查看结果\n"
  },
  {
    "path": "docker-compose.yaml",
    "chars": 1595,
    "preview": "version: '3.9'\nservices:\n  hyperf:\n    container_name: hyperf\n    image: hyperf/hyperf:8.1-alpine-v3.15-swoole-v5\n    ho"
  },
  {
    "path": "file-srv/.github/workflows/Dockerfile",
    "chars": 1459,
    "preview": "# Default Dockerfile\n#\n# @link     https://www.hyperf.io\n# @document https://hyperf.wiki\n# @contact  group@hyperf.io\n# @"
  },
  {
    "path": "file-srv/.github/workflows/build.yml",
    "chars": 260,
    "preview": "name: Build Docker\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkou"
  },
  {
    "path": "file-srv/.github/workflows/release.yml",
    "chars": 604,
    "preview": "on:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i."
  },
  {
    "path": "file-srv/.gitignore",
    "chars": 113,
    "preview": ".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",
    "chars": 473,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Constants/ErrorCode.php",
    "chars": 493,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Controller/AbstractController.php",
    "chars": 647,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Controller/IndexController.php",
    "chars": 567,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Exception/BusinessException.php",
    "chars": 671,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Exception/Handler/AppExceptionHandler.php",
    "chars": 1100,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Exception/JsonRpcException.php",
    "chars": 465,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\Serv"
  },
  {
    "path": "file-srv/app/JsonRpc/FileRpcService.php",
    "chars": 939,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\nuse App\\Services\\AuthSe"
  },
  {
    "path": "file-srv/app/JsonRpc/FileRpcServiceInterface.php",
    "chars": 230,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/12/20\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface FileRpcServi"
  },
  {
    "path": "file-srv/app/Listener/DbQueryExecutedListener.php",
    "chars": 1684,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Listener/ResumeExitCoordinatorListener.php",
    "chars": 784,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Log.php",
    "chars": 328,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory"
  },
  {
    "path": "file-srv/app/Model/Model.php",
    "chars": 478,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/app/Services/FileService.php",
    "chars": 1191,
    "preview": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Exception\\JsonRpcException;\nuse App\\Log;\n\n/**\n * 文件service\n * Class UserService"
  },
  {
    "path": "file-srv/bin/hyperf.php",
    "chars": 939,
    "preview": "#!/usr/bin/env php\n<?php\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document https://"
  },
  {
    "path": "file-srv/composer.json",
    "chars": 2794,
    "preview": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n      "
  },
  {
    "path": "file-srv/config/autoload/annotations.php",
    "chars": 403,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/aspects.php",
    "chars": 250,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/cache.php",
    "chars": 430,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/commands.php",
    "chars": 250,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/config_center.php",
    "chars": 1352,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABL"
  },
  {
    "path": "file-srv/config/autoload/databases.php",
    "chars": 1555,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/dependencies.php",
    "chars": 250,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/devtool.php",
    "chars": 1048,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/exceptions.php",
    "chars": 446,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/file.php",
    "chars": 3444,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/listeners.php",
    "chars": 374,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/logger.php",
    "chars": 810,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/middlewares.php",
    "chars": 273,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/nacos.php",
    "chars": 409,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than "
  },
  {
    "path": "file-srv/config/autoload/opentracing.php",
    "chars": 2031,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zip"
  },
  {
    "path": "file-srv/config/autoload/processes.php",
    "chars": 250,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/redis.php",
    "chars": 740,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/server.php",
    "chars": 1886,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/autoload/services.php",
    "chars": 939,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n\nreturn [\n    'enable' => [\n        // 开启服务发现\n "
  },
  {
    "path": "file-srv/config/config.php",
    "chars": 781,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/config/container.php",
    "chars": 573,
    "preview": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare("
  },
  {
    "path": "file-srv/config/routes.php",
    "chars": 426,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/test/Cases/ExampleTest.php",
    "chars": 512,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/test/HttpTestCase.php",
    "chars": 1009,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "file-srv/test/bootstrap.php",
    "chars": 769,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document h"
  },
  {
    "path": "order-srv/app/Amqp/Producer/OrderProducer.php",
    "chars": 399,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Producer;\n\nuse Hyperf\\Amqp\\Annotation\\Producer;\nuse Hyperf\\Amqp\\Mess"
  },
  {
    "path": "order-srv/app/Constants/ErrorCode.php",
    "chars": 281,
    "preview": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants"
  },
  {
    "path": "order-srv/app/Constants/ResponseCode.php",
    "chars": 1458,
    "preview": "<?php\n\nnamespace App\\Constants;\n\nuse Hyperf\\Constants\\AbstractConstants;\nuse Hyperf\\Constants\\Annotation\\Constants;\n\n#[C"
  },
  {
    "path": "order-srv/app/Controller/AbstractController.php",
    "chars": 455,
    "preview": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Cont"
  },
  {
    "path": "order-srv/app/Controller/SagaController.php",
    "chars": 1376,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse App\\Services\\OrderService;\nuse Hyperf\\HttpServer\\Contrac"
  },
  {
    "path": "order-srv/app/Exception/Handler/DtmExceptionHandler.php",
    "chars": 1016,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\JsonRpcException;\nuse App\\Exception"
  },
  {
    "path": "order-srv/app/Exception/Handler/JsonRpcExceptionHandler.php",
    "chars": 1723,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse App\\Exception\\JsonRpcException;\nuse Hyperf\\Contra"
  },
  {
    "path": "order-srv/app/Exception/JsonRpcException.php",
    "chars": 465,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\Serv"
  },
  {
    "path": "order-srv/app/Exception/ServiceException.php",
    "chars": 465,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception;\n\nuse App\\Constants\\ErrorCode;\nuse Hyperf\\Server\\Exception\\Serv"
  },
  {
    "path": "order-srv/app/JsonRpc/OrderRpcService.php",
    "chars": 1302,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\nuse Hyperf\\RpcServer\\An"
  },
  {
    "path": "order-srv/app/JsonRpc/OrderRpcServiceInterface.php",
    "chars": 287,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface OrderRpcServi"
  },
  {
    "path": "order-srv/app/JsonRpc/UserRpcServiceInterface.php",
    "chars": 483,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:31\n */\n\nnamespace App\\JsonRpc;\n\ninterface UserRpcServic"
  },
  {
    "path": "order-srv/app/Kernel/Functions.php",
    "chars": 2886,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of Hyperf.\n *\n * @link     https://www.hyperf.io\n * @document "
  },
  {
    "path": "order-srv/app/Listener/DbQueryExecutedListener.php",
    "chars": 1208,
    "preview": "<?php\n\ndeclare (strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\An"
  },
  {
    "path": "order-srv/app/Log.php",
    "chars": 328,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory"
  },
  {
    "path": "order-srv/app/Model/Order.php",
    "chars": 837,
    "preview": "<?php\n\ndeclare (strict_types=1);\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\nclass Order extends Model\n{\n"
  },
  {
    "path": "order-srv/app/Model/OrderGoods.php",
    "chars": 770,
    "preview": "<?php\n\ndeclare (strict_types=1);\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model;\nclass OrderGoods extends Mod"
  },
  {
    "path": "order-srv/app/Services/OrderService.php",
    "chars": 5485,
    "preview": "<?php\n\n\nnamespace App\\Services;\n\nuse App\\Amqp\\Producer\\OrderProducer;\nuse App\\JsonRpc\\UserRpcServiceInterface;\nuse App\\M"
  },
  {
    "path": "order-srv/bin/hyperf.php",
    "chars": 734,
    "preview": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limi"
  },
  {
    "path": "order-srv/composer.json",
    "chars": 2948,
    "preview": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n      "
  },
  {
    "path": "order-srv/config/autoload/amqp.php",
    "chars": 936,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('AMQP_HOST', 'localhost'),\n        'p"
  },
  {
    "path": "order-srv/config/autoload/annotations.php",
    "chars": 198,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ]"
  },
  {
    "path": "order-srv/config/autoload/aspects.php",
    "chars": 92,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Tracer\\Aspect\\JsonRpcAspect::class,\n];\n"
  },
  {
    "path": "order-srv/config/autoload/cache.php",
    "chars": 225,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,"
  },
  {
    "path": "order-srv/config/autoload/commands.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/config_center.php",
    "chars": 1352,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABL"
  },
  {
    "path": "order-srv/config/autoload/databases.php",
    "chars": 1366,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'hos"
  },
  {
    "path": "order-srv/config/autoload/dependencies.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/devtool.php",
    "chars": 843,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n         "
  },
  {
    "path": "order-srv/config/autoload/dtm.php",
    "chars": 688,
    "preview": "<?php\n\ndeclare(strict_types=1);\n/**\n * This file is part of DTM-PHP.\n *\n * @license  https://github.com/dtm-php/dtm-clie"
  },
  {
    "path": "order-srv/config/autoload/exceptions.php",
    "chars": 345,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception"
  },
  {
    "path": "order-srv/config/autoload/listeners.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/logger.php",
    "chars": 613,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handl"
  },
  {
    "path": "order-srv/config/autoload/middlewares.php",
    "chars": 261,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n        \\DtmClient\\Middleware\\DtmMiddleware::class,\n    ],\n   "
  },
  {
    "path": "order-srv/config/autoload/nacos.php",
    "chars": 409,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than "
  },
  {
    "path": "order-srv/config/autoload/opentracing.php",
    "chars": 2031,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zip"
  },
  {
    "path": "order-srv/config/autoload/processes.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "order-srv/config/autoload/redis.php",
    "chars": 535,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        '"
  },
  {
    "path": "order-srv/config/autoload/server.php",
    "chars": 1727,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Server\\Event;\nuse Hyperf\\Server\\Server;\nuse Swoole\\Constant;\n\nreturn [\n    '"
  },
  {
    "path": "order-srv/config/autoload/services.php",
    "chars": 1569,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/24\n * @create: 09:35\n */\n\n// 这个是nacos服务的端口和地址\n$registry = [\n    'protocol"
  },
  {
    "path": "order-srv/config/autoload/tracer.php",
    "chars": 1015,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/25\n * @create: 11:29\n */\n\n\nreturn [\n    // 选择默认的 Tracer\n    'default' => "
  },
  {
    "path": "order-srv/config/autoload/watcher.php",
    "chars": 268,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Watcher\\Driver\\ScanFileDriver;\n\nreturn [\n    'driver' => ScanFileDriver::cla"
  },
  {
    "path": "order-srv/config/config.php",
    "chars": 576,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Psr\\Log\\LogLevel;\n\nreturn [\n    'app_nam"
  },
  {
    "path": "order-srv/config/container.php",
    "chars": 521,
    "preview": "<?php\n/**\n * Initialize a dependency injection container that implemented PSR-11 and return the container.\n */\n\ndeclare("
  },
  {
    "path": "order-srv/config/routes.php",
    "chars": 131,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\HttpServer\\Router\\Router;\n\nRouter::get('/favicon.ico', function () {\n    ret"
  },
  {
    "path": "order-srv/migrations/2022_06_08_061612_create_order_table.php",
    "chars": 1424,
    "preview": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration"
  },
  {
    "path": "order-srv/migrations/2022_06_08_063020_create_order_goods_table.php",
    "chars": 1529,
    "preview": "<?php\n\nuse Hyperf\\Database\\Schema\\Schema;\nuse Hyperf\\Database\\Schema\\Blueprint;\nuse Hyperf\\Database\\Migrations\\Migration"
  },
  {
    "path": "order-srv/seeders/order_goods_seeder.php",
    "chars": 757,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass OrderGoodsSeeder extends Seeder\n{\n    /**\n  "
  },
  {
    "path": "order-srv/seeders/order_seeder.php",
    "chars": 673,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\Database\\Seeders\\Seeder;\n\nclass OrderSeeder extends Seeder\n{\n    /**\n     * "
  },
  {
    "path": "order-srv/test/Cases/ExampleTest.php",
    "chars": 307,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest\\Cases;\n\nuse HyperfTest\\HttpTestCase;\n\n/**\n * @internal\n * @coversN"
  },
  {
    "path": "order-srv/test/HttpTestCase.php",
    "chars": 804,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace HyperfTest;\n\nuse Hyperf\\Testing\\Client;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n"
  },
  {
    "path": "order-srv/test/bootstrap.php",
    "chars": 564,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\n\nerror_report"
  },
  {
    "path": "task-srv/.github/workflows/Dockerfile",
    "chars": 1459,
    "preview": "# Default Dockerfile\n#\n# @link     https://www.hyperf.io\n# @document https://hyperf.wiki\n# @contact  group@hyperf.io\n# @"
  },
  {
    "path": "task-srv/.github/workflows/build.yml",
    "chars": 260,
    "preview": "name: Build Docker\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkou"
  },
  {
    "path": "task-srv/.github/workflows/release.yml",
    "chars": 604,
    "preview": "on:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i."
  },
  {
    "path": "task-srv/.gitignore",
    "chars": 113,
    "preview": ".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",
    "chars": 592,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Consumer;\n\nuse App\\Log;\nuse Hyperf\\Amqp\\Result;\nuse Hyperf\\Amqp\\Anno"
  },
  {
    "path": "task-srv/app/Amqp/Consumer/UserConsumer.php",
    "chars": 586,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Amqp\\Consumer;\n\nuse App\\Log;\nuse Hyperf\\Amqp\\Result;\nuse Hyperf\\Amqp\\Anno"
  },
  {
    "path": "task-srv/app/Command/TestCommand.php",
    "chars": 534,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Command;\n\nuse App\\Log;\nuse Hyperf\\Command\\Command as HyperfCommand;\nuse P"
  },
  {
    "path": "task-srv/app/Controller/AbstractController.php",
    "chars": 442,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nuse Hyperf\\Di\\Annotation\\Inject;\nuse Hyperf\\HttpServer\\Contr"
  },
  {
    "path": "task-srv/app/Controller/IndexController.php",
    "chars": 362,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Controller;\n\nclass IndexController extends AbstractController\n{\n    publi"
  },
  {
    "path": "task-srv/app/Exception/Handler/AppExceptionHandler.php",
    "chars": 895,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exception\\Handler;\n\nuse Hyperf\\Contract\\StdoutLoggerInterface;\nuse Hyperf"
  },
  {
    "path": "task-srv/app/Listener/DbQueryExecutedListener.php",
    "chars": 1224,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\Database\\Events\\QueryExecuted;\nuse Hyperf\\Event\\Ann"
  },
  {
    "path": "task-srv/app/Listener/QueueHandleListener.php",
    "chars": 2203,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listener;\n\nuse Hyperf\\AsyncQueue\\AnnotationJob;\nuse Hyperf\\AsyncQueue\\Eve"
  },
  {
    "path": "task-srv/app/Log.php",
    "chars": 328,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/5/26\n * @create: 14:54\n */\n\nnamespace App;\n\nuse Hyperf\\Logger\\LoggerFactory"
  },
  {
    "path": "task-srv/app/Model/Model.php",
    "chars": 273,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Model;\n\nuse Hyperf\\DbConnection\\Model\\Model as BaseModel;\nuse Hyperf\\Mode"
  },
  {
    "path": "task-srv/app/Process/AsyncQueueConsumer.php",
    "chars": 208,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Process;\n\nuse Hyperf\\AsyncQueue\\Process\\ConsumerProcess;\nuse Hyperf\\Proce"
  },
  {
    "path": "task-srv/bin/hyperf.php",
    "chars": 734,
    "preview": "#!/usr/bin/env php\n<?php\n\nini_set('display_errors', 'on');\nini_set('display_startup_errors', 'on');\nini_set('memory_limi"
  },
  {
    "path": "task-srv/composer.json",
    "chars": 2588,
    "preview": "{\n    \"name\": \"hyperf/hyperf-skeleton\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"php\",\n        \"swoole\",\n      "
  },
  {
    "path": "task-srv/config/autoload/amqp.php",
    "chars": 907,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('AMQP_HOST', 'localhost'),\n        'p"
  },
  {
    "path": "task-srv/config/autoload/annotations.php",
    "chars": 198,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'scan' => [\n        'paths' => [\n            BASE_PATH . '/app',\n        ]"
  },
  {
    "path": "task-srv/config/autoload/aspects.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/async_queue.php",
    "chars": 409,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\AsyncQueue\\Driver\\RedisDriver::c"
  },
  {
    "path": "task-srv/config/autoload/cache.php",
    "chars": 225,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => Hyperf\\Cache\\Driver\\RedisDriver::class,"
  },
  {
    "path": "task-srv/config/autoload/commands.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/config_center.php",
    "chars": 1352,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Hyperf\\ConfigCenter\\Mode;\n\nreturn [\n    'enable' => (bool) env('CONFIG_CENTER_ENABL"
  },
  {
    "path": "task-srv/config/autoload/crontab.php",
    "chars": 368,
    "preview": "<?php\n/**\n * @user: DoubleJin\n * @date: 2022/6/23\n * @create: 14:55\n */\n\nuse Hyperf\\Crontab\\Crontab;\n\nreturn [\n    // 是否"
  },
  {
    "path": "task-srv/config/autoload/databases.php",
    "chars": 1350,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'driver' => env('DB_DRIVER', 'mysql'),\n        'hos"
  },
  {
    "path": "task-srv/config/autoload/dependencies.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/devtool.php",
    "chars": 843,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'generator' => [\n        'amqp' => [\n            'consumer' => [\n         "
  },
  {
    "path": "task-srv/config/autoload/exceptions.php",
    "chars": 241,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'handler' => [\n        'http' => [\n            Hyperf\\HttpServer\\Exception"
  },
  {
    "path": "task-srv/config/autoload/listeners.php",
    "chars": 45,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n];\n"
  },
  {
    "path": "task-srv/config/autoload/logger.php",
    "chars": 613,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'handler' => [\n            'class' => Monolog\\Handl"
  },
  {
    "path": "task-srv/config/autoload/middlewares.php",
    "chars": 68,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'http' => [\n    ],\n];\n"
  },
  {
    "path": "task-srv/config/autoload/nacos.php",
    "chars": 409,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    // nacos server url like https://nacos.hyperf.io, Priority is higher than "
  },
  {
    "path": "task-srv/config/autoload/opentracing.php",
    "chars": 1482,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nuse Zipkin\\Samplers\\BinarySampler;\n\nreturn [\n    'default' => env('TRACER_DRIVER', 'zip"
  },
  {
    "path": "task-srv/config/autoload/processes.php",
    "chars": 105,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    Hyperf\\Crontab\\Process\\CrontabDispatcherProcess::class,\n];\n"
  },
  {
    "path": "task-srv/config/autoload/redis.php",
    "chars": 535,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    'default' => [\n        'host' => env('REDIS_HOST', 'localhost'),\n        '"
  }
]

// ... and 64 more files (download for full content)

About this extraction

This page contains the full source code of the Double-Jin/jin-microservices GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 264 files (240.1 KB), approximately 74.0k tokens, and a symbol index with 323 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!