diff --git a/.gitignore b/.gitignore index 3ddda332d..d9cef967a 100644 --- a/.gitignore +++ b/.gitignore @@ -195,6 +195,7 @@ ClientBin/ *.pfx *.publishsettings node_modules/ +!/node_modules/swagger-ui-dist/ orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components @@ -262,3 +263,9 @@ paket-files/ __pycache__/ *.pyc +/src/Surging.Core/Surging.Core.CPlatform/CPlatformResource.en-US.resources +api/ +_site/ + +/src/Surging.ApiGateway +/src/Surging.Services/Surging.Services.Server/Dockerfile diff --git a/samples/README.md b/FETCH_HEAD similarity index 100% rename from samples/README.md rename to FETCH_HEAD diff --git a/README.EN.md b/README.EN.md index de4072624..95fc52d7d 100644 --- a/README.EN.md +++ b/README.EN.md @@ -4,7 +4,11 @@ # surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission.
-Start configuration: +### Architecture: + +架构图 + +### Start configuration:
diff --git a/README.md b/README.md index 5574e670b..719aca3a9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # surging                     [English](https://github.com/dotnetcore/surging/blob/master/README.EN.md) [![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://mit-license.org/) -### surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper、Consul作为surging服务的注册中心,集成了哈希,随机,轮询,压力最小优先作为负载均衡的算法,RPC集成采用的是netty框架,采用异步传输。 +### surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper、Consul作为surging服务的注册中心,集成了哈希,随机,轮询,压力最小优先作为负载均衡的算法,RPC可以选择采用netty或thrift框架,采用异步非阻塞传输。
@@ -18,6 +18,11 @@ ### 微服务定义 微服务应该是可以自由组合拆分,对于每个业务都是独立的,针对于业务模块的 CRUD 可以注册为服务,而每个服务都是高度自治的,从开发,部署都是独立,而每个服务只做单一功能,利用领域驱动设计去更好的拆分成粒度更小的模块 +### 微服务边界 +微服务是针对业务的松耦合,也是粒度最小的功能业务模块,针对于行业解决方案,集成相应的service host,而针对于业务需要一些中间件来辅助,比如缓存中间件,eventbus中间件(消息中间件),数据储存中间件,而各个服务又可以互相通过rpc进行可靠性通信。 + +引擎是微服务的容器,而docker 是服务引擎的容器,而利用k8s或rancher可以针对docker集群化管理,可以服务编排弹性扩容,熟知工具,让工具物尽其用。 + ### 能做什么 1.简化的服务调用,通过服务规则的指定,就可以做到服务之间的远程调用,无需其它方式的侵入 @@ -39,9 +44,13 @@ docker hub : docker pull serviceengine/surging:版本号 nuget:Install-Package surging -Version 版本号 -### surging模块功能 +### 架构图 + +架构图 -surging模块功能 +### 调用链 + +链路图 ### 配置: @@ -262,11 +271,18 @@ Task.FromResult(new Surging.IModuleServices.Common.Models.UserModel .AddClientIntercepted(typeof(CacheProviderInterceptor)) ``` +## 捐赠明细 + +surging 接受来自社区的捐赠,所有款项将通过 [捐赠明细表](Statement-of-Income-and-Expense.md) 进行公示,接受社区监督。 + IDE:Visual Studio 2017 15.5,vscode
框架:.NET core 2.1
QQ群:615562965 -* [Demo](https://github.com/billyang/SurgingDemo) * [文档](http://docs.dotnet-china.org/surging/) * [简单示例](https://github.com/dotnetcore/surging/blob/master/docs/docs.en/INDEX.md) + +## 谁在使用 + + diff --git a/Statement-of-Income-and-Expense.md b/Statement-of-Income-and-Expense.md new file mode 100644 index 000000000..2090bfa09 --- /dev/null +++ b/Statement-of-Income-and-Expense.md @@ -0,0 +1,64 @@ +# 收支明细表 + +说明:为保证surging财务公开透明,决定将每一笔捐赠和支出记录于本表,资金由 [fanly](https://github.com/fanliang11) 托管,并且受社区人员监督用于surging的生态发展 + + +## 汇总 + +截止到 2018 年 12 月 28 日: ++ 共获得捐赠 `49` 笔计 `8679.06` 元人民币 ++ 暂无支出项 + +## 明细 + +| 序号 | 捐赠人 | 时间 | 金额 | 说明 | 留言 | 类型 | +|------------|:------------:|-------------|--------------------|-------------------|--------------------|-----| +| 1 | Murphy | 2018-12-19 | 100 | Murphy 个人捐赠 | 这家伙很懒 |获赠 | +| 2 | 宗国 | 2018-12-19 | 20 | 宗国 个人捐赠 | 这家伙很懒 |获赠 | +| 3 | 紫能 | 2018-12-19 | 50 | 紫能 个人捐赠 | 这家伙很懒 |获赠 | +| 4 | Damon | 2018-12-19 | 18.8 | Damon 个人捐赠 | 支持一下 |获赠 | +| 5 | 悉路 | 2018-12-19 | 10 | 悉路 个人捐赠 | 感谢作者的付出,希望能完善文档 |获赠 | +| 6 | jiang | 2018-12-19 | 16.66 | jiang 个人捐赠 | 这家伙很懒 |获赠 | +| 7 | 伯锰 z.l | 2018-12-19 | 20 | 伯锰 z.l 个人捐赠 | 期待1.0 |获赠 | +| 8 | 匿名 | 2018-12-19 | 5000 | 匿名个人捐赠 | 这家伙很懒 |获赠 | +| 9 | 爱吃牛排的牛仔 | 2018-12-19 | 66.66 | 爱吃牛排的牛仔个人捐赠 | 这家伙很懒 |获赠 | +| 10 | siyue | 2018-12-20 | 50 | siyue个人捐赠 | 这家伙很懒 |获赠 | +| 11 | 学飞 | 2018-12-20 | 200 | 学飞个人捐赠 | 还在学习,期待surging越来越好 |获赠 | +| 12 | 昵称bai | 2018-12-21 | 10 | 昵称bai个人捐赠 | 这家伙很懒 |获赠 | +| 13 | 半碗的彩霞 | 2018-12-21 | 10 | 半碗的彩霞个人捐赠 | 这家伙很懒 |获赠 | +| 14 | 虎牙 | 2018-12-21 | 1000 | 虎牙个人捐赠 | 这家伙很懒 |获赠 | +| 15 | 寸草无心 | 2018-12-21 | 100 | 寸草无心个人捐赠 | 关注surging已有大半年了 默默支持 |获赠 | +| 16 | 洋 | 2018-12-24 | 1 | 洋个人捐赠 | dotnetty支持websocket了 |获赠 | +| 17 | 高文 | 2018-12-24 | 10 | 高文个人捐赠 | 庆祝1.0 |获赠 | +| 18 | 培根 | 2018-12-24 | 36 | 培根个人捐赠 | 捐赠一杯咖啡 |获赠 | +| 19 | gesneriana | 2018-12-24 | 26 | gesneriana个人捐赠 | 这家伙很懒 |获赠 | +| 20 | 学军 | 2018-12-27 | 100 | 学军个人捐赠 | 这家伙很懒 |获赠 | +| 21 | 高立哲 | 2018-12-27 | 30 | 高立哲个人捐赠 | 这家伙很懒 |获赠 | +| 22 | 俊文 | 2018-12-27 | 10 | 俊文个人捐赠 | 这家伙很懒 |获赠 | +| 23 | 根堂 | 2018-12-28 | 100 | 根堂个人捐赠 | 这家伙很懒 |获赠 | +| 24 | 东周 | 2018-12-28 | 5 | 东周个人捐赠 | 辛苦 |获赠 | +| 25 | 纯 | 2018-12-28 | 20 | 纯个人捐赠 | 这家伙很懒 |获赠 | +| 26 | 夏志行 | 2018-12-28 | 88 | 夏志行个人捐赠 | 这家伙很懒 |获赠 | +| 27 | 勇 | 2018-12-28 | 88.88 | 勇个人捐赠 | 这家伙很懒 |获赠 | +| 28 | 启旺 | 2018-12-28 | 10 | 勇个人捐赠 | 这家伙很懒 |获赠 | +| 29 | 雯昌 | 2018-12-28 | 20 | 雯昌个人捐赠 | 支持surging |获赠 | +| 30 | 宏伟 | 2018-12-28 | 500 | 宏伟个人捐赠 | 这家伙很懒 |获赠 | +| 31 | 伟 | 2018-12-28 | 20 | 伟个人捐赠 | 这家伙很懒 |获赠 | +| 32 | 建 | 2018-12-28 | 10 |建个人捐赠 | 希望大佬搞好文档,在下尽点微薄之力 |获赠 | +| 33 | 林 | 2018-12-29 | 30 |林个人捐赠 | 这家伙很懒 |获赠 | +| 34 | 俊强 | 2018-12-29 | 100 | 俊强个人捐赠 | 这家伙很懒 |获赠 | +| 35 | 彪 | 2018-01-02 | 10 | 彪个人捐赠 | 支持一下surging |获赠 | +| 36 | 忠全 | 2018-01-02 | 200 | 忠全个人捐赠 | 学习一下 |获赠 | +| 37 | 思恒 | 2018-01-03 | 10 | 思恒个人捐赠 | 这家伙很懒 |获赠 | +| 38 | 松波 | 2018-01-04 | 100 | 松波个人捐赠 | 出精品 |获赠 | +| 39 | 先鸿 | 2019-01-05 | 30 | 先鸿个人捐赠 | 加油 |获赠 | +| 40 | 杨坚 | 2019-01-08 | 100 | 杨坚个人捐赠 | 加油,希望surging能形成自己的社区 |获赠 | +| 41 | 济良 | 2019-01-09 | 10 | 济良个人捐赠 | 这家伙很懒 |获赠 | +| 42 | 祥 | 2019-01-11 | 36 | 祥个人捐赠 | 支持大佬,希望.net社区越来越好 |获赠 | +| 43 | 文斌 | 2019-01-14 | 50 | 文斌个人捐赠 | 读书也要交学费,买书起码花点钱 |获赠 | +| 44 | 笋 | 2019-01-25 | 30 | 笋个人捐赠 | 支持一下 |获赠 | +| 45 | Leo | 2019-01-30 | 100 | Leo个人捐赠 | 支持surging |获赠 | +| 46 | 文丽 | 2019-02-01 | 20 | 文丽 | 这家伙很懒 |获赠 | +| 47 | 卫东 | 2019-02-13 | 16 | 卫东 | 这家伙很懒 |获赠 | +| 48 | 安平 | 2019-02-15 | 30 | 安平 | 支持surging,感谢作者付出. |获赠 | +| 49 | MyDAL | 2019-02-19 | 6.66 | MyDAL | 支持国人自己的轮子. |获赠 | diff --git a/docfx.json b/docfx.json new file mode 100644 index 000000000..b436d8477 --- /dev/null +++ b/docfx.json @@ -0,0 +1,83 @@ +{ + "metadata": [ + ], + "build": { + "content": [ + { + "files": [ + "docs/**.md", + "docs/**/toc.yml", + "toc.yml", + "*.md" + ] + } + ], + "resource": [ + { + "files": [ + "**/images/**" + ] + } + ], + "overwrite": [ + { + "files": [ + "apidoc/**.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "dest": "_site", + "globalMetadataFiles": [], + "fileMetadataFiles": [], + "template": [ + "default" + ], + "postProcessors": [], + "markdownEngineName": "markdig", + "noLangKeyword": false, + "keepFileLink": false, + "cleanupCacheHistory": false, + "disableGitFeatures": false + } +// "pdf": { +// "content": [ +// { +// "files": [ +// "docs/**.md", +// "docs/**/toc.yml", +// "toc.yml", +// "*.md" +// ] +// } +// ], +// "resource": [ +// { +// "files": [ +// "**/images/**" +// ], +// "exclude": [ +// "**/bin/**", +// "**/obj/**", +// "_site_pdf/**" +// ] +// } +// ], +// "overwrite": [ +// { +// "files": [ +// "apidoc/**.md" +// ], +// "exclude": [ +// "**/bin/**", +// "**/obj/**", +// "_site_pdf/**" +// ] +// } +// ], +// "dest": "_site_pdf" +// } +} \ No newline at end of file diff --git a/docs/Architecture.png b/docs/Architecture.png new file mode 100644 index 000000000..af1d6e577 Binary files /dev/null and b/docs/Architecture.png differ diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 000000000..581bdf7eb --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,45 @@ +# Surging文档贡献指南 + +## docfx的安装与使用 +### 1. 打开`powershell`,使用如下命令安装[Chocolatey](https://chocolatey.org/install) +```shell +Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) +``` + +### 2. 安装`docfx`工具 +```shell +choco install docfx -y +``` +> **Notes** +> - 安装完`docfx`之后需要重启`powershell`,才会有`docfx`命令 + +### 3. `docfx`的使用 +```shell +# 构建文档 +docfx build + +# 构建文档同时本地预览 +docfx build -s + +# 本地预览文档 +docfx serve +``` +> **Notes** +> - 更多关于`docfx`工具使用教程的请[参考](https://dotnet.github.io/docfx/tutorial/docfx.exe_user_manual.html) + +## 如何成为开发者文档贡献者 +我们欢迎所有有能力的开发者为surging社区做出自己的贡献,为surging的发展贡献自己的力量。您可以通过qq群或是issues向作者申请成为文档作者。我们会将文档的贡献者显示在开发者文档相关页面,对所有做出贡献的开发者表示感谢。 + +## 编写开发者文档 + +### 1. 新增文档目录 +在[`./docs/toc.yml`](./toc.yml)新增文档目录,并在首页[`./docs/index.md`](./index.md)中创建相关的链接。 + +### 2. 编写开发者文档 +使用`markdown`编写开发者文档,将文档存放到相关模块的目录下。关于文档写作规范请[参考](https://github.com/ruanyf/document-style-guide)。 + +### 3. 提交并发起PR +发起pr后,经作者审核通过,将会合并到主分支。 + +## 投稿 +欢迎开发者向社区投稿关于surging或是微服务相关的博客,您可以选择同时发表到其他平台,但是必须是原创的。请将相关的博文存放在`./docs/blogs`目录下,并向社区提交`PR`。 diff --git a/docs/blogs/index.md b/docs/blogs/index.md new file mode 100644 index 000000000..2e88b4546 --- /dev/null +++ b/docs/blogs/index.md @@ -0,0 +1,3 @@ +# Surging相关博文 + +## 欢迎投稿 \ No newline at end of file diff --git a/docs/call-chain.png b/docs/call-chain.png new file mode 100644 index 000000000..aeb496f01 Binary files /dev/null and b/docs/call-chain.png differ diff --git a/docs/docs.cn/INDEX.md b/docs/docs.cn/INDEX.md index b9adf8f4e..14d681c63 100644 --- a/docs/docs.cn/INDEX.md +++ b/docs/docs.cn/INDEX.md @@ -1,3 +1,40 @@ -surging is a high-performance microservice framework based on the .NET core language,It was created by an individual and designed for use in the cloud, -Then add to dotnetcore +# surging的介绍               +``` + 作者:fanly 校对:fanly +``` + +什么是Surging + + surging 是微服务引擎,提供了轻量级,高性能,模块化的RPC请求管道,服务引擎支持http、TCP、WS、Mqtt、UDP、DNS协议,采用了Zookeeper、Consul作为注册中心,集成了哈希,随机,轮询,压力最小优先作为负载均衡的算法,内置了服务治理用来保证可靠性RPC通信 + +使用surging你可以: + + * 构建Web应用程序,微服务和api网关 + * 微服务可以部署在docker。可以使用k8s、rancher服务编排弹性扩容 + * 提供了多协议支持 + * 支持负载平衡分流压力 + * 基于.NET Core的跨平台可以在Windows,macOS和Linux上运行;也可以移植到其他操作系统。 + * 简化的服务调用,通过服务规则的指定,就可以做到服务之间的远程调用,无需其它方式的侵入 + * 服务自动注册与发现,不需要配置服务提供方地址,注册中心基于ServiceId 或者RoutePath查询服务提供者的地址和元数据,并且能够平滑添加或删除服务提供者。 + * 软负载均衡及容错机制,通过surging内部负载算法和容错规则的设定,从而达到内部调用的负载和容错 + * 分布式缓存中间件:通过哈希一致性算法来实现负载,并且有健康检查能够平滑的把不健康的服务从列表中删除 + * 事件总线:通过对于事件总线的适配可以实现发布订阅交互模式 + * 容器化持续集成与持续交付 :通过构建一体化Devops平台,实现项目的自动化构建、部署、测试和发布,从而提高生产环境的可靠性、稳定性、弹性和安全性。 + * 业务模块化驱动引擎,通过加载指定业务模块,能够更加灵活、高效的部署不同版本的业务功能模块 + +基于surging微服务的开发人员提供以下好处: + + * 统一构建微服务。 + * 内置依赖注入,您可以自由组合依赖组件。 + * 内置服务注册中心。 + * 内置网关可以统一外部访问和管理。 + * 轻量级,高性能,模块化的RPC请求管道。 + * 能够在您自己的进程中托管IIS或自托管。 + * 可以在.NET Core上运行,能够在Windows,macOS和Linux上构建和运行 + * 简化繁琐的维护。 + * 基于github平台的开源。 + * 支持负载平衡分流压力。 + * 支持多协议服务主机。 + * 内置服务化治理。 + * 支持引用、Nuget Install Package、扫描三种方式来加载组件和业务模块 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..fff2a2778 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,62 @@ +# 关于开发者文档 + +## 文档简介 + +## 目录 +- [概述](quick-start/index.md) +- - [surging 简介]() +- - [版本更新]() +- [教程]() +- - [服务主机如何构建]() +- - - [依赖注入服务]() +- - - [配置日志组件]() +- - - [如何设置成服务提供者]() +- - - [启动配置]() +- - - [配置文件构建]() +- - [协议主机构建]() +- - - [构建TCP协议服务主机]() +- - - [构建MQTT协议服务主机]() +- - - [构建WS协议服务主机]() +- - - [构建UDP协议服务主机]() +- - - [构建Http协议服务主机]() +- - - [构建Dns协议服务主机]() +- - [如何构建微服务]() +- - - [微服务规则]() +- - - [配置routepath]() +- - - [配置ServiceMetadata]() +- - - [服务拦截器配置]() +- - - [配置依赖注入]() +- - - [如何配置和读取配置项]() +- - [服务注册发现和服务治理]() +- - - [consul的注册与发现]() +- - - [zookeeper的注册与发现]() +- - - [服务路由的负载均衡]() +- - - [容错策略]() +- - - [服务熔断]() +- - [引擎核心组件]() +- - - [配置使用Swagger组件]() +- - - [配置ProtoBuffer、MessagePack或Json.net组件编解码消息]() +- - - [配置Log4net日志组件]() +- - - [配置NLog日志组件]() +- - - [配置Stage关卡组件]() +- - - [配置扩展SystemModule组件]() +- - - [配置扩展BusinessModule组件]() +- - - [配置扩展EnginePartModule组件]() +- - - [配置扩展KestrelHttpModule组件]() +- - [中间件]() +- - - [缓存中间件]() +- - - [消息中间件]() +- - [网关]() +- - - [配置gatewaySettings.json文件]() +- - - [jwt鉴权]() +- - - [基于Stage生成的第三方接口网关]() +- [示例]() +- - [缓存中间件使用]() +- - [消息中间件使用]() +- - [服务之间本地和远程调用]() +- [部署]() +- - [引擎部署到window环境中]() +- - [引擎部署到linux环境容器中]() +- - [引擎构建镜像push到镜像库]() +- - [扫描业务模块组件和中间件装载到引擎中]() +- - [基于rancher 服务编排 ]() diff --git a/docs/quick-start/index.md b/docs/quick-start/index.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/toc.yml b/docs/toc.yml new file mode 100644 index 000000000..fb70c2c4d --- /dev/null +++ b/docs/toc.yml @@ -0,0 +1,5 @@ +- name: 开发者文档 + href: index.md +- name: 快速开始 + href: quick-start/index.md + topicHref: quick-start/ \ No newline at end of file diff --git a/index.md b/index.md new file mode 100644 index 000000000..da1316874 --- /dev/null +++ b/index.md @@ -0,0 +1,15 @@ +--- +layout: HubPage +ms.topic: hub-page +hide_bc: true +title: +description: +ms.date: "2019.6.29" +--- + +# Surging + +## 简介 + +## 社区愿景 + diff --git a/samples/.gitignore b/samples/.gitignore deleted file mode 100644 index befad6a88..000000000 --- a/samples/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -/Centa.Agency.HostService/bin -/Centa.Agency.HostService/obj -/Centa.Agency.Application.Service/bin -/Centa.Agency.Application.Service/obj -/DDD.Core/bin -/DDD.Core/obj -/Centa.Agency.Web/bin -bin -obj -/Centa.HostService.SysLog/obj -/Centa.HostService.SysLog/bin -/Centa.Agency.Application.Interface/obj -/Centa.Agency.Domain/obj -/Centa.Agency.Domain/bin -/Centa.Agency.Query/bin -/Centa.Agency.Query/obj -/Centa.Agency.Web/obj diff --git a/samples/AuthServer/Application.Interface.Auth/Application.Interface.Auth.csproj b/samples/AuthServer/Application.Interface.Auth/Application.Interface.Auth.csproj deleted file mode 100644 index 8c27115ea..000000000 --- a/samples/AuthServer/Application.Interface.Auth/Application.Interface.Auth.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - diff --git a/samples/AuthServer/Application.Interface.Auth/Dto/LoginReq.cs b/samples/AuthServer/Application.Interface.Auth/Dto/LoginReq.cs deleted file mode 100644 index acbad5813..000000000 --- a/samples/AuthServer/Application.Interface.Auth/Dto/LoginReq.cs +++ /dev/null @@ -1,14 +0,0 @@ -using DTO.Core; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Application.Service.Auth.Dto -{ - public class LoginReq : BaseDto - { - public string UserName { get; set; } - public string Pwd { get; set; } - public Guid CorporationKeyId { get; set; } - } -} diff --git a/samples/AuthServer/Application.Interface.Auth/Event/CorporationActivated.cs b/samples/AuthServer/Application.Interface.Auth/Event/CorporationActivated.cs deleted file mode 100644 index 11f421dad..000000000 --- a/samples/AuthServer/Application.Interface.Auth/Event/CorporationActivated.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Surging.Core.CPlatform.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Application.Interface.Auth.EVENT -{ - // /// - // /// 新注册公司被激活的事件 - // /// - //public class CorporationActivatedEvent: IntegrationEvent - // { - - // } -} diff --git a/samples/AuthServer/Application.Interface.Auth/Event/IAuthEventHandler.cs b/samples/AuthServer/Application.Interface.Auth/Event/IAuthEventHandler.cs deleted file mode 100644 index 93ae5b0b7..000000000 --- a/samples/AuthServer/Application.Interface.Auth/Event/IAuthEventHandler.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Application.Interface.Org.EVENT; -using Surging.Core.CPlatform.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Application.Interface.Auth.EVENT -{ - /// - /// 事件处理器 - /// - public interface IAuthEventHandler : IIntegrationEventHandler - { - } -} diff --git a/samples/AuthServer/Application.Interface.Auth/IAuthAppService.cs b/samples/AuthServer/Application.Interface.Auth/IAuthAppService.cs deleted file mode 100644 index 3b899c1ea..000000000 --- a/samples/AuthServer/Application.Interface.Auth/IAuthAppService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Application.Service.Auth.Dto; -using DTO.Core; -using Surging.Core.CPlatform.Ioc; -using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Application.Interface.Auth -{ - [ServiceBundle("api/{Service}")] - public interface IAuthAppService : IServiceKey - { - - /// - /// 登录系统 - /// - /// - [Service(Date = "2018-1-30", Director = "刘旭东", Name = "登录系统")] - Task SignIn( LoginReq req); - - /// - /// 退出系统 - /// - /// - [Service(Date = "2018-1-30", Director = "刘旭东", Name = "退出系统")] - Task SignUp(CommonCMDReq req); - - [Service(Date = "2018-1-30", Director = "刘旭东", Name = "查询系统模块下的所有权限")] - Task FindDomainPermissions(CommonCMDReq req); - } -} diff --git a/samples/AuthServer/Application.Service.Auth/Application.Service.Auth.csproj b/samples/AuthServer/Application.Service.Auth/Application.Service.Auth.csproj deleted file mode 100644 index 0e9898f87..000000000 --- a/samples/AuthServer/Application.Service.Auth/Application.Service.Auth.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - - - - - diff --git a/samples/AuthServer/Application.Service.Auth/EventHandling/AuthEventHandler.cs b/samples/AuthServer/Application.Service.Auth/EventHandling/AuthEventHandler.cs deleted file mode 100644 index ab81150ff..000000000 --- a/samples/AuthServer/Application.Service.Auth/EventHandling/AuthEventHandler.cs +++ /dev/null @@ -1,55 +0,0 @@ -using App.Core.Security; -using Application.Interface.Auth.EVENT; -using Application.Interface.Org.EVENT; -using Domain.Auth.Aggregate; -using Repository.Auth; -using Surging.Core.ProxyGenerator; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace Application.Service.Auth.EventHandling -{ - //[QueueConsumerAttribute] - public class AuthEventHandler : IAuthEventHandler - { - private readonly UserRepository _userRepository; - private readonly SubDomainRepository _subDomainRepository; - private readonly UserQueryRepository _queryUserRepository; - private readonly SubDomainQueryRepository _querySubDomainRepository; - // private ICacheProvider _cacheProvider; - public AuthEventHandler(UserRepository userRepository, UserQueryRepository queryUserRepository, - SubDomainRepository subDomainRepository, SubDomainQueryRepository querySubDomainRepository) - { - _userRepository = userRepository; - _subDomainRepository = subDomainRepository; - _queryUserRepository = queryUserRepository; - _querySubDomainRepository = querySubDomainRepository; - } - - - public Task Handle(CorporationActivatedEvent @event) - { - //需要为企业管理做初始化,并生成管理员账号 - return Task.Run(() => - { - var encryptionService = new EncryptionService(); - _userRepository.Add(new User - { - CorporationKeyId = @event.CorpId, - IsDelete = false, - EmployeeKeyID = Guid.Parse(@event.EmpId), - KeyId = Guid.NewGuid(), - Name = "超级管理员", - No = "SuperMan", - Version = 1, - Pwd = encryptionService.EncryptText("123456") - }); - - _userRepository.Commit(); - }); - - } - } -} diff --git a/samples/AuthServer/Application.Service.Auth/Query/AuthAppService.cs b/samples/AuthServer/Application.Service.Auth/Query/AuthAppService.cs deleted file mode 100644 index d6db7d3de..000000000 --- a/samples/AuthServer/Application.Service.Auth/Query/AuthAppService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DTO.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Application.Service.Auth -{ - public partial class AuthAppService - { - public Task FindDomainPermissions(CommonCMDReq req) - { - BaseListResponseDto rsp = new BaseListResponseDto(); - var rows= _querySubDomainRepository.Get(a => !a.IsDelete,b=>b.SubDomainPermissions).ToList(); - rsp.Result = rows.Select(a => new { - keyId = a.KeyId, - domainNmae = a.Name, - action = a.SubDomainPermissions.Where(b=>b.PermissionType== Domain.Auth.Entity.PermissionCategory.Action)?.GroupBy(b => b.GroupName, c => new { - name=c.Name, - no=c.No - }).ToDictionary(b=>b.Key,c=>c), - page = a.SubDomainPermissions.Where(b => b.PermissionType == Domain.Auth.Entity.PermissionCategory.Page)?.Select(c => new { - name = c.Name, - no = c.No - }).ToList() - }).ToList(); - return Task.FromResult(rsp); - } - - } -} diff --git a/samples/AuthServer/Application.Service.Auth/UseCases/AuthAppService.cs b/samples/AuthServer/Application.Service.Auth/UseCases/AuthAppService.cs deleted file mode 100644 index f3d351d92..000000000 --- a/samples/AuthServer/Application.Service.Auth/UseCases/AuthAppService.cs +++ /dev/null @@ -1,65 +0,0 @@ -using App.Core.Security; -using Application.Interface.Auth; -using Application.Service.Auth.Dto; -using Domain.Auth.Aggregate; -using DTO.Core; -using Repository.Auth; -using Surging.Core.Caching; -using Surging.Core.CPlatform.Ioc; -using Surging.Core.ProxyGenerator; - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Application.Service.Auth -{ - [ModuleName("Auth")] - public partial class AuthAppService : ProxyServiceBase, IAuthAppService - { - private readonly UserRepository _userRepository; - private readonly SubDomainRepository _subDomainRepository; - private readonly UserQueryRepository _queryUserRepository; - private readonly SubDomainQueryRepository _querySubDomainRepository; - // private ICacheProvider _cacheProvider; - public AuthAppService(UserRepository userRepository, UserQueryRepository queryUserRepository, - SubDomainRepository subDomainRepository, SubDomainQueryRepository querySubDomainRepository) - { - _userRepository = userRepository; - _subDomainRepository = subDomainRepository; - _queryUserRepository = queryUserRepository; - _querySubDomainRepository = querySubDomainRepository; - } - - public Task SignIn(LoginReq req) - { - User user=null; - try { - //缓存增加当前用户相关信息 - //_cacheProvider= CacheContainer.GetInstances("Redis"); - //_cacheProvider.Add("UserKeyId=22", "{ UserKeyId=22,TenantId=3}"); - var encryptionService = new EncryptionService(); - var pwde = encryptionService.EncryptText(req.Pwd); - user = _queryUserRepository.GetSingle(a => a.CorporationKeyId == req.CorporationKeyId && !a.IsDelete && a.Pwd == pwde && a.No == req.UserName); - } - catch (Exception ex) - { - string ss = ex.Message; - } - if (user != null) - { - return Task.FromResult(new TokenDto { CorporationKeyId = user.CorporationKeyId, Token = user.EmployeeKeyID.ToString() }); - - } - else - { - return Task.FromResult(null); - } - } - - public Task SignUp(CommonCMDReq req) - { - throw new NotImplementedException(); - } - } -} diff --git a/samples/AuthServer/Domain/Aggregate/SubDomain.cs b/samples/AuthServer/Domain/Aggregate/SubDomain.cs deleted file mode 100644 index ba5963c54..000000000 --- a/samples/AuthServer/Domain/Aggregate/SubDomain.cs +++ /dev/null @@ -1,24 +0,0 @@ -using DDD.Core; -using Domain.Auth.Entity; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Auth.Aggregate -{ - /// - /// 服务模块(子领域) - /// - [Table("Auth_SubDomains")] - public class SubDomain : IAggregate - { - - /// - /// 模块下的权限 - /// - public virtual List SubDomainPermissions { get; set; } - - } -} diff --git a/samples/AuthServer/Domain/Aggregate/User.cs b/samples/AuthServer/Domain/Aggregate/User.cs deleted file mode 100644 index 2135d1a39..000000000 --- a/samples/AuthServer/Domain/Aggregate/User.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Auth.Aggregate -{ - /// - /// 平台用户(账号) - /// - [Table("Auth_Users")] - public class User : IAggregate - { - - /// - /// 密码 - /// - public string Pwd { get; set; } - - - /// - /// 归属员工 - /// - public Guid EmployeeKeyID { get; set; } - - - //public virtual List Departments { get; set; } - - } -} diff --git a/samples/AuthServer/Domain/Domain.Auth.csproj b/samples/AuthServer/Domain/Domain.Auth.csproj deleted file mode 100644 index 557735dc9..000000000 --- a/samples/AuthServer/Domain/Domain.Auth.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - - - - - - - - - diff --git a/samples/AuthServer/Domain/Entity/SubDomainPermission.cs b/samples/AuthServer/Domain/Entity/SubDomainPermission.cs deleted file mode 100644 index b34a3e9dc..000000000 --- a/samples/AuthServer/Domain/Entity/SubDomainPermission.cs +++ /dev/null @@ -1,40 +0,0 @@ -using DDD.Core; -using Domain.Auth.Aggregate; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Auth.Entity -{ - /// - /// 模块下的权限 - /// - [Table("Auth_SubDomain_Permissions")] - public class SubDomainPermission : BaseEntity - { - public string GroupName { get; set; } - public string GroupNo { get; set; } - - public PermissionCategory PermissionType { get; set; } - - public Guid SubDomainKeyId { get; set; } - - [ForeignKey("SubDomainKeyId")] - public SubDomain SubDomain { get; set; } - } - - public enum PermissionCategory - { - /// - /// 页面 - /// - Page=1, - - /// - /// 动作 - /// - Action=2 - } -} diff --git a/samples/AuthServer/Domain/Repository/UserRepository.cs b/samples/AuthServer/Domain/Repository/UserRepository.cs deleted file mode 100644 index 00c3f69c7..000000000 --- a/samples/AuthServer/Domain/Repository/UserRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Domain.Auth.Aggregate; -using Microsoft.EntityFrameworkCore; -using Repository.EF.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Domain.Auth.Repository -{ - -} diff --git a/samples/AuthServer/Domain/ValueObject/InquiryParameter.cs b/samples/AuthServer/Domain/ValueObject/InquiryParameter.cs deleted file mode 100644 index 4dcf8b670..000000000 --- a/samples/AuthServer/Domain/ValueObject/InquiryParameter.cs +++ /dev/null @@ -1,29 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.ValueObject.Inquiry -{ - - public class InquiryParameter: BaseValueObject - { - // [Column("InquiryKeyId")] - public Guid InquiryKeyId { get; set; } - // [ForeignKey("InquiryKeyId")] - // public CusInquiry OwnCusInquiry { get; set; } - - public Guid SysParameterItemKeyId { get; set; } - public int ParameterType { get; set; } - public int Seq { get; set; } - /* - [InverseProperty("Author")] - public List AuthoredPosts { get; set; } - - [InverseProperty("Contributor")] - public List ContributedToPosts { get; set; } - */ - - } -} diff --git a/samples/AuthServer/HostService/Configs/log4net.config b/samples/AuthServer/HostService/Configs/log4net.config deleted file mode 100644 index 42fd16880..000000000 --- a/samples/AuthServer/HostService/Configs/log4net.config +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/AuthServer/HostService/HostService.csproj b/samples/AuthServer/HostService/HostService.csproj deleted file mode 100644 index 6fc04dddc..000000000 --- a/samples/AuthServer/HostService/HostService.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - Exe - netcoreapp2.0 - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - diff --git a/samples/AuthServer/HostService/Program.cs b/samples/AuthServer/HostService/Program.cs deleted file mode 100644 index fd254ab5b..000000000 --- a/samples/AuthServer/HostService/Program.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Autofac; -using Surging.Core.Codec.MessagePack; -using Surging.Core.Consul; -using Surging.Core.Consul.Configurations; -using Surging.Core.CPlatform; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.DotNetty; -using Surging.Core.EventBusRabbitMQ; -using Surging.Core.ServiceHosting; -using Surging.Core.ServiceHosting.Internal.Implementation; -using System; -using System.Text; -using Surging.Core.Log4net; -using Surging.Core.ProxyGenerator; - -namespace Centa.HostService.Auth -{ - public class Program - { - static void Main(string[] args) - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - var host = new ServiceHostBuilder() - .RegisterServices(builder => - { - // builder.RegisterAssemblyModules(); - //这里写自己的注册 - }) - .RegisterServices(builder => - { - builder.AddMicroService(option => - { - option.AddServiceRuntime(); - option.AddRelateService(); - option.UseConsulManager(new ConfigInfo("127.0.0.1:8500")); - option.UseDotNettyTransport(); - option.UseRabbitMQTransport(); - option.AddRabbitMQAdapt(); - //option.UseMessagePackCodec(); - option.UseJsonCodec(); - builder.Register(p => new CPlatformContainer(ServiceLocator.Current)); - }); - }) - .SubscribeAt() - .UseLog4net("Configs/log4net.config") - .UseServer(options => - { - options.Ip = "127.0.0.1"; - options.Port = 10241; - options.Token = "True"; - options.ExecutionTimeoutInMilliseconds = 30000; - options.MaxConcurrentRequests = 200; - }) - .UseProxy() - .UseStartup() - .Build(); - - using (host.Run()) - { - Console.Title = "认证授权"; - Console.WriteLine($"认证授权——服务端启动成功,{DateTime.Now}。"); - Console.ReadLine(); - } - } - } -} diff --git a/samples/AuthServer/HostService/Startup.cs b/samples/AuthServer/HostService/Startup.cs deleted file mode 100644 index 84043e018..000000000 --- a/samples/AuthServer/HostService/Startup.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Config.Core.Extensions; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Surging.Core.Caching.Configurations; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.EventBusRabbitMQ.Configurations; -using System; - -namespace Centa.HostService.Auth -{ - public class Startup - { - public Startup() - { - var config = new ConfigurationBuilder() - .SetBasePath(AppContext.BaseDirectory); - ConfigureEventBus(config); - ConfigureCache(config); - ConfigureDB(config); - - } - - public IContainer ConfigureServices(ContainerBuilder builder) - { - var services = new ServiceCollection(); - ConfigureLogging(services); - builder.Populate(services); - ServiceLocator.Current = builder.Build(); - return ServiceLocator.Current; - } - - public void Configure(IContainer app) - { - app.Resolve().AddConsole((c, l) => (int)l >= 3); - } - - #region 私有方法 - /// - /// 配置日志服务 - /// - /// - private void ConfigureLogging(IServiceCollection services) - { - services.AddLogging(); - } - - private static void ConfigureEventBus(IConfigurationBuilder build) - { - build - .AddEventBusFile("eventBusSettings.json", optional: false); - } - - /// - /// 配置缓存服务 - /// - private void ConfigureCache(IConfigurationBuilder build) - { - build.AddCacheFile("cacheSettings.json", optional: false); - } - - private void ConfigureDB(IConfigurationBuilder build) - { - build.AddDBFile("dbSettings.json", optional: false); - } - #endregion - - } -} diff --git a/samples/AuthServer/HostService/cacheSettings.json b/samples/AuthServer/HostService/cacheSettings.json deleted file mode 100644 index ab9c7e43d..000000000 --- a/samples/AuthServer/HostService/cacheSettings.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "CachingSettings": [ - { - "Id": "ddlCache", - "Class": "Surging.Core.Caching.RedisCache.RedisContext,Surging.Core.Caching", - "Properties": [ - { - "Name": "appRuleFile", - "Ref": "rule" - }, - { - "Name": "dataContextPool", - "Ref": "ddls_sample", - "Maps": [ - { - "Name": "Redis", - "Properties": [ - { - "value": "127.0.0.1:6379::1" - } - ] - }, - { - "Name": "MemoryCache" - } - ] - }, - { - "Name": "defaultExpireTime", - "value": "120" - }, - { - "Name": "connectTimeout", - "Value": "120" - }, - { - "Name": "minSize", - "Value": "1" - }, - { - "Name": "maxSize", - "Value": "10" - } - ] - } - ] -} diff --git a/samples/AuthServer/HostService/dbSettings.json b/samples/AuthServer/HostService/dbSettings.json deleted file mode 100644 index 9903dfd68..000000000 --- a/samples/AuthServer/HostService/dbSettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionString": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Web_A2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", - "ModelAssemblyName": "Domain.Auth" -} - diff --git a/samples/AuthServer/HostService/eventBusSettings.json b/samples/AuthServer/HostService/eventBusSettings.json deleted file mode 100644 index d5d4487b7..000000000 --- a/samples/AuthServer/HostService/eventBusSettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "EventBusConnection": "localhost", - "EventBusUserName": "guest", - "EventBusPassword": "guest" -} - diff --git a/samples/AuthServer/Repository.Auth/AuthRepository.cs b/samples/AuthServer/Repository.Auth/AuthRepository.cs deleted file mode 100644 index 25ce7ba6c..000000000 --- a/samples/AuthServer/Repository.Auth/AuthRepository.cs +++ /dev/null @@ -1,48 +0,0 @@ -using DDD.Core; -using Domain.Auth.Aggregate; -using Microsoft.EntityFrameworkCore; -using Repository.EF.Core; -using Surging.Core.CPlatform.Ioc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace Repository.Auth -{ - - - - public class UserRepository : BaseImpRepository - { - public override User FindBy(Guid key) - { - return _set //.Include(a => a.Departments).ThenInclude(a => a.Employees) - .SingleOrDefault(a => a.KeyId == key); - } - } - - public class SubDomainRepository : BaseImpRepository - { - public override SubDomain FindBy(Guid key) - { - return _set //.Include(a => a.Departments).ThenInclude(a => a.Employees) - .SingleOrDefault(a => a.KeyId == key); - } - } - - public class UserQueryRepository : BaseImpQueryOnlyRepository - { - } - - public class SubDomainQueryRepository : BaseImpQueryOnlyRepository - { - - public override IQueryable Get(Expression> where = null) - { - return _set.Include(a => a.SubDomainPermissions).Where(where); - } - } - -} diff --git a/samples/AuthServer/Repository.Auth/Repository.Auth.csproj b/samples/AuthServer/Repository.Auth/Repository.Auth.csproj deleted file mode 100644 index 9fb3bffee..000000000 --- a/samples/AuthServer/Repository.Auth/Repository.Auth.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - diff --git a/samples/Common/App.Core/App.Core.csproj b/samples/Common/App.Core/App.Core.csproj deleted file mode 100644 index df1909e24..000000000 --- a/samples/Common/App.Core/App.Core.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - - - - - - - - - - - diff --git a/samples/Common/App.Core/BaseAppService.cs b/samples/Common/App.Core/BaseAppService.cs deleted file mode 100644 index a7b6e682c..000000000 --- a/samples/Common/App.Core/BaseAppService.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Repository.EF.Core; -using Surging.Core.ProxyGenerator; -using System; - -namespace App.Core -{ - public class BaseAppService : ProxyServiceBase - { - // protected BaseImpRepository _repository; - //protected QueryOrgRepository _queryOnlyRepository; - public BaseAppService()//(BaseImpRepository repository)//, QueryOrgRepository queryOnlyRepository) - { - // _repository = repository; - //_queryOnlyRepository = queryOnlyRepository; - } - } -} diff --git a/samples/Common/App.Core/Security/EncryptionService.cs b/samples/Common/App.Core/Security/EncryptionService.cs deleted file mode 100644 index 36159e03e..000000000 --- a/samples/Common/App.Core/Security/EncryptionService.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace App.Core.Security -{ - /// - /// Encryption service - /// - public class EncryptionService : IEncryptionService - { - #region Fields - - private readonly dynamic _securitySettings ; - private readonly string EncryptionKey = "loveC#loveC#loveC#"; - #endregion - - #region Ctor - public EncryptionService() - { - //_securitySettings.EncryptionKey = "loveC#"; - } - - - #endregion - - #region Utilities - - private byte[] EncryptTextToMemory(string data, byte[] key, byte[] iv) - { - using (var ms = new MemoryStream()) { - using (var cs = new CryptoStream(ms, new TripleDESCryptoServiceProvider().CreateEncryptor(key, iv), CryptoStreamMode.Write)) { - var toEncrypt = Encoding.Unicode.GetBytes(data); - cs.Write(toEncrypt, 0, toEncrypt.Length); - cs.FlushFinalBlock(); - } - - return ms.ToArray(); - } - } - - private string DecryptTextFromMemory(byte[] data, byte[] key, byte[] iv) - { - using (var ms = new MemoryStream(data)) { - using (var cs = new CryptoStream(ms, new TripleDESCryptoServiceProvider().CreateDecryptor(key, iv), CryptoStreamMode.Read)) - { - using (var sr = new StreamReader(cs, Encoding.Unicode)) - { - return sr.ReadToEnd(); - } - } - } - } - - #endregion - - #region Methods - - /// - /// Create salt key - /// - /// Key size - /// Salt key - public virtual string CreateSaltKey(int size) - { - //generate a cryptographic random number - using (var provider = new RNGCryptoServiceProvider()) - { - var buff = new byte[size]; - provider.GetBytes(buff); - - // Return a Base64 string representation of the random number - return Convert.ToBase64String(buff); - } - } - - /// - /// Create a password hash - /// - /// Password - /// Salk key - /// Password format (hash algorithm) - /// Password hash - public virtual string CreatePasswordHash(string password, string saltkey, string passwordFormat) - { - return CreateHash(Encoding.UTF8.GetBytes(string.Concat(password, saltkey)), passwordFormat); - } - - /// - /// Create a data hash - /// - /// The data for calculating the hash - /// Hash algorithm - /// Data hash - public virtual string CreateHash(byte[] data, string hashAlgorithm) - { - if (string.IsNullOrEmpty(hashAlgorithm)) - throw new ArgumentNullException(nameof(hashAlgorithm)); - - var algorithm = HashAlgorithm.Create(hashAlgorithm); - if (algorithm == null) - throw new ArgumentException("Unrecognized hash name"); - - var hashByteArray = algorithm.ComputeHash(data); - return BitConverter.ToString(hashByteArray).Replace("-", ""); - } - - /// - /// Encrypt text - /// - /// Text to encrypt - /// Encryption private key - /// Encrypted text - public virtual string EncryptText(string plainText, string encryptionPrivateKey = "") - { - if (string.IsNullOrEmpty(plainText)) - return plainText; - - if (string.IsNullOrEmpty(encryptionPrivateKey)) - encryptionPrivateKey = EncryptionKey;// _securitySettings.EncryptionKey; - - using (var provider = new TripleDESCryptoServiceProvider()) - { - provider.Key = Encoding.ASCII.GetBytes(encryptionPrivateKey.Substring(0, 16)); - provider.IV = Encoding.ASCII.GetBytes(encryptionPrivateKey.Substring(8, 8)); - - var encryptedBinary = EncryptTextToMemory(plainText, provider.Key, provider.IV); - return Convert.ToBase64String(encryptedBinary); - } - } - - /// - /// Decrypt text - /// - /// Text to decrypt - /// Encryption private key - /// Decrypted text - public virtual string DecryptText(string cipherText, string encryptionPrivateKey = "") - { - if (string.IsNullOrEmpty(cipherText)) - return cipherText; - - if (string.IsNullOrEmpty(encryptionPrivateKey)) - encryptionPrivateKey = EncryptionKey;// _securitySettings.EncryptionKey; - - using (var provider = new TripleDESCryptoServiceProvider()) - { - provider.Key = Encoding.ASCII.GetBytes(encryptionPrivateKey.Substring(0, 16)); - provider.IV = Encoding.ASCII.GetBytes(encryptionPrivateKey.Substring(8, 8)); - - var buffer = Convert.FromBase64String(cipherText); - return DecryptTextFromMemory(buffer, provider.Key, provider.IV); - } - } - - #endregion - } -} diff --git a/samples/Common/App.Core/Security/IEncryptionService.cs b/samples/Common/App.Core/Security/IEncryptionService.cs deleted file mode 100644 index 57c6af36c..000000000 --- a/samples/Common/App.Core/Security/IEncryptionService.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace App.Core.Security -{ - /// - /// Encryption service - /// - public interface IEncryptionService - { - /// - /// Create salt key - /// - /// Key size - /// Salt key - string CreateSaltKey(int size); - - /// - /// Create a password hash - /// - /// Password - /// Salk key - /// Password format (hash algorithm) - /// Password hash - string CreatePasswordHash(string password, string saltkey, string passwordFormat); - - /// - /// Create a data hash - /// - /// The data for calculating the hash - /// Hash algorithm - /// Data hash - string CreateHash(byte [] data, string hashAlgorithm); - - /// - /// Encrypt text - /// - /// Text to encrypt - /// Encryption private key - /// Encrypted text - string EncryptText(string plainText, string encryptionPrivateKey = ""); - - /// - /// Decrypt text - /// - /// Text to decrypt - /// Encryption private key - /// Decrypted text - string DecryptText(string cipherText, string encryptionPrivateKey = ""); - } -} diff --git a/samples/Common/Config.Core/Config.Core.csproj b/samples/Common/Config.Core/Config.Core.csproj deleted file mode 100644 index 89c8baf3a..000000000 --- a/samples/Common/Config.Core/Config.Core.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - netcoreapp2.0 - - - - - - - - - C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.configuration.fileextensions\2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll - - - - diff --git a/samples/Common/Config.Core/DBConfigurationExtensions.cs b/samples/Common/Config.Core/DBConfigurationExtensions.cs deleted file mode 100644 index 15a651324..000000000 --- a/samples/Common/Config.Core/DBConfigurationExtensions.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; -using Surging.Core.CPlatform.Configurations.Remote; -using Surging.Core.CPlatform.Utilities; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Config.Core.Extensions -{ - public static class DBConfigurationExtensions - { - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, string path) - { - return AddDBFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); - } - - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, string path, bool optional) - { - return AddDBFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); - } - - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) - { - return AddDBFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); - } - - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) - { - Check.NotNull(builder, "builder"); - Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); - if (provider == null && Path.IsPathRooted(path)) - { - provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); - path = Path.GetFileName(path); - } - var source = new DBConfigurationSource - { - FileProvider = provider, - Path = path, - Optional = optional, - ReloadOnChange = reloadOnChange - }; - builder.Add(source); - DBConfig.Configuration = builder.Build(); - return builder; - } - } - public class DBConfig - { - - public static IConfiguration Configuration { get; set; } - /* static ConfigHelper() - { - configuration = AutofacContainer.Resolve(); - } - - public static IConfigurationSection GetSection(string key) - { - return configuration.GetSection(key); - } - - public static string GetConfigurationValue(string key) - { - return configuration[key]; - } - - public static string GetConfigurationValue(string section, string key) - { - return GetSection(section)?[key]; - } - - public static string GetConnectionString(string key) - { - return configuration.GetConnectionString(key); - } - */ - } - - public class DBConfigurationSource : FileConfigurationSource - { - public string ConfigurationKeyPrefix { get; set; } - - public override IConfigurationProvider Build(IConfigurationBuilder builder) - { - FileProvider = FileProvider ?? builder.GetFileProvider(); - return new DBConfigurationProvider(this); - } - } - public class DBConfigurationProvider : FileConfigurationProvider - { - public DBConfigurationProvider(DBConfigurationSource source) : base(source) { } - - public override void Load(Stream stream) - { - var parser = new JsonConfigurationParser(); - this.Data = parser.Parse(stream, null); - } - } -} diff --git a/samples/Common/DDD.Core/BaseEntity.cs b/samples/Common/DDD.Core/BaseEntity.cs deleted file mode 100644 index 9093f51b4..000000000 --- a/samples/Common/DDD.Core/BaseEntity.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Text; - -namespace DDD.Core -{ - public abstract class BaseEntity : IDBModel - { - [Key] - public Guid KeyId { get; set; } - public virtual Guid CorporationKeyId { get; set; } - public virtual DateTime CreateTime { get; set; } - public virtual Guid CreateUserKeyId { get; set; } - public virtual DateTime UpdateTime { get; set; } - public virtual Guid UpdateUserKeyId { get; set; } - public virtual bool IsDelete { get; set; } - public virtual int Version { get; set; } - - //2-12增加名字、编号 - public string Name { get; set; } - - public string No { get; set; } - - public virtual void SetEditer(Guid? editer) - { - if(this.KeyId==Guid.Empty) - { - this.CreateTime = DateTime.Now; - this.CreateUserKeyId = Guid.Empty; - this.UpdateUserKeyId = Guid.Empty; - this.UpdateTime = DateTime.Now; - } - else - { - if (editer.HasValue) - { - this.UpdateUserKeyId = editer.Value; - this.UpdateTime = DateTime.Now; - } - } - } - } -} diff --git a/samples/Common/DDD.Core/BaseValueObject.cs b/samples/Common/DDD.Core/BaseValueObject.cs deleted file mode 100644 index 91399b62b..000000000 --- a/samples/Common/DDD.Core/BaseValueObject.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Text; - -namespace DDD.Core -{ - public abstract class BaseValueObject : IDBModel - { - [Key] - public Guid KeyId { get; set; } - public virtual Guid CorporationKeyId { get; set; } - public virtual DateTime CreateTime { get; set; } - public virtual Guid CreateUserKeyId { get; set; } - public virtual DateTime UpdateTime { get; set; } - public virtual Guid UpdateUserKeyId { get; set; } - public virtual bool IsDelete { get; set; } - public virtual int Version { get; set; } - - public string Name { get; set; } - - public string No { get; set; } - } -} diff --git a/samples/Common/DDD.Core/DDD.Core.Extensions/GenericExtension.cs b/samples/Common/DDD.Core/DDD.Core.Extensions/GenericExtension.cs deleted file mode 100644 index 35919f27c..000000000 --- a/samples/Common/DDD.Core/DDD.Core.Extensions/GenericExtension.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; - -namespace DDD.Core.Extensions -{ - /// - /// 泛型扩展 - /// - public static class GenericExtension - { - public static bool Equal(this T x, T y) - { - return ((IComparable)(x)).CompareTo(y) == 0; - } - - #region ToDictionary - - public static Dictionary ToDictionary(this T t, Dictionary dic = null) where T : class - { - if (dic == null) - dic = new Dictionary(); - var properties = t.GetType().GetProperties(); - foreach (var property in properties) - { - var value = property.GetValue(t, null); - dic.Add(property.Name, value?.ToString() ?? ""); - } - return dic; - } - - public static Dictionary ToDictionary(this TInterface t, Dictionary dic = null) where T : class, TInterface - { - if (dic == null) - dic = new Dictionary(); - var properties = typeof(T).GetProperties(); - foreach (var property in properties) - { - var value = property.GetValue(t, null); - if (value == null) continue; - dic.Add(property.Name, value?.ToString() ?? ""); - } - return dic; - } - - #endregion - - /// - /// 将字符串转换为指定的类型,如果转换不成功,返回默认值。 - /// - /// 结构体类型或枚举类型 - /// 需要转换的字符串 - /// 返回指定的类型。 - public static T ParseTo(this string str) where T : struct - { - return str.ParseTo(default(T)); - } - - /// - /// 将字符串转换为指定的类型,如果转换不成功,返回默认值。 - /// - /// 结构体类型或枚举类型 - /// 需要转换的字符串 - /// 如果转换失败,需要使用的默认值 - /// 返回指定的类型。 - public static T ParseTo(this string str, T defaultValue) where T : struct - { - var t = str.ParseToNullable(); - if (t.HasValue) - { - return t.Value; - } - return defaultValue; - } - - /// - /// 将字符串转换为指定的类型,如果转换不成功,返回null - /// - /// 结构体类型或枚举类型 - /// 需要转换的字符串 - /// 返回指定的类型 - public static T? ParseToNullable(this string str) where T : struct - { - if (string.IsNullOrEmpty(str)) - { - return null; - } - var typeFromHandle = typeof(T); - if (typeFromHandle.IsEnum) - { - return str.ToEnum(); - } - return (T?)str.ParseTo(typeFromHandle.FullName); - } - - public static DataTable ToDataTable(this IEnumerable source) - { - DataTable dtReturn = new DataTable(); - - // column names - PropertyInfo[] oProps = null; - - if (source == null) return dtReturn; - - foreach (var rec in source) - { - // Use reflection to get property names, to create table, Only first time, others will follow - if (oProps == null) - { - oProps = rec.GetType().GetProperties(); - foreach (var pi in oProps) - { - var colType = pi.PropertyType; - - if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) - { - colType = colType.GetGenericArguments()[0]; - } - - dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); - } - } - - var dr = dtReturn.NewRow(); - - foreach (var pi in oProps) - { - dr[pi.Name] = pi.GetValue(rec, null) == null - ? DBNull.Value - : pi.GetValue - (rec, null); - } - - dtReturn.Rows.Add(dr); - } - return dtReturn; - } - } -} diff --git a/samples/Common/DDD.Core/DDD.Core.Extensions/ObjectExtension.cs b/samples/Common/DDD.Core/DDD.Core.Extensions/ObjectExtension.cs deleted file mode 100644 index 306776e06..000000000 --- a/samples/Common/DDD.Core/DDD.Core.Extensions/ObjectExtension.cs +++ /dev/null @@ -1,1181 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using System.Text.RegularExpressions; -using System.Web; -using System.Xml; -using System.Xml.Linq; - -namespace DDD.Core.Extensions -{ - public static class ObjectExtension - { - /// - /// 将集合转换为数据集。 - /// - /// 转换的元素类型。 - /// 集合。 - /// 是否生成泛型数据集。 - /// 数据集。 - public static DataSet ToDataSet(this IEnumerable list, bool generic = true) - { - return ListToDataSet(list, generic); - } - - /// - /// 将集合转换为数据集。 - /// - /// 集合。 - /// 是否生成泛型数据集。 - /// 数据集。 - public static DataSet ToDataSet(this IEnumerable list, bool generic = true) - { - return ListToDataSet(list, generic); - } - - /// - /// 将集合转换为数据集。 - /// - /// 转换的元素类型。 - /// 集合。 - /// 是否生成泛型数据集。 - /// 数据集。 - public static DataSet ToDataSet(this IEnumerable list, bool generic = true) - { - return ListToDataSet(list, typeof(T), generic); - } - - /// - /// 将实例转换为集合数据集。 - /// - /// 实例类型。 - /// 实例。 - /// 是否生成泛型数据集。 - /// 数据集。 - public static DataSet ToListSet(this T o, bool generic = true) - { - if (o is IEnumerable) - { - return ListToDataSet(o as IEnumerable, generic); - } - else - { - return ListToDataSet(new T[] { o }, generic); - } - } - - /// - /// 将可序列化实例转换为XmlDocument。 - /// - /// 实例类型。 - /// 实例。 - /// XmlDocument。 - public static XmlDocument ToXmlDocument(this T o) - { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.InnerXml = o.ToListSet().GetXml(); - return xmlDocument; - } - - /// - /// 将集合转换为数据集。 - /// - /// 集合。 - /// 转换的元素类型。 - /// 是否生成泛型数据集。 - /// 转换后的数据集。 - private static DataSet ListToDataSet(IEnumerable list, Type t, bool generic) - { - DataSet ds = new DataSet("Data"); - if (t == null) - { - if (list != null) - { - foreach (var i in list) - { - if (i == null) - { - continue; - } - t = i.GetType(); - break; - } - } - if (t == null) - { - return ds; - } - } - ds.Tables.Add(t.Name); - //如果集合中元素为DataSet扩展涉及到的基本类型时,进行特殊转换。 - if (t.IsValueType || t == typeof(string)) - { - ds.Tables[0].TableName = "Info"; - ds.Tables[0].Columns.Add(t.Name); - if (list != null) - { - foreach (var i in list) - { - DataRow addRow = ds.Tables[0].NewRow(); - addRow[t.Name] = i; - ds.Tables[0].Rows.Add(addRow); - } - } - return ds; - } - //处理模型的字段和属性。 - var fields = t.GetFields(); - var properties = t.GetProperties(); - foreach (var j in fields) - { - if (!ds.Tables[0].Columns.Contains(j.Name)) - { - if (generic) - { - ds.Tables[0].Columns.Add(j.Name, j.FieldType); - } - else - { - ds.Tables[0].Columns.Add(j.Name); - } - } - } - foreach (var j in properties) - { - if (!ds.Tables[0].Columns.Contains(j.Name)) - { - if (generic) - { - ds.Tables[0].Columns.Add(j.Name, j.PropertyType); - } - else - { - ds.Tables[0].Columns.Add(j.Name); - } - } - } - if (list == null) - { - return ds; - } - //读取list中元素的值。 - foreach (var i in list) - { - if (i == null) - { - continue; - } - DataRow addRow = ds.Tables[0].NewRow(); - foreach (var j in fields) - { - MemberExpression field = Expression.Field(Expression.Constant(i), j.Name); - LambdaExpression lambda = Expression.Lambda(field, new ParameterExpression[] { }); - Delegate func = lambda.Compile(); - object value = func.DynamicInvoke(); - addRow[j.Name] = value; - } - foreach (var j in properties) - { - MemberExpression property = Expression.Property(Expression.Constant(i), j); - LambdaExpression lambda = Expression.Lambda(property, new ParameterExpression[] { }); - Delegate func = lambda.Compile(); - object value = func.DynamicInvoke(); - addRow[j.Name] = value; - } - ds.Tables[0].Rows.Add(addRow); - } - return ds; - } - - /// - /// 将集合转换为数据集。 - /// - /// 转换的元素类型。 - /// 集合。 - /// 是否生成泛型数据集。 - /// 数据集。 - private static DataSet ListToDataSet(IEnumerable list, bool generic) - { - return ListToDataSet(list, typeof(T), generic); - } - - /// - /// 将集合转换为数据集。 - /// - /// 集合。 - /// 是否转换为字符串形式。 - /// 转换后的数据集。 - private static DataSet ListToDataSet(IEnumerable list, bool generic) - { - return ListToDataSet(list, null, generic); - } - - /// - /// 获取DataSet第一表,第一行,第一列的值。 - /// - /// DataSet数据集。 - /// 值。 - public static object GetData(this DataSet ds) - { - if ( - ds == null - || ds.Tables.Count == 0 - ) - { - return string.Empty; - } - else - { - return ds.Tables[0].GetData(); - } - } - - /// - /// 获取DataTable第一行,第一列的值。 - /// - /// DataTable数据集表。 - /// 值。 - public static object GetData(this DataTable dt) - { - if ( - dt.Columns.Count == 0 - || dt.Rows.Count == 0 - ) - { - return string.Empty; - } - else - { - return dt.Rows[0][0]; - } - } - - /// - /// 获取DataSet第一个匹配columnName的值。 - /// - /// 数据集。 - /// 列名。 - /// 值。 - public static object GetData(this DataSet ds, string columnName) - { - if ( - ds == null - || ds.Tables.Count == 0 - ) - { - return string.Empty; - } - foreach (DataTable dt in ds.Tables) - { - object o = dt.GetData(columnName); - if (!string.IsNullOrEmpty(o.ToString())) - { - return o; - } - } - return string.Empty; - } - - /// - /// 获取DataTable第一个匹配columnName的值。 - /// - /// 数据表。 - /// 列名。 - /// 值。 - public static object GetData(this DataTable dt, string columnName) - { - if (string.IsNullOrEmpty(columnName)) - { - return GetData(dt); - } - if ( - dt.Columns.Count == 0 - || dt.Columns.IndexOf(columnName) == -1 - || dt.Rows.Count == 0 - ) - { - return string.Empty; - } - return dt.Rows[0][columnName]; - } - - /// - /// 将object转换为string类型信息。 - /// - /// object。 - /// 默认值。 - /// string。 - public static string ToString(this object o, string t) - { - string info = string.Empty; - if (o == null) - { - info = t; - } - else - { - info = o.ToString(); - } - return info; - } - - /// - /// 将DateTime?转换为string类型信息。 - /// - /// DateTime?。 - /// 标准或自定义日期和时间格式的字符串。 - /// 默认值。 - /// string。 - public static string ToString(this DateTime? o, string format, string t) - { - string info = string.Empty; - if (o == null) - { - info = t; - } - else - { - info = o.Value.ToString(format); - } - return info; - } - - /// - /// 将TimeSpan?转换为string类型信息。 - /// - /// TimeSpan?。 - /// 标准或自定义时间格式的字符串。 - /// 默认值。 - /// string。 - public static string ToString(this TimeSpan? o, string format, string t) - { - string info = string.Empty; - if (o == null) - { - info = t; - } - else - { - info = o.Value.ToString(format); - } - return info; - } - - /// - /// 将object转换为截取后的string类型信息。 - /// - /// object。 - /// 此实例中子字符串的起始字符位置(从零开始)。 - /// 子字符串中的字符数。 - /// 后缀。如果没有截取则不添加。 - /// 截取后的string类型信息。 - public static string ToSubString(this object o, int startIndex, int length, string suffix = null) - { - string inputString = o.ToString(string.Empty); - startIndex = Math.Max(startIndex, 0); - startIndex = Math.Min(startIndex, (inputString.Length - 1)); - length = Math.Max(length, 1); - if (startIndex + length > inputString.Length) - { - length = inputString.Length - startIndex; - } - if (inputString.Length == startIndex + length) - { - return inputString; - } - else - { - return inputString.Substring(startIndex, length) + suffix; - } - } - - /// - /// 将object转换为byte类型信息。 - /// - /// object。 - /// 默认值。 - /// byte。 - public static byte ToByte(this object o, byte t = default(byte)) - { - byte info; - if (!byte.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - public static byte[] ToBytes(this object obj) - { - if (obj == null) - return null; - var bf = new BinaryFormatter(); - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, obj); - return ms.ToArray(); - } - } - - public static object ToObject(this byte[] source) - { - using (var memStream = new MemoryStream()) - { - var bf = new BinaryFormatter(); - memStream.Write(source, 0, source.Length); - memStream.Seek(0, SeekOrigin.Begin); - var obj = bf.Deserialize(memStream); - return obj; - } - } - - /// - /// 将object转换为char类型信息。 - /// - /// object。 - /// 默认值。 - /// char。 - public static char ToChar(this object o, char t = default(char)) - { - char info; - if (!char.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为int类型信息。 - /// - /// object。 - /// 默认值。 - /// int。 - public static int ToInt(this object o, int t = default(int)) - { - int info; - if (!int.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为double类型信息。 - /// - /// object。 - /// 默认值。 - /// double。 - public static double ToDouble(this object o, double t = default(double)) - { - double info; - if (!double.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为decimal类型信息。 - /// - /// object。 - /// 默认值。 - /// decimal。 - public static decimal ToDecimal(this object o, decimal t = default(decimal)) - { - decimal info; - if (!decimal.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为float类型信息。 - /// - /// object。 - /// 默认值。 - /// float。 - public static float ToFloat(this object o, float t = default(float)) - { - float info; - if (!float.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为long类型信息。 - /// - /// object。 - /// 默认值。 - /// long。 - public static long ToLong(this object o, long t = default(long)) - { - long info; - if (!long.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为bool类型信息。 - /// - /// object。 - /// 默认值。 - /// bool。 - public static bool ToBool(this object o, bool t = default(bool)) - { - bool info; - if (!bool.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为sbyte类型信息。 - /// - /// object。 - /// 默认值。 - /// sbyte。 - public static sbyte ToSbyte(this object o, sbyte t = default(sbyte)) - { - sbyte info; - if (!sbyte.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为short类型信息。 - /// - /// object。 - /// 默认值。 - /// short。 - public static short ToShort(this object o, short t = default(short)) - { - short info; - if (!short.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为ushort类型信息。 - /// - /// object。 - /// 默认值。 - /// ushort。 - public static ushort ToUShort(this object o, ushort t = default(ushort)) - { - ushort info; - if (!ushort.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为ulong类型信息。 - /// - /// object。 - /// 默认值。 - /// ulong。 - public static ulong ToULong(this object o, ulong t = default(ulong)) - { - ulong info; - if (!ulong.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为Enum[T]类型信息。 - /// - /// object。 - /// 默认值。 - /// Enum[T]。 - public static T ToEnum(this object o, T t = default(T)) - where T : struct - { - T info; - if (!Enum.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为DateTime类型信息。 - /// - /// object。 - /// 默认值。 - /// DateTime。 - public static DateTime ToDateTime(this object o, DateTime t = default(DateTime)) - { - if (t == default(DateTime)) - { - t = new DateTime(1753, 1, 1); - } - DateTime info; - if (!DateTime.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为TimeSpan类型信息。 - /// - /// object。 - /// 默认值。 - /// TimeSpan。 - public static TimeSpan ToTimeSpan(this object o, TimeSpan t = default(TimeSpan)) - { - if (t == default(TimeSpan)) - { - t = new TimeSpan(0, 0, 0); - } - TimeSpan info; - if (!TimeSpan.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - /// - /// 将object转换为Guid类型信息。 - /// - /// object。 - /// 默认值。 - /// Guid。 - public static Guid ToGuid(this object o, Guid t = default(Guid)) - { - Guid info; - if (!Guid.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - return info; - } - - private static Regex BoolRegex = new Regex("(?(true|false))", RegexOptions.IgnoreCase | RegexOptions.Singleline); - - /// - /// 从object中获取bool类型信息。 - /// - /// object。 - /// bool。 - public static bool? GetBool(this object o) - { - bool info; - if (!bool.TryParse(BoolRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return info; - } - - private static Regex IntRegex = new Regex("(?-?\\d+)", RegexOptions.IgnoreCase | RegexOptions.Singleline); - - /// - /// 从object中获取int类型信息。 - /// - /// object。 - /// int。 - public static int? GetInt(this object o) - { - int info; - if (!int.TryParse(IntRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return info; - } - - private static Regex DecimalRegex = new Regex("(?-?\\d+(\\.\\d+)?)", RegexOptions.IgnoreCase | RegexOptions.Singleline); - - /// - /// 从object中获取decimal类型信息。 - /// - /// object。 - /// decimal。 - public static decimal? GetDecimal(this object o) - { - decimal info; - if (!decimal.TryParse(DecimalRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return info; - } - - /// - /// 从object中获取double类型信息。 - /// - /// object。 - /// double。 - public static double? GetDouble(this object o) - { - double info; - if (!double.TryParse(DecimalRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return info; - } - - /// - /// 从object中获取正数信息。 - /// - /// object。 - /// decimal。 - public static decimal? GetPositiveNumber(this object o) - { - decimal info; - if (!decimal.TryParse(DecimalRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return Math.Abs(info); - } - - private static Regex DateTimeRegex = new Regex("(?(((\\d+)[/年-](0?[13578]|1[02])[/月-](3[01]|[12]\\d|0?\\d)[日]?)|((\\d+)[/年-](0?[469]|11)[/月-](30|[12]\\d|0?\\d)[日]?)|((\\d+)[/年-]0?2[/月-](2[0-8]|1\\d|0?\\d)[日]?))(\\s((2[0-3]|[0-1]\\d)):[0-5]\\d:[0-5]\\d)?)", RegexOptions.IgnoreCase | RegexOptions.Singleline); - - /// - /// 从object中获取DateTime?类型信息。 - /// - /// object。 - /// DateTime?。 - public static DateTime? GetDateTime(this object o) - { - DateTime info; - if (!DateTime.TryParse(DateTimeRegex.Match(o.ToString(string.Empty)).Groups["info"].Value.Replace("年", "-").Replace("月", "-").Replace("/", "-").Replace("日", ""), out info)) - { - return null; - } - return info; - } - - private static Regex TimeSpanRegex = new Regex("(?-?(\\d+\\.(([0-1]\\d)|(2[0-3])):[0-5]\\d:[0-5]\\d)|((([0-1]\\d)|(2[0-3])):[0-5]\\d:[0-5]\\d)|(\\d+))", RegexOptions.IgnoreCase | RegexOptions.Singleline); - - /// - /// 从object中获取TimeSpan?类型信息。 - /// - /// object。 - /// TimeSpan?。 - public static TimeSpan? GetTimeSpan(this object o) - { - TimeSpan info; - if (!TimeSpan.TryParse(TimeSpanRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return info; - } - - private static Regex GuidRegex = new Regex("(?\\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\\}{0,1})", RegexOptions.IgnoreCase | RegexOptions.Singleline); - - /// - /// 从object中获取Guid?类型信息。 - /// - /// object。 - /// Guid?。 - public static Guid? GetGuid(this object o) - { - Guid info; - if (!Guid.TryParse(GuidRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out info)) - { - return null; - } - return info; - } - - /// - /// 将object转换为SqlServer中的DateTime?类型信息。 - /// - /// object。 - /// 默认值。 - /// DateTime?。 - public static DateTime? GetSqlDateTime(this object o, DateTime t = default(DateTime)) - { - DateTime info; - if (!DateTime.TryParse(o.ToString(string.Empty), out info)) - { - info = t; - } - if (info < new DateTime(1753, 1, 1) || info > new DateTime(9999, 12, 31)) - { - return null; - } - return info; - } - - /// - /// 读取XElement节点的文本内容。 - /// - /// XElement节点。 - /// 默认值。 - /// 文本内容。 - public static string Value(this XElement xElement, string t = default(string)) - { - if (xElement == null) - { - return t; - } - else - { - return xElement.Value; - } - } - - /// - /// 获取与指定键相关的值。 - /// - /// 键类型。 - /// 值类型。 - /// 表示键/值对象的泛型集合。 - /// 键。 - /// 默认值。 - /// 值。 - public static TValue GetValue(this IDictionary dictionary, TKey key, TValue t = default(TValue)) - { - TValue value = default(TValue); - if (dictionary == null || key == null) - { - return t; - } - if (!dictionary.TryGetValue(key, out value)) - { - value = t; - } - return value; - } - - /// - /// 获取与指定键相关或者第一个的值。 - /// - /// 键类型。 - /// 值类型。 - /// 表示键/值对象的泛型集合。 - /// 键。 - /// 默认值。 - /// 值。 - public static TValue GetFirstOrDefaultValue(this IDictionary dictionary, TKey key, TValue t = default(TValue)) - { - TValue value = default(TValue); - if (dictionary == null || key == null) - { - return t; - } - if (!dictionary.TryGetValue(key, out value)) - { - if (dictionary.Count() == 0) - { - value = t; - } - else - { - value = dictionary.FirstOrDefault().Value; - } - } - return value; - } - - /// - /// 获取具有指定 System.Xml.Linq.XName 的第一个(按文档顺序)子元素。 - /// - /// XContainer。 - /// 要匹配的 System.Xml.Linq.XName。 - /// 是否返回同名默认值。 - /// 与指定 System.Xml.Linq.XName 匹配的 System.Xml.Linq.XElement,或者为 null。 - public static XElement Element(this XContainer xContainer, XName xName, bool t) - { - XElement info; - if (xContainer == null) - { - info = null; - } - else - { - info = xContainer.Element(xName); - } - if (t && info == null) - { - info = new XElement(xName); - } - return info; - } - - /// - /// 按文档顺序返回此元素或文档的子元素集合。 - /// - /// XContainer。 - /// 是否返回非空默认值。 - /// System.Xml.Linq.XElement 的按文档顺序包含此System.Xml.Linq.XContainer 的子元素,或者非空默认值。 - public static IEnumerable Elements(this XContainer xContainer, bool t) - { - IEnumerable info; - if (xContainer == null) - { - info = null; - } - else - { - info = xContainer.Elements(); - } - if (t && info == null) - { - info = new List(); - } - return info; - } - - /// - /// 按文档顺序返回此元素或文档的经过筛选的子元素集合。集合中只包括具有匹配 System.Xml.Linq.XName 的元素。 - /// - /// XContainer。 - /// 要匹配的 System.Xml.Linq.XName。 - /// 是否返回非空默认值。 - /// System.Xml.Linq.XElement 的按文档顺序包含具有匹配System.Xml.Linq.XName 的 System.Xml.Linq.XContainer 的子级,或者非空默认值。 - public static IEnumerable Elements(this XContainer xContainer, XName xName, bool t) - { - IEnumerable info; - if (xContainer == null) - { - info = null; - } - else - { - info = xContainer.Elements(xName); - } - if (t && info == null) - { - info = new List(); - } - return info; - } - - /// - /// 删除html标签。 - /// - /// 输入的字符串。 - /// 没有html标签的字符串。 - public static string RemoveHTMLTags(this string html) - { - return Regex.Replace(Regex.Replace(Regex.Replace((html ?? string.Empty).Replace(" ", " ").Replace("\r\n", " ").Replace("\n", " ").Replace("\r", " ").Replace("\t", " "), "<\\/?[^>]+>", "\r\n"), "(\r\n)+", "\r\n"), "(\\s)+", " ").Trim(); - } - - /// - /// 字符串转换为文件名。 - /// - /// 字符串。 - /// 文件名。 - public static string ToFileName(this string s) - { - return Regex.Replace(s.ToString(string.Empty), @"[\\/:*?<>|]", "_").Replace("\t", " ").Replace("\r\n", " ").Replace("\"", " "); - } - - /// - /// 获取星期一的日期。 - /// - /// 日期。 - /// 星期一的日期。 - public static DateTime? GetMonday(this DateTime dateTime) - { - return dateTime.AddDays(-1 * (int)dateTime.AddDays(-1).DayOfWeek).ToString("yyyy-MM-dd").GetDateTime(); - } - - /// - /// 获取默认非空字符串。 - /// - /// 首选默认非空字符串。 - /// 依次非空字符串可选项。 - /// 默认非空字符串。若无可选项则返回string.Empty。 - public static string DefaultStringIfEmpty(this string s, params string[] args) - { - if (string.IsNullOrEmpty(s)) - { - foreach (string i in args) - { - if (!string.IsNullOrEmpty(i) && !string.IsNullOrEmpty(i.Trim())) - { - return i; - } - } - } - return (s ?? string.Empty); - } - - /// - /// 对 URL 字符串进行编码。 - /// - /// 要编码的文本。 - /// 匹配要编码的文本。 - /// 指定编码方案的 System.Text.Encoding 对象。 - /// 一个已编码的字符串。 - public static string ToUrlEncodeString(this string s, Regex regex = default(Regex), Encoding encoding = null) - { - if (encoding == null) - { - encoding = Encoding.UTF8; - } - if (regex == null) - { - return HttpUtility.UrlEncode(s, encoding); - } - List l = new List(); - foreach (char i in s) - { - string t = i.ToString(); - l.Add(regex.IsMatch(t) ? HttpUtility.UrlEncode(t, encoding) : t); - } - return string.Join(string.Empty, l); - } - - /// - /// 对 URL 字符串进行编码。 - /// - /// 要编码的文本。 - /// 匹配要编码的文本。 - /// 指定编码方案的 System.Text.Encoding 对象。 - /// 一个已编码的字符串。 - public static string ToUrlEncodeString(this string s, string regex, Encoding encoding = null) - { - return ToUrlEncodeString(s, new Regex(regex), encoding); - } - - /// - /// 将日期转换为UNIX时间戳字符串 - /// - /// - /// - public static string ToUnixTimeStamp(this DateTime date) - { - DateTime startTime = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1)); - string timeStamp = date.Subtract(startTime).Ticks.ToString(); - return timeStamp.Substring(0, timeStamp.Length - 7); - } - - private static Regex MobileRegex = new Regex("^1[3|4|5|7|8][0-9]\\d{4,8}$"); - private static Regex EmailRegex = new Regex("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})$"); - - /// - /// 判断当前字符串是否是移动电话号码 - /// - /// - /// - public static bool IsMobile(this string mobile) - { - return MobileRegex.IsMatch(mobile); - } - - /// - /// 判断当前字符串是否为邮箱 - /// - /// - /// - public static bool IsEmail(this string email) - { - return EmailRegex.IsMatch(email); - } - } - - /// - /// 结果。 - /// - /// 结果返回值类型。 - public class Result - { - /// - /// 标记。 - /// - public Flag Flag { get; set; } - - /// - /// 返回值。 - /// - public T Return { get; set; } - - /// - /// 消息。 - /// - public string Message { get; set; } - - /// - /// 异常。 - /// - public Exception Exception { get; set; } - - /// - /// 时间。 - /// - public DateTime DateTime { get; set; } - - /// - /// 整型数据。 - /// - public int Int { get; set; } - - /// - /// 浮点数据。 - /// - public decimal Decimal { get; set; } - - /// - /// 布尔数据。 - /// - public bool Bool { get; set; } - - /// - /// 对象。 - /// - public object Object { get; set; } - } - - /// - /// 标记。 - /// - public enum Flag - { - /// - /// 默认。 - /// - Default, - - /// - /// 真。 - /// - True, - - /// - /// 假。 - /// - False - } -} \ No newline at end of file diff --git a/samples/Common/DDD.Core/DDD.Core.Extensions/StringExtensions.cs b/samples/Common/DDD.Core/DDD.Core.Extensions/StringExtensions.cs deleted file mode 100644 index b1c191880..000000000 --- a/samples/Common/DDD.Core/DDD.Core.Extensions/StringExtensions.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System; -using System.Text.RegularExpressions; - -namespace DDD.Core.Extensions -{ - public static class StringExtensions - { - public static object ParseTo(this string str, string type) - { - switch (type) - { - case "System.Boolean": - return ToBoolean(str); - case "System.SByte": - return ToSByte(str); - case "System.Byte": - return ToByte(str); - case "System.UInt16": - return ToUInt16(str); - case "System.Int16": - return ToInt16(str); - case "System.uInt32": - return ToUInt32(str); - case "System.Int32": - return str.ToInt32(); - case "System.UInt64": - return ToUInt64(str); - case "System.Int64": - return ToInt64(str); - case "System.Single": - return ToSingle(str); - case "System.Double": - return ToDouble(str); - case "System.Decimal": - return ToDecimal(str); - case "System.DateTime": - return ToDateTime(str); - case "System.Guid": - return ToGuid(str); - } - throw new NotSupportedException(string.Format("The string of \"{0}\" can not be parsed to {1}", str, type)); - } - - public static sbyte? ToSByte(this string value) - { - sbyte value2; - if (sbyte.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static byte? ToByte(this string value) - { - byte value2; - if (byte.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static ushort? ToUInt16(this string value) - { - ushort value2; - if (ushort.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static short? ToInt16(this string value) - { - short value2; - if (short.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static uint? ToUInt32(this string value) - { - uint value2; - if (uint.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static ulong? ToUInt64(this string value) - { - ulong value2; - if (ulong.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static long? ToInt64(this string value) - { - long value2; - if (long.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static float? ToSingle(this string value) - { - float value2; - if (float.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static double? ToDouble(this string value) - { - double value2; - if (double.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static decimal? ToDecimal(this string value) - { - decimal value2; - if (decimal.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static bool? ToBoolean(this string value) - { - bool value2; - if (bool.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static T? ToEnum(this string str) where T : struct - { - T t; - if (Enum.TryParse(str, true, out t) && Enum.IsDefined(typeof(T), t)) - { - return t; - } - return null; - } - - public static Guid? ToGuid(this string str) - { - Guid value; - if (Guid.TryParse(str, out value)) - { - return value; - } - return null; - } - - public static DateTime? ToDateTime(this string value) - { - DateTime value2; - if (DateTime.TryParse(value, out value2)) - { - return value2; - } - return null; - } - - public static int? ToInt32(this string input) - { - if (string.IsNullOrEmpty(input)) - { - return null; - } - int value; - if (int.TryParse(input, out value)) - { - return value; - } - return null; - } - - /// - /// 替换空格字符 - /// - /// - /// 替换为该字符 - /// 替换后的字符串 - public static string ReplaceWhitespace(this string input, string replacement = "") - { - return string.IsNullOrEmpty(input) ? null : Regex.Replace(input, "\\s", replacement, RegexOptions.Compiled); - } - - /// - /// 返回一个值,该值指示指定的 String 对象是否出现在此字符串中。 - /// - /// - /// 要搜寻的字符串。 - /// 指定搜索规则的枚举值之一。 - /// 如果 value 参数出现在此字符串中则为 true;否则为 false。 - public static bool Contains(this string source, string value, - StringComparison comparisonType = StringComparison.OrdinalIgnoreCase) - { - return source.IndexOf(value, comparisonType) >= 0; - } - - /// - /// 清除 Html 代码,并返回指定长度的文本。(连续空行或空格会被替换为一个) - /// - /// - /// 返回的文本长度(为0返回所有文本) - /// - public static string StripHtml(this string text, int maxLength = 0) - { - if (string.IsNullOrEmpty(text)) return string.Empty; - text = text.Trim(); - - text = Regex.Replace(text, "[\\r\\n]{2,}", "<&rn>"); //替换回车和换行为<&rn>,防止下一行代码替换空格的时候被替换掉 - text = Regex.Replace(text, "[\\s]{2,}", " "); //替换 2 个以上的空格为 1 个 - text = Regex.Replace(text, "(<&rn>)+", "\n"); //还原 <&rn> 为 \n - text = Regex.Replace(text, "(\\s*&[n|N][b|B][s|S][p|P];\\s*)+", " "); //  - - text = Regex.Replace(text, "(<[b|B][r|R]/*>)+|(<[p|P](.|\\n)*?>)", "\n"); //
- text = Regex.Replace(text, "<(.|\n)+?>", " ", RegexOptions.IgnoreCase); //any other tags - - if (maxLength > 0 && text.Length > maxLength) - text = text.Substring(0, maxLength); - - return text; - } - } -} diff --git a/samples/Common/DDD.Core/DDD.Core.csproj b/samples/Common/DDD.Core/DDD.Core.csproj deleted file mode 100644 index 3cfd4024c..000000000 --- a/samples/Common/DDD.Core/DDD.Core.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netstandard2.0 - - - - - - - - - - - - - C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.configuration.abstractions\2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll - - - C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.fileproviders.physical\2.0.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll - - - - diff --git a/samples/Common/DDD.Core/IAggregate.cs b/samples/Common/DDD.Core/IAggregate.cs deleted file mode 100644 index 0edd419b1..000000000 --- a/samples/Common/DDD.Core/IAggregate.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace DDD.Core -{ - - /// Represents an aggregate root. - /// - public abstract class IAggregate: IDBModel - { - [Key] - public virtual Guid KeyId { get; set; } - /// - /// 归属公司 - /// - public virtual Guid CorporationKeyId { get; set; } - public DateTime CreateTime { get; set; } - public Guid CreateUserKeyId { get; set; } - public DateTime UpdateTime { get; set; } - public Guid UpdateUserKeyId { get; set; } - public bool IsDelete { get; set; } - public int Version { get; set; } - - public string Name { get; set; } - - public string No { get; set; } - } -} diff --git a/samples/Common/DDD.Core/IQueryOnlyRepository.cs b/samples/Common/DDD.Core/IQueryOnlyRepository.cs deleted file mode 100644 index 0d17da9b7..000000000 --- a/samples/Common/DDD.Core/IQueryOnlyRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace DDD.Core -{ - /// - /// 只读的查询资源库接口 - /// - public interface IQueryOnlyRepository where T : class,IDBModel - { - - int Count(Expression> @where = null); - - bool Exist(Expression> @where = null); - bool Exist(Expression> @where = null, params Expression>[] includes); - int ExecuteSqlWithNonQuery(string sql, params object[] parameters); - T GetSingle(TKey key); - T GetSingle(TKey key, params Expression>[] includes); - T GetSingle(Expression> @where = null); - T GetSingle(Expression> @where = null, params Expression>[] includes); - IQueryable Get(Expression> @where = null); - IQueryable Get(Expression> @where = null, params Expression>[] includes); - IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, - Expression>[] include,bool asc = true, params Func[] @orderby); - - IList SqlQuery(string sql, params object[] parameters) where TView : class, new(); - - - } -} diff --git a/samples/Common/DDD.Core/IRepository.cs b/samples/Common/DDD.Core/IRepository.cs deleted file mode 100644 index 8d0d5ac01..000000000 --- a/samples/Common/DDD.Core/IRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace DDD.Core -{ - public interface IDBModel - { - TKey KeyId { get; set; } - - TKey CorporationKeyId { get; set; } - DateTime CreateTime { get; set; } - TKey CreateUserKeyId { get; set; } - DateTime UpdateTime { get; set; } - TKey UpdateUserKeyId { get; set; } - bool IsDelete { get; set; } - int Version { get; set; } - - - } - public interface IRepository: IUnitOfWork where T : IAggregate - { - void Add(T aggregate); //where T : IAggregate; - T FindBy(TKey key); //where T : IAggregate; - void Update(T aggregate); //where T : IAggregate; - void Delete(TKey key); - - - } -} diff --git a/samples/Common/DDD.Core/IUnitOfWork.cs b/samples/Common/DDD.Core/IUnitOfWork.cs deleted file mode 100644 index d687b586b..000000000 --- a/samples/Common/DDD.Core/IUnitOfWork.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace DDD.Core -{ - public interface IUnitOfWork: IDisposable - { - #region for transaction - /// - /// 提交一个聚合内的所有变更 - /// - /// - /// If the entity have fixed properties and any optimistic concurrency problem exists, - /// then an exception is thrown - /// - int Commit(); - - - #endregion - - // int SaveChanges(); - //int SaveChangesAsync(); - - } -} diff --git a/samples/Common/DTO.Core/BasePagedRequestDto.cs b/samples/Common/DTO.Core/BasePagedRequestDto.cs deleted file mode 100644 index 03a9bbd71..000000000 --- a/samples/Common/DTO.Core/BasePagedRequestDto.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - public class BasePagedRequestDto: BaseRequestDto - { - /// - /// 页码号,从1开始,可空(返回全部记录) - /// - public int PageIndex { get; set; } - - /// - /// 每页显示的记录数,可空(返回全部记录) - /// - public int PageSize { get; set; } - } -} diff --git a/samples/Common/DTO.Core/BaseRequestDto.cs b/samples/Common/DTO.Core/BaseRequestDto.cs deleted file mode 100644 index 9220bf810..000000000 --- a/samples/Common/DTO.Core/BaseRequestDto.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - /// - /// 接口参数 dto抽象基类 - /// - public abstract class BaseRequestDto : BaseDto - { - /// - /// 服务访问身份信息 - /// - public TokenDto Identify { get; set; } - - - } - /// - /// 实体的增、删、改 - /// - public class EntityCUDReq : BaseRequestDto - { - public Guid? KeyId { get; set; } - } - /// - /// 实体上的命令 - /// - public class EntityCMDReq : BaseRequestDto - { - - } - - /// - /// 简单的请求 - /// 参数不确定 - /// - public class CommonCMDReq : BaseRequestDto - { - public string CommonCMD { get; set; } - } - - - /// - /// 树形列表的搜索 - /// - public class BaseTreeSearchReq : BaseRequestDto - { - /// - /// 搜索条件 - /// - public string SearchKey { get; set; } - - } -} diff --git a/samples/Common/DTO.Core/BaseResponseDto.cs b/samples/Common/DTO.Core/BaseResponseDto.cs deleted file mode 100644 index 4cada02d1..000000000 --- a/samples/Common/DTO.Core/BaseResponseDto.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - public class BaseResponseDto:BaseDto - { - /// - /// 请求结果,请求成功/失败 - /// - public bool OperateFlag { get; set; } - - /// - /// 服务端错误信息 - /// - public string FlagErrorMsg { get; set; } - - - } - - public class BaseTreeResponseDto: BaseResponseDto - { - public List Tree { get; set; } - } - - public class BaseTreeDto - { - public string Id { get; set; } - public string PId { get; set; } - public string Name { get; set; } - } - - public class BaseListResponseDto : BaseResponseDto - { - public dynamic Result { get; set; } - } - -} diff --git a/samples/Common/DTO.Core/BaseSortCriteriaDto.cs b/samples/Common/DTO.Core/BaseSortCriteriaDto.cs deleted file mode 100644 index bb0b01142..000000000 --- a/samples/Common/DTO.Core/BaseSortCriteriaDto.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - /// - /// 搜索条件排序基类Dto。 - /// - public abstract class BaseSortCriteriaDto : BaseDto - { - /// - /// 创建时间 - /// - - public static readonly string CREATE_TIME = "CreateTime"; - - /// - /// 修改时间 - /// - - public static readonly string UPDATE_TIME = "UpdateTime"; - - /// - /// 正向/反向排序 - /// - - public bool Ascending { set; get; } - - /// - /// 排序名称 - /// - - public string SortPropertyName { set; get; } - } -} diff --git a/samples/Common/DTO.Core/DTO.Core.csproj b/samples/Common/DTO.Core/DTO.Core.csproj deleted file mode 100644 index 5766db614..000000000 --- a/samples/Common/DTO.Core/DTO.Core.csproj +++ /dev/null @@ -1,7 +0,0 @@ - - - - netcoreapp2.0 - - - diff --git a/samples/Common/DTO.Core/IdentifyDto.cs b/samples/Common/DTO.Core/IdentifyDto.cs deleted file mode 100644 index 61a276b6e..000000000 --- a/samples/Common/DTO.Core/IdentifyDto.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - public abstract class BaseDto - { - - } - public class TokenDto: BaseDto - { - /// - /// 员工编号 - /// - public string Token { get; set; } - public Guid CorporationKeyId { get; set; } - - } - public class IdentifyDto : BaseDto - { - /// - /// 当前用户keyId - /// - - public Guid UserKeyId { get; set; } - - /// - /// 当前用户名 - /// - - public string UserName { get; set; } - - /// - /// 当前用户部门keyId - /// - - public Guid DepartmentKeyId { get; set; } - - /// - /// 部门编号 - /// - - public string DepartmentNo { get; set; } - - /// - /// 当前用户部门名称 - /// - - public string DepartmentName { get; set; } - - /// - /// 当前用户所属公司keyId - /// - - public Guid CorporationKeyId { get; set; } - - - /// - /// 用户登录方式 - /// - - public string LoginType { get; set; } - - /// - /// 用户账号 - /// - - public string UserNo { get; set; } - - /// - /// 当前用户手机号 - /// - - public string UserPhone { get; set; } - - /// - /// 角色code - /// - - public string RoleCode { get; set; } - - /// - /// 角色名称 - /// - - public string RoleName { get; set; } - } - } diff --git a/samples/Common/DTO.Core/KeyIdReq.cs b/samples/Common/DTO.Core/KeyIdReq.cs deleted file mode 100644 index aebc1b302..000000000 --- a/samples/Common/DTO.Core/KeyIdReq.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - public class KeyIdReq:BaseRequestDto - { - public Guid KeyId { get; set; } - } -} diff --git a/samples/Common/DTO.Core/OperateResultDto.cs b/samples/Common/DTO.Core/OperateResultDto.cs deleted file mode 100644 index a8a88f3f4..000000000 --- a/samples/Common/DTO.Core/OperateResultDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DTO.Core -{ - public class OperateResultRsp : BaseResponseDto - { - /// - /// 操作结果 - /// - public string OperateResult { get; set; } - - } -} diff --git a/samples/Common/Repository.Dapper.Core/BaseImpQueryOnlyRepository.cs b/samples/Common/Repository.Dapper.Core/BaseImpQueryOnlyRepository.cs deleted file mode 100644 index 614dbd9a3..000000000 --- a/samples/Common/Repository.Dapper.Core/BaseImpQueryOnlyRepository.cs +++ /dev/null @@ -1,72 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace Repository.Dapper.Core -{ - public class BaseImpQueryOnlyRepository : IQueryOnlyRepository where T : class, IDBModel - { - public int Count(Expression> where = null) - { - throw new NotImplementedException(); - } - - public int ExecuteSqlWithNonQuery(string sql, params object[] parameters) - { - throw new NotImplementedException(); - } - - public bool Exist(Expression> where = null) - { - throw new NotImplementedException(); - } - - public bool Exist(Expression> where = null, params Expression>[] includes) - { - throw new NotImplementedException(); - } - - public IQueryable Get(Expression> where = null) - { - throw new NotImplementedException(); - } - - public IQueryable Get(Expression> where = null, params Expression>[] includes) - { - throw new NotImplementedException(); - } - - public IEnumerable GetByPagination(Expression> where, int pageSize, int pageIndex, Expression>[] include, bool asc = true, params Func[] orderby) - { - throw new NotImplementedException(); - } - - public T GetSingle(Guid key) - { - throw new NotImplementedException(); - } - - public T GetSingle(Guid key, params Expression>[] includes) - { - throw new NotImplementedException(); - } - - public T GetSingle(Expression> where = null) - { - throw new NotImplementedException(); - } - - public T GetSingle(Expression> where = null, params Expression>[] includes) - { - throw new NotImplementedException(); - } - - public IList SqlQuery(string sql, params object[] parameters) where TView : class, new() - { - throw new NotImplementedException(); - } - } -} diff --git a/samples/Common/Repository.Dapper.Core/BaseImpRepository.cs b/samples/Common/Repository.Dapper.Core/BaseImpRepository.cs deleted file mode 100644 index a22e182ad..000000000 --- a/samples/Common/Repository.Dapper.Core/BaseImpRepository.cs +++ /dev/null @@ -1,40 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Repository.Dapper.Core -{ - public class BaseImpRepository : IRepository where T : IAggregate - { - public void Add(T aggregate) - { - throw new NotImplementedException(); - } - - public int Commit() - { - throw new NotImplementedException(); - } - - public void Delete(Guid key) - { - throw new NotImplementedException(); - } - - public void Dispose() - { - throw new NotImplementedException(); - } - - public T FindBy(Guid key) - { - throw new NotImplementedException(); - } - - public void Update(T aggregate) - { - throw new NotImplementedException(); - } - } -} diff --git a/samples/Common/Repository.Dapper.Core/DapperExtensions.cs b/samples/Common/Repository.Dapper.Core/DapperExtensions.cs deleted file mode 100644 index 61b4a2146..000000000 --- a/samples/Common/Repository.Dapper.Core/DapperExtensions.cs +++ /dev/null @@ -1,567 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Reflection; -using System.Text; -using Repository.Dapper.Core.Sql; -using Repository.Dapper.Core.Mapper; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Repository.Dapper.Core -{ - public static class DapperExtensions - { - #region other - private readonly static object _lock = new object(); - - private static Func _instanceFactory; - private static IDapperImplementor _instance; - private static IDapperExtensionsConfiguration _configuration; - - /// - /// Gets or sets the default class mapper to use when generating class maps. If not specified, AutoClassMapper is used. - /// Repository.Dapper.Core.Configure(Type, IList, ISqlDialect) can be used instead to set all values at once - /// - public static Type DefaultMapper - { - get - { - return _configuration.DefaultMapper; - } - - set - { - Configure(value, _configuration.MappingAssemblies, _configuration.Dialect); - } - } - - /// - /// Gets or sets the type of sql to be generated. - /// DapperExtensions.Configure(Type, IList, ISqlDialect) can be used instead to set all values at once - /// - public static ISqlDialect SqlDialect - { - get - { - return _configuration.Dialect; - } - - set - { - Configure(_configuration.DefaultMapper, _configuration.MappingAssemblies, value); - } - } - - /// - /// Get or sets the Dapper Extensions Implementation Factory. - /// - public static Func InstanceFactory - { - get - { - if (_instanceFactory == null) - { - _instanceFactory = config => new DapperImplementor(new SqlGeneratorImpl(config)); - } - - return _instanceFactory; - } - set - { - _instanceFactory = value; - Configure(_configuration.DefaultMapper, _configuration.MappingAssemblies, _configuration.Dialect); - } - } - - /// - /// Gets the Dapper Extensions Implementation - /// - private static IDapperImplementor Instance - { - get - { - if (_instance == null) - { - lock (_lock) - { - if (_instance == null) - { - _instance = InstanceFactory(_configuration); - } - } - } - - return _instance; - } - } - - //static DapperExtensions() - //{ - // Configure(typeof(AutoClassMapper<>), new List(), new SqlServerDialect()); - //} - - /// - /// Add other assemblies that Dapper Extensions will search if a mapping is not found in the same assembly of the POCO. - /// - /// - public static void SetMappingAssemblies(IList assemblies) - { - Configure(_configuration.DefaultMapper, assemblies, _configuration.Dialect); - } - - /// - /// Configure DapperExtensions extension methods. - /// - /// - /// - /// - public static void Configure(IDapperExtensionsConfiguration configuration) - { - _instance = null; - _configuration = configuration; - } - - /// - /// Configure DapperExtensions extension methods. - /// - /// - /// - /// - public static void Configure(Type defaultMapper, IList mappingAssemblies, ISqlDialect sqlDialect) - { - Configure(new DapperExtensionsConfiguration(defaultMapper, mappingAssemblies, sqlDialect)); - } - - public static void Configure(ISqlDialect sqlDialect, Type defaultMapper = null, IList mappingAssemblies = null) - { - defaultMapper = defaultMapper ?? typeof(AutoClassMapper<>); - mappingAssemblies = mappingAssemblies ?? new List(); - Configure(new DapperExtensionsConfiguration(defaultMapper, mappingAssemblies, sqlDialect)); - } - - #endregion - - #region Get - /// - /// Executes a query for the specified id, returning the data typed as per T - /// - public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Get(connection, null, id, transaction, commandTimeout); - - public static T Get(this IDbConnection connection, string tableName, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Get(connection, tableName, null, id, transaction, commandTimeout); - - public static T Get(this IDbConnection connection, string tableName, string schemaName, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => (T)Instance.Get(connection, id, transaction, commandTimeout, tableName, schemaName, null, null); - - public static async Task GetAsync(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetAsync(connection, null, id, transaction, commandTimeout); - - public static async Task GetAsync(this IDbConnection connection, string tableName, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetAsync(connection, tableName, null, id, transaction, commandTimeout); - - public static async Task GetAsync(this IDbConnection connection, string tableName, string schemaName, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetAsync(connection, id, transaction, commandTimeout, tableName, schemaName, null, null); - - public static T Get(this IDbConnection connection, IList join, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Get(connection, join, null, id, transaction, commandTimeout); - - public static T Get(this IDbConnection connection, IList join, IList alias, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => (T)Instance.Get(connection, id, transaction, commandTimeout, null, null, join, alias); - - public static async Task GetAsync(this IDbConnection connection, IList join, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetAsync(connection, join, null, id, transaction, commandTimeout); - - public static async Task GetAsync(this IDbConnection connection, IList join, IList alias, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetAsync(connection, id, transaction, commandTimeout, null, null, join, alias); - - #endregion - - #region Insert - /// - /// Executes an insert query for the specified entity. - /// - public static void Insert(this IDbConnection connection, IEnumerable entities, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Insert(connection, null, entities, transaction, commandTimeout); - - public static void Insert(this IDbConnection connection, string tableName, IEnumerable entities, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Insert(connection, tableName, null, entities, transaction, commandTimeout); - - public static void Insert(this IDbConnection connection, string tableName, string schemaName, IEnumerable entities, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.Insert(connection, entities, transaction, commandTimeout, tableName, schemaName); - - - /// - /// Executes an insert query for the specified entity, returning the primary key. - /// If the entity has a single key, just the value is returned. - /// If the entity has a composite key, an IDictionary<string, object> is returned with the key values. - /// The key value for the entity will also be updated if the KeyType is a Guid or Identity. - /// - public static dynamic Insert(this IDbConnection connection, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Insert(connection, null, entity, transaction, commandTimeout); - - public static dynamic Insert(this IDbConnection connection, string tableName, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Insert(connection, tableName, null, entity, transaction, commandTimeout); - - public static dynamic Insert(this IDbConnection connection, string tableName, string schemaName, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.Insert(connection, entity, transaction, commandTimeout, tableName, schemaName); - - #endregion - - #region Update - /// - /// Executes an update query for the specified entity. - /// - public static bool Update(this IDbConnection connection, T entity, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Update(connection, null, entity, transaction, commandTimeout, ignoreAllKeyProperties); - - public static bool Update(this IDbConnection connection, string tableName, T entity, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Update(connection, tableName, null, entity, transaction, commandTimeout, ignoreAllKeyProperties); - - public static bool Update(this IDbConnection connection, string tableName, string schemaName, T entity, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Instance.Update(connection, entity, null, transaction, commandTimeout, tableName, schemaName, ignoreAllKeyProperties); - - - public static bool Update(this IDbConnection connection, T entity, object predicate, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Update(connection, null, entity, predicate, transaction, commandTimeout, ignoreAllKeyProperties); - - public static bool Update(this IDbConnection connection, string tableName, T entity, object predicate, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Update(connection, tableName, null, entity, predicate, transaction, commandTimeout, ignoreAllKeyProperties); - - public static bool Update(this IDbConnection connection, string tableName, string schemaName, T entity, object predicate, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Instance.Update(connection, entity, predicate, transaction, commandTimeout, tableName, schemaName, ignoreAllKeyProperties); - - - public static async Task UpdateAsync(this IDbConnection connection, T entity, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await UpdateAsync(connection, null, entity, transaction, commandTimeout, ignoreAllKeyProperties); - - public static async Task UpdateAsync(this IDbConnection connection, string tableName, T entity, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await UpdateAsync(connection, tableName, null, entity, transaction, commandTimeout, ignoreAllKeyProperties); - - public static async Task UpdateAsync(this IDbConnection connection, string tableName, string schemaName, T entity, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await Instance.UpdateAsync(connection, entity, null, transaction, commandTimeout, tableName, schemaName, ignoreAllKeyProperties); - - public static async Task UpdateAsync(this IDbConnection connection, T entity, object predicate, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await UpdateAsync(connection, null, entity, predicate, transaction, commandTimeout, ignoreAllKeyProperties); - - public static async Task UpdateAsync(this IDbConnection connection, string tableName, T entity, object predicate, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await UpdateAsync(connection, tableName, null, entity, predicate, transaction, commandTimeout, ignoreAllKeyProperties); - - public static async Task UpdateAsync(this IDbConnection connection, string tableName, string schemaName, T entity, object predicate, IDbTransaction transaction = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await Instance.UpdateAsync(connection, entity, predicate, transaction, commandTimeout, tableName, schemaName, ignoreAllKeyProperties); - - - - public static bool UpdateSet(this IDbConnection connection, object entity, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => UpdateSet(connection, null, entity, predicate, transaction, commandTimeout); - - public static bool UpdateSet(this IDbConnection connection, string tableName, object entity, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => UpdateSet(connection, tableName, null, entity, predicate, transaction, commandTimeout); - - public static bool UpdateSet(this IDbConnection connection, string tableName, string schemaName, object entity, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.UpdateSet(connection, entity, predicate, transaction, commandTimeout, tableName, schemaName); - - - public static async Task UpdateSetAsync(this IDbConnection connection, object entity, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await UpdateSetAsync(connection, null, entity, predicate, transaction, commandTimeout); - - public static async Task UpdateSetAsync(this IDbConnection connection, string tableName, object entity, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await UpdateSetAsync(connection, tableName, null, entity, predicate, transaction, commandTimeout); - - public static async Task UpdateSetAsync(this IDbConnection connection, string tableName, string schemaName, object entity, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.UpdateSetAsync(connection, entity, predicate, transaction, commandTimeout, tableName, schemaName); - - - #endregion - - #region Delete - /// - /// Executes a delete query for the specified entity. - /// - public static bool Delete(this IDbConnection connection, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Delete(connection, null, entity, transaction, commandTimeout); - - public static bool Delete(this IDbConnection connection, string tableName, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Delete(connection, tableName, null, entity, transaction, commandTimeout); - - public static bool Delete(this IDbConnection connection, string tableName, string schemaName, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.Delete(connection, entity, transaction, commandTimeout, tableName, schemaName); - - - public static async Task DeleteAsync(this IDbConnection connection, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await DeleteAsync(connection, null, entity, transaction, commandTimeout); - - public static async Task DeleteAsync(this IDbConnection connection, string tableName, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await DeleteAsync(connection, tableName, null, entity, transaction, commandTimeout); - - public static async Task DeleteAsync(this IDbConnection connection, string tableName, string schemaName, T entity, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.DeleteAsync(connection, entity, transaction, commandTimeout, tableName, schemaName); - - - /// - /// Executes a delete query using the specified predicate. - /// - public static bool Delete(this IDbConnection connection, object predicate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Delete(connection, null, predicate, transaction, commandTimeout); - - public static bool Delete(this IDbConnection connection, string tableName, object predicate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Delete(connection, tableName, null, predicate, transaction, commandTimeout); - - public static bool Delete(this IDbConnection connection, string tableName, string schemaName, object predicate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.Delete(connection, predicate, transaction, commandTimeout, tableName, schemaName); - - public static async Task DeleteAsync(this IDbConnection connection, object predicate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await DeleteAsync(connection, null, predicate, transaction, commandTimeout); - - public static async Task DeleteAsync(this IDbConnection connection, string tableName, object predicate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await DeleteAsync(connection, tableName, null, predicate, transaction, commandTimeout); - - public static async Task DeleteAsync(this IDbConnection connection, string tableName, string schemaName, object predicate, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.DeleteAsync(connection, predicate, transaction, commandTimeout, tableName, schemaName); - - - #endregion - - #region GetList - /// - /// Executes a select query using the specified predicate, returning an IEnumerable data typed as per T. - /// - public static IEnumerable GetList(this IDbConnection connection, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetList(connection, (string)null, null, predicate, sort, transaction, commandTimeout, buffered); - - public static IEnumerable GetList(this IDbConnection connection, string tableName, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetList(connection, tableName, null, predicate, sort, transaction, commandTimeout, buffered); - - public static IEnumerable GetList(this IDbConnection connection, string tableName, string schemaName, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => Instance.GetList(connection, predicate, sort, transaction, commandTimeout, buffered, tableName, schemaName, null, null); - - - public static async Task> GetListAsync(this IDbConnection connection, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetListAsync(connection, (string)null, null, predicate, sort, transaction, commandTimeout); - - public static async Task> GetListAsync(this IDbConnection connection, string tableName, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetListAsync(connection, tableName, null, predicate, sort, transaction, commandTimeout); - - public static async Task> GetListAsync(this IDbConnection connection, string tableName, string schemaName, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetListAsync(connection, predicate, sort, transaction, commandTimeout, tableName, schemaName, null, null); - - - public static IEnumerable GetList(this IDbConnection connection, IList join, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetList(connection, join, null, predicate, sort, transaction, commandTimeout, buffered); - - public static IEnumerable GetList(this IDbConnection connection, IList join, IList alias, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => Instance.GetList(connection, predicate, sort, transaction, commandTimeout, buffered, null, null, join, alias); - - public static async Task> GetListAsync(this IDbConnection connection, IList join, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetListAsync(connection, join, null, predicate, sort, transaction, commandTimeout); - - public static async Task> GetListAsync(this IDbConnection connection, IList join, IList alias, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetListAsync(connection, predicate, sort, transaction, commandTimeout, null, null, join, alias); - - - #endregion - - #region GetPage - /// - /// Executes a select query using the specified predicate, returning an IEnumerable data typed as per T. - /// Data returned is dependent upon the specified page and resultsPerPage. - /// - public static IEnumerable GetPage(this IDbConnection connection, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetPage(connection, (string)null, page, resultsPerPage, predicate, sort, transaction, commandTimeout, buffered); - - public static IEnumerable GetPage(this IDbConnection connection, string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetPage(connection, tableName, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout, buffered); - - public static IEnumerable GetPage(this IDbConnection connection, string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => Instance.GetPage(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, buffered, tableName, schemaName, null, null); - - - public static async Task> GetPageAsync(this IDbConnection connection, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetPageAsync(connection, (string)null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static async Task> GetPageAsync(this IDbConnection connection, string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetPageAsync(connection, tableName, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static async Task> GetPageAsync(this IDbConnection connection, string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetPageAsync(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, tableName, schemaName, null, null); - - public static IEnumerable GetPage(this IDbConnection connection, IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetPage(connection, join, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout, buffered); - - public static IEnumerable GetPage(this IDbConnection connection, IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => Instance.GetPage(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, buffered, null, null, join, alias); - - public static async Task> GetPageAsync(this IDbConnection connection, IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetPageAsync(connection, join, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static async Task> GetPageAsync(this IDbConnection connection, IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetPageAsync(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, null, null, join, alias); - #endregion - - #region GetPages - - /// - /// Executes a select query using the specified predicate, returning an IEnumerable data typed as per T. - /// Data returned is dependent upon the specified page and resultsPerPage. - /// - public static Page GetPages(this IDbConnection connection, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => GetPages(connection, (string)null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static Page GetPages(this IDbConnection connection, string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => GetPages(connection, tableName, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static Page GetPages(this IDbConnection connection, string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.GetPages(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, tableName, schemaName, null, null); - - public static async Task> GetPagesAsync(this IDbConnection connection, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetPagesAsync(connection, (string)null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static async Task> GetPagesAsync(this IDbConnection connection, string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetPagesAsync(connection, tableName, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static async Task> GetPagesAsync(this IDbConnection connection, string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetPagesAsync(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, tableName, schemaName, null, null); - - public static Page GetPages(this IDbConnection connection, IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => GetPages(connection, join, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static Page GetPages(this IDbConnection connection, IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.GetPages(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, null, null, join, alias); - - public static async Task> GetPagesAsync(this IDbConnection connection, IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetPagesAsync(connection, join, null, page, resultsPerPage, predicate, sort, transaction, commandTimeout); - - public static async Task> GetPagesAsync(this IDbConnection connection, IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetPagesAsync(connection, predicate, sort, page, resultsPerPage, transaction, commandTimeout, null, null, join, alias); - - - #endregion - - #region GetSet - /// - /// Executes a select query using the specified predicate, returning an IEnumerable data typed as per T. - /// Data returned is dependent upon the specified firstResult and maxResults. - /// - public static IEnumerable GetSet(this IDbConnection connection, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetSet(connection, (string)null, predicate, sort, firstResult, maxResults, transaction, commandTimeout, buffered); - - public static IEnumerable GetSet(this IDbConnection connection, string tableName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetSet(connection, tableName, null, predicate, sort, firstResult, maxResults, transaction, commandTimeout, buffered); - - public static IEnumerable GetSet(this IDbConnection connection, string tableName, string schemaName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => Instance.GetSet(connection, predicate, sort, firstResult, maxResults, transaction, commandTimeout, buffered, tableName, schemaName, null, null); - - public static async Task> GetSetAsync(this IDbConnection connection, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetSetAsync(connection, (string)null, predicate, sort, firstResult, maxResults, transaction, commandTimeout); - - public static async Task> GetSetAsync(this IDbConnection connection, string tableName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetSetAsync(connection, tableName, null, predicate, sort, firstResult, maxResults, transaction, commandTimeout); - - public static async Task> GetSetAsync(this IDbConnection connection, string tableName, string schemaName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetSetAsync(connection, predicate, sort, firstResult, maxResults, transaction, commandTimeout, tableName, schemaName, null, null); - - public static IEnumerable GetSet(this IDbConnection connection, IList join, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => GetSet(connection, join, null, predicate, sort, firstResult, maxResults, transaction, commandTimeout, buffered); - - public static IEnumerable GetSet(this IDbConnection connection, IList join, IList alias, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null, bool buffered = false) where T : class - => Instance.GetSet(connection, predicate, sort, firstResult, maxResults, transaction, commandTimeout, buffered, null, null, join, alias); - - public static async Task> GetSetAsync(this IDbConnection connection, IList join, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await GetSetAsync(connection, join, null, predicate, sort, firstResult, maxResults, transaction, commandTimeout); - - public static async Task> GetSetAsync(this IDbConnection connection, IList join, IList alias, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.GetSetAsync(connection, predicate, sort, firstResult, maxResults, transaction, commandTimeout, null, null, join, alias); - - #endregion - - #region Count - /// - /// Executes a query using the specified predicate, returning an integer that represents the number of rows that match the query. - /// - public static long Count(this IDbConnection connection, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Count(connection, (string)null, predicate, transaction, commandTimeout); - - public static long Count(this IDbConnection connection, string tableName, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Count(connection, tableName, null, predicate, transaction, commandTimeout); - - public static long Count(this IDbConnection connection, string tableName, string schemaName, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.Count(connection, predicate, transaction, commandTimeout, tableName, schemaName, null); - - - public static async Task CountAsync(this IDbConnection connection, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await CountAsync(connection, (string)null, predicate, transaction, commandTimeout); - - public static async Task CountAsync(this IDbConnection connection, string tableName, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await CountAsync(connection, tableName, null, predicate, transaction, commandTimeout); - - public static async Task CountAsync(this IDbConnection connection, string tableName, string schemaName, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.CountAsync(connection, predicate, transaction, commandTimeout, tableName, schemaName, null); - - public static long Count(this IDbConnection connection, IList join, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => Instance.Count(connection, predicate, transaction, commandTimeout, null, null, join); - - public static async Task CountAsync(this IDbConnection connection, IList join, object predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class - => await Instance.CountAsync(connection, predicate, transaction, commandTimeout, null, null, join); - #endregion - - #region GetMultiple - - /// - /// Executes a select query for multiple objects, returning IMultipleResultReader for each predicate. - /// - public static IMultipleResultReader GetMultiple(this IDbConnection connection, GetMultiplePredicate predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) - => GetMultiple(connection, null, null, predicate, transaction, commandTimeout); - - public static IMultipleResultReader GetMultiple(this IDbConnection connection, string tableName, GetMultiplePredicate predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) - => GetMultiple(connection, tableName, null, predicate, transaction, commandTimeout); - - public static IMultipleResultReader GetMultiple(this IDbConnection connection, string tableName, string schemaName, GetMultiplePredicate predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) - { - return Instance.GetMultiple(connection, predicate, transaction, commandTimeout, tableName, schemaName); - } - - public static async Task GetMultipleAsync(this IDbConnection connection, GetMultiplePredicate predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) - => await GetMultipleAsync(connection, null, null, predicate, transaction, commandTimeout); - - public static async Task GetMultipleAsync(this IDbConnection connection, string tableName, GetMultiplePredicate predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) - => await GetMultipleAsync(connection, tableName, null, predicate, transaction, commandTimeout); - - public static async Task GetMultipleAsync(this IDbConnection connection, string tableName, string schemaName, GetMultiplePredicate predicate = null, IDbTransaction transaction = null, int? commandTimeout = null) - { - return await Instance.GetMultipleAsync(connection, predicate, transaction, commandTimeout, tableName, schemaName); - } - #endregion - - #region - /// - /// Gets the appropriate mapper for the specified type T. - /// If the mapper for the type is not yet created, a new mapper is generated from the mapper type specifed by DefaultMapper. - /// - public static IClassMapper GetMap() where T : class - { - return Instance.SqlGenerator.Configuration.GetMap(); - } - - /// - /// Clears the ClassMappers for each type. - /// - public static void ClearCache() - { - Instance.SqlGenerator.Configuration.ClearCache(); - } - - /// - /// Generates a COMB Guid which solves the fragmented index issue. - /// See: http://davybrion.com/blog/2009/05/using-the-guidcomb-identifier-strategy - /// - public static Guid GetNextGuid() - { - return Instance.SqlGenerator.Configuration.GetNextGuid(); - } - - - #endregion - } -} diff --git a/samples/Common/Repository.Dapper.Core/DapperExtensionsConfiguration.cs b/samples/Common/Repository.Dapper.Core/DapperExtensionsConfiguration.cs deleted file mode 100644 index 8ae8b3df5..000000000 --- a/samples/Common/Repository.Dapper.Core/DapperExtensionsConfiguration.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using Repository.Dapper.Core.Mapper; -using Repository.Dapper.Core.Sql; -using Microsoft.Extensions.Options; - -namespace Repository.Dapper.Core -{ - public interface IDapperExtensionsConfiguration - { - Type DefaultMapper { get; } - IList MappingAssemblies { get; } - ISqlDialect Dialect { get; } - IClassMapper GetMap(Type entityType); - IClassMapper GetMap() where T : class; - void ClearCache(); - Guid GetNextGuid(); - } - - public class DapperExtensionsConfiguration : IDapperExtensionsConfiguration - { - public DateTime NowTime { get; set; } - - private readonly ConcurrentDictionary _classMaps = new ConcurrentDictionary(); - - public DapperExtensionsConfiguration() - : this(typeof(AutoClassMapper<>), new List(), new SqlServerDialect()) - { - } - public DapperExtensionsConfiguration(IOptions options) - : this(typeof(AutoClassMapper<>), new List(), options.Value.sqlDialect) - { - NowTime = DateTime.Now; - } - public DapperExtensionsConfiguration(ISqlDialect sqlDialect) - : this(typeof(AutoClassMapper<>), new List(), sqlDialect) - { - NowTime = DateTime.Now; - } - - - public DapperExtensionsConfiguration(Type defaultMapper, IList mappingAssemblies, ISqlDialect sqlDialect) - { - DefaultMapper = defaultMapper; - MappingAssemblies = mappingAssemblies ?? new List(); - Dialect = sqlDialect; - } - - public Type DefaultMapper { get; private set; } - public IList MappingAssemblies { get; private set; } - public ISqlDialect Dialect { get; private set; } - - public IClassMapper GetMap(Type entityType) - { - IClassMapper map; - if (!_classMaps.TryGetValue(entityType, out map)) - { - Type mapType = GetMapType(entityType); - if (mapType == null) - { - mapType = DefaultMapper.MakeGenericType(entityType); - } - - map = Activator.CreateInstance(mapType) as IClassMapper; - _classMaps[entityType] = map; - } - - return map; - } - - public IClassMapper GetMap() where T : class - { - return GetMap(typeof (T)); - } - - public void ClearCache() - { - _classMaps.Clear(); - } - - public Guid GetNextGuid() - { - byte[] b = Guid.NewGuid().ToByteArray(); - DateTime dateTime = new DateTime(1900, 1, 1); - DateTime now = DateTime.Now; - TimeSpan timeSpan = new TimeSpan(now.Ticks - dateTime.Ticks); - TimeSpan timeOfDay = now.TimeOfDay; - byte[] bytes1 = BitConverter.GetBytes(timeSpan.Days); - byte[] bytes2 = BitConverter.GetBytes((long)(timeOfDay.TotalMilliseconds / 3.333333)); - Array.Reverse(bytes1); - Array.Reverse(bytes2); - Array.Copy(bytes1, bytes1.Length - 2, b, b.Length - 6, 2); - Array.Copy(bytes2, bytes2.Length - 4, b, b.Length - 4, 4); - return new Guid(b); - } - - protected virtual Type GetMapType(Type entityType) - { - Func getType = a => - { - Type[] types = a.GetTypes(); - return (from type in types - let interfaceType = type.GetInterface(typeof(IClassMapper<>).FullName) - where - interfaceType != null && - interfaceType.GetGenericArguments()[0] == entityType - select type).SingleOrDefault(); - }; - - Type result = getType(entityType.Assembly); - if (result != null) - { - return result; - } - - foreach (var mappingAssembly in MappingAssemblies) - { - result = getType(mappingAssembly); - if (result != null) - { - return result; - } - } - - return getType(entityType.Assembly); - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/DapperImplementor.cs b/samples/Common/Repository.Dapper.Core/DapperImplementor.cs deleted file mode 100644 index 8b4162036..000000000 --- a/samples/Common/Repository.Dapper.Core/DapperImplementor.cs +++ /dev/null @@ -1,825 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Dynamic; -using System.Linq; -using System.Reflection; -using System.Text; -using Dapper; -using Repository.Dapper.Core.Mapper; -using Repository.Dapper.Core.Sql; -using System.Threading.Tasks; - -namespace Repository.Dapper.Core -{ - public interface IDapperImplementor - { - ISqlGenerator SqlGenerator { get; } - - #region Get - T Get(IDbConnection connection, dynamic id, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - Task GetAsync(IDbConnection connection, dynamic id, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - - #endregion - - #region Insert - void Insert(IDbConnection connection, IEnumerable entities, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - dynamic Insert(IDbConnection connection, T entity, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - - #endregion - - #region Update - bool Update(IDbConnection connection, T entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, bool ignoreAllKeyProperties) where T : class; - Task UpdateAsync(IDbConnection connection, T entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, bool ignoreAllKeyProperties) where T : class; - bool UpdateSet(IDbConnection connection, object entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - Task UpdateSetAsync(IDbConnection connection, object entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - - #endregion - - #region Delete - bool Delete(IDbConnection connection, T entity, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - Task DeleteAsync(IDbConnection connection, T entity, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - bool Delete(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - Task DeleteAsync(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class; - #endregion - - #region GetList - IEnumerable GetList(IDbConnection connection, object predicate, IList sort, IDbTransaction transaction, int? commandTimeout, bool buffered, string tableName, string schemaName, IList join, IList alias) where T : class; - - Task> GetListAsync(IDbConnection connection, object predicate, IList sort, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - #endregion - - #region GetPage - IEnumerable GetPage(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, bool buffered, string tableName, string schemaName, IList join, IList alias) where T : class; - Task> GetPageAsync(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - #endregion - - #region GetPages - Page GetPages(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - Task> GetPagesAsync(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - #endregion - - #region GetSet - IEnumerable GetSet(IDbConnection connection, object predicate, IList sort, int firstResult, int maxResults, IDbTransaction transaction, int? commandTimeout, bool buffered, string tableName, string schemaName, IList join, IList alias) where T : class; - Task> GetSetAsync(IDbConnection connection, object predicate, IList sort, int firstResult, int maxResults, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class; - #endregion - - #region Count - long Count(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join) where T : class; - Task CountAsync(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join) where T : class; - #endregion - - #region GetMultiple - IMultipleResultReader GetMultiple(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName); - - Task GetMultipleAsync(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName); - #endregion - - } - - public class DapperImplementor : IDapperImplementor - { - public DapperImplementor(ISqlGenerator sqlGenerator) - { - SqlGenerator = sqlGenerator; - } - - public ISqlGenerator SqlGenerator { get; private set; } - - #region Get - - public T Get(IDbConnection connection, dynamic id, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate predicate = GetIdPredicate(classMap, id); - T result = GetList(connection, predicate, null, transaction, commandTimeout, true, tableName,schemaName, join, alias).SingleOrDefault(); - return result; - } - public async Task GetAsync(IDbConnection connection, dynamic id, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate predicate = GetIdPredicate(classMap, id); - return (await GetListAsync(connection, predicate, null, transaction, commandTimeout, tableName, schemaName, join, alias)).SingleOrDefault(); - } - - #endregion - - #region Insert - public void Insert(IDbConnection connection, IEnumerable entities, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class - { - IEnumerable properties = null; - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - var notKeyProperties = classMap.Properties.Where(p => p.KeyType != KeyType.NotAKey); - var triggerIdentityColumn = classMap.Properties.SingleOrDefault(p => p.KeyType == KeyType.TriggerIdentity); - - var parameters = new List(); - if (triggerIdentityColumn != null) - { - properties = typeof(T).GetProperties(BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public) - .Where(p => p.Name != triggerIdentityColumn.PropertyInfo.Name); - } - - foreach (var e in entities) - { - foreach (var column in notKeyProperties) - { - if (column.KeyType == KeyType.Guid && (Guid)column.PropertyInfo.GetValue(e, null) == Guid.Empty) - { - Guid comb = SqlGenerator.Configuration.GetNextGuid(); - column.PropertyInfo.SetValue(e, comb, null); - } - } - - if (triggerIdentityColumn != null) - { - var dynamicParameters = new DynamicParameters(); - foreach (var prop in properties) - { - dynamicParameters.Add(prop.Name, prop.GetValue(e, null)); - } - - // defaultValue need for identify type of parameter - var defaultValue = typeof(T).GetProperty(triggerIdentityColumn.PropertyInfo.Name).GetValue(e, null); - dynamicParameters.Add("IdOutParam", direction: ParameterDirection.Output, value: defaultValue); - - parameters.Add(dynamicParameters); - } - } - - string sql = SqlGenerator.Insert(classMap,schemaName, tableName); - - if (triggerIdentityColumn == null) - { - connection.Execute(sql, entities, transaction, commandTimeout, CommandType.Text); - } - else - { - connection.Execute(sql, parameters, transaction, commandTimeout, CommandType.Text); - } - } - - public dynamic Insert(IDbConnection connection, T entity, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName = null) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - List nonIdentityKeyProperties = classMap.Properties.Where(p => p.KeyType == KeyType.Guid || p.KeyType == KeyType.Assigned).ToList(); - var identityColumn = classMap.Properties.SingleOrDefault(p => p.KeyType == KeyType.Identity); - var triggerIdentityColumn = classMap.Properties.SingleOrDefault(p => p.KeyType == KeyType.TriggerIdentity); - foreach (var column in nonIdentityKeyProperties) - { - if (column.KeyType == KeyType.Guid && (Guid)column.PropertyInfo.GetValue(entity, null) == Guid.Empty) - { - Guid comb = SqlGenerator.Configuration.GetNextGuid(); - column.PropertyInfo.SetValue(entity, comb, null); - } - } - - IDictionary keyValues = new ExpandoObject(); - string sql = SqlGenerator.Insert(classMap,schemaName, tableName); - if (identityColumn != null) - { - IEnumerable result; - if (SqlGenerator.SupportsMultipleStatements()) - { - sql += SqlGenerator.Configuration.Dialect.BatchSeperator + SqlGenerator.IdentitySql(classMap,schemaName, tableName); - result = connection.Query(sql, entity, transaction, false, commandTimeout, CommandType.Text); - } - else - { - connection.Execute(sql, entity, transaction, commandTimeout, CommandType.Text); - sql = SqlGenerator.IdentitySql(classMap,schemaName, tableName); - result = connection.Query(sql, entity, transaction, false, commandTimeout, CommandType.Text); - } - - // We are only interested in the first identity, but we are iterating over all resulting items (if any). - // This makes sure that ADO.NET drivers (like MySql) won't actively terminate the query. - bool hasResult = false; - int identityInt = 0; - foreach (var identityValue in result) - { - if (hasResult) - { - continue; - } - identityInt = Convert.ToInt32(identityValue); - hasResult = true; - } - if (!hasResult) - { - throw new InvalidOperationException("The source sequence is empty."); - } - - keyValues.Add(identityColumn.Name, identityInt); - identityColumn.PropertyInfo.SetValue(entity, identityInt, null); - } - else if (triggerIdentityColumn != null) - { - var dynamicParameters = new DynamicParameters(); - foreach (var prop in entity.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public) - .Where(p => p.Name != triggerIdentityColumn.PropertyInfo.Name)) - { - dynamicParameters.Add(prop.Name, prop.GetValue(entity, null)); - } - - // defaultValue need for identify type of parameter - var defaultValue = entity.GetType().GetProperty(triggerIdentityColumn.PropertyInfo.Name).GetValue(entity, null); - dynamicParameters.Add("IdOutParam", direction: ParameterDirection.Output, value: defaultValue); - - connection.Execute(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text); - - var value = dynamicParameters.Get(SqlGenerator.Configuration.Dialect.ParameterPrefix + "IdOutParam"); - keyValues.Add(triggerIdentityColumn.Name, value); - triggerIdentityColumn.PropertyInfo.SetValue(entity, value, null); - } - else - { - connection.Execute(sql, entity, transaction, commandTimeout, CommandType.Text); - } - - foreach (var column in nonIdentityKeyProperties) - { - keyValues.Add(column.Name, column.PropertyInfo.GetValue(entity, null)); - } - - if (keyValues.Count == 1) - { - return keyValues.First().Value; - } - - return keyValues; - } - - - #endregion - - #region Update - - public bool Update(IDbConnection connection, T entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName = null, bool ignoreAllKeyProperties = false) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = predicate == null ? GetKeyPredicate(classMap, entity) : GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.Update(classMap, wherePredicate, parameters, schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - - var columns = ignoreAllKeyProperties - ? classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly) && p.KeyType == KeyType.NotAKey) - : classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.Assigned)); - - foreach (var property in ReflectionHelper.GetObjectValues(entity).Where(property => columns.Any(c => c.Name == property.Key))) - { - dynamicParameters.Add(property.Key, property.Value); - } - - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - return connection.Execute(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - public async Task UpdateAsync(IDbConnection connection, T entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, bool ignoreAllKeyProperties) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = predicate == null ? GetKeyPredicate(classMap, entity) : GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.Update(classMap, wherePredicate, parameters, schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - - var columns = ignoreAllKeyProperties - ? classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly) && p.KeyType == KeyType.NotAKey) - : classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.Assigned)); - - foreach (var property in ReflectionHelper.GetObjectValues(entity).Where(property => columns.Any(c => c.Name == property.Key))) - { - dynamicParameters.Add(property.Key, property.Value); - } - - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - return await connection.ExecuteAsync(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - - public bool UpdateSet(IDbConnection connection, object entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName = null) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = predicate == null ? GetSetKeyPredicate(classMap, entity) : GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.UpdateSet(classMap, entity, wherePredicate, parameters, schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - - var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.Assigned)); - - foreach (var property in ReflectionHelper.GetObjectValues(entity).Where(property => columns.Any(c => c.Name.Equals(property.Key)))) - { - dynamicParameters.Add(property.Key, property.Value); - } - - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - return connection.Execute(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - public async Task UpdateSetAsync(IDbConnection connection, object entity, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = predicate == null ? GetSetKeyPredicate(classMap, entity) : GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.UpdateSet(classMap, entity, wherePredicate, parameters, schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - - var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.Assigned)); - - foreach (var property in ReflectionHelper.GetObjectValues(entity).Where(property => columns.Any(c => c.Name.Equals(property.Key)))) - { - dynamicParameters.Add(property.Key, property.Value); - } - - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - return await connection.ExecuteAsync(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - #endregion - - #region Delete - public bool Delete(IDbConnection connection, T entity, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName = null) where T : class - { - var build = BuildDelete(entity, null, tableName, schemaName); - return connection.Execute(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - public bool Delete(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class - { - var build = BuildDelete(null, predicate, tableName, schemaName); - return connection.Execute(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - - public async Task DeleteAsync(IDbConnection connection, T entity, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class - { - var build = BuildDelete(entity, null, tableName, schemaName); - return await connection.ExecuteAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - - - public async Task DeleteAsync(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) where T : class - { - var build = BuildDelete(null, predicate, tableName, schemaName); - return await connection.ExecuteAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text) > 0; - } - - - protected (string sql, DynamicParameters dynamicParameters) BuildDelete(T entity, object predicate, string tableName, string schemaName) where T : class - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = entity == null && predicate != null ? GetPredicate(classMap, predicate) : GetKeyPredicate(classMap, entity); - - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.Delete(classMap, wherePredicate, parameters, schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - return (sql, dynamicParameters); - } - - - #endregion - - #region GetList - public IEnumerable GetList(IDbConnection connection, object predicate, IList sort, IDbTransaction transaction, int? commandTimeout, bool buffered, string tableName, string schemaName, IList join, IList alias) where T : class - { - var build = BuildList(predicate, sort, tableName, schemaName, join, alias); - return connection.Query(build.sql, build.dynamicParameters, transaction, buffered, commandTimeout, CommandType.Text); - } - - public async Task> GetListAsync(IDbConnection connection, object predicate, IList sort, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - var build = BuildList(predicate, sort, tableName, schemaName, join, alias); - return await connection.QueryAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text); - } - - protected (string sql, DynamicParameters dynamicParameters) BuildList(object predicate, IList sort, string tableName, string schemaName, IList join, IList alias) where T : class - { - VerifyJoinPredicate(join, predicate); - - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - Dictionary parameters = new Dictionary(); - IPredicate wherePredicate = GetPredicate(classMap, predicate); - string sql = SqlGenerator.Select(classMap, wherePredicate, sort, parameters, schemaName, tableName, join, alias); - - - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - return (sql, dynamicParameters); - } - - - #endregion - - #region GetPage - public IEnumerable GetPage(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, bool buffered, string tableName, string schemaName, IList join, IList alias) where T : class - { - var build = BuildPage(predicate, sort, page, resultsPerPage, tableName, schemaName, join, alias); - return connection.Query(build.sql, build.dynamicParameters, transaction, buffered, commandTimeout, CommandType.Text); - } - - public async Task> GetPageAsync(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - var build = BuildPage(predicate, sort, page, resultsPerPage, tableName, schemaName, join, alias); - return await connection.QueryAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text); - } - - protected (string sql, DynamicParameters dynamicParameters) BuildPage(object predicate, IList sort, int page, int resultsPerPage, string tableName, string schemaName, IList join, IList alias) where T : class - { - VerifyJoinPredicate(join, predicate); - - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - - string sql = SqlGenerator.SelectPaged(classMap, wherePredicate, sort, page, resultsPerPage, parameters, schemaName, tableName, join, alias); - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - return (sql, dynamicParameters); - } - - - #endregion - - #region GetPages - - public Page GetPages(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - var PageResult = new Page() { CurrentPage = page, ItemsPerPage = resultsPerPage }; - PageResult.TotalItems = Count(connection, predicate, transaction, commandTimeout, tableName, schemaName, join); - if (PageResult.TotalItems == 0) - { - PageResult.Items = new List(); - return PageResult; - } - var build = BuildPage(predicate, sort, page, resultsPerPage, tableName, schemaName, join, alias); - PageResult.Items = connection.Query(build.sql, build.dynamicParameters, transaction, false, commandTimeout, CommandType.Text); - return PageResult; - } - public async Task> GetPagesAsync(IDbConnection connection, object predicate, IList sort, int page, int resultsPerPage, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - var PageResult = new Page() { CurrentPage = page, ItemsPerPage = resultsPerPage }; - PageResult.TotalItems = await CountAsync(connection, predicate, transaction, commandTimeout, tableName, schemaName, join); - if (PageResult.TotalItems == 0) - { - PageResult.Items = new List(); - return PageResult; - } - var build = BuildPage(predicate, sort, page, resultsPerPage, tableName, schemaName, join, alias); - PageResult.Items = await connection.QueryAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text); - return PageResult; - } - #endregion - - #region GetSet - public IEnumerable GetSet(IDbConnection connection, object predicate, IList sort, int firstResult, int maxResults, IDbTransaction transaction, int? commandTimeout, bool buffered, string tableName, string schemaName, IList join, IList alias) where T : class - { - var build = BuildPage(predicate, sort, firstResult, maxResults, tableName, schemaName, join, alias); - return connection.Query(build.sql, build.dynamicParameters, transaction, buffered, commandTimeout, CommandType.Text); - } - - public async Task> GetSetAsync(IDbConnection connection, object predicate, IList sort, int firstResult, int maxResults, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join, IList alias) where T : class - { - var build = BuildPage(predicate, sort, firstResult, maxResults, tableName, schemaName, join, alias); - return await connection.QueryAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text); - } - - protected (string sql, DynamicParameters dynamicParameters) BuildGetSet(object predicate, IList sort, int firstResult, int maxResults, string tableName, string schemaName, IList join, IList alias) where T : class - { - VerifyJoinPredicate(join, predicate); - - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.SelectSet(classMap, wherePredicate, sort, firstResult, maxResults, parameters, schemaName, tableName, join, alias); - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - return (sql, dynamicParameters); - } - - #endregion - - #region Count - public long Count(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join) where T : class - { - var build = BuildCount(predicate, tableName, schemaName, join); - return (long)(connection.Query(build.sql, build.dynamicParameters, transaction, false, commandTimeout, CommandType.Text).Single().Total); - } - - public async Task CountAsync(IDbConnection connection, object predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName, IList join) where T : class - { - var build = BuildCount(predicate, tableName, schemaName, join); - return (int)(await connection.QueryAsync(build.sql, build.dynamicParameters, transaction, commandTimeout, CommandType.Text)).Single().Total; - } - - protected (string sql, DynamicParameters dynamicParameters) BuildCount(object predicate, string tableName, string schemaName, IList join) where T : class - { - VerifyJoinPredicate(join, predicate); - - IClassMapper classMap = SqlGenerator.Configuration.GetMap(); - IPredicate wherePredicate = GetPredicate(classMap, predicate); - Dictionary parameters = new Dictionary(); - string sql = SqlGenerator.Count(classMap, wherePredicate, parameters, schemaName, tableName, join); - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - return (sql, dynamicParameters); - } - - #endregion - - #region GetMultiple - - public IMultipleResultReader GetMultiple(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) - { - if (SqlGenerator.SupportsMultipleStatements()) - { - return GetMultipleByBatch(connection, predicate, transaction, commandTimeout, tableName, schemaName); - } - - return GetMultipleBySequence(connection, predicate, transaction, commandTimeout, tableName, schemaName); - } - public async Task GetMultipleAsync(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) - { - if (SqlGenerator.SupportsMultipleStatements()) - { - return await GetMultipleByBatchAsync(connection, predicate, transaction, commandTimeout, tableName, schemaName); - } - - return await GetMultipleBySequenceAsync(connection, predicate, transaction, commandTimeout, tableName, schemaName); - } - - #endregion - - #region Helpers - - protected IPredicate GetPredicate(IClassMapper classMap, object predicate) - { - IPredicate wherePredicate = predicate as IPredicate; - if (wherePredicate == null && predicate != null) - { - wherePredicate = GetEntityPredicate(classMap, predicate); - } - - return wherePredicate; - } - - protected IPredicate GetIdPredicate(IClassMapper classMap, object id) - { - bool isSimpleType = ReflectionHelper.IsSimpleType(id.GetType()); - var keys = classMap.Properties.Where(p => p.KeyType != KeyType.NotAKey); - IDictionary paramValues = null; - IList predicates = new List(); - if (!isSimpleType) - { - paramValues = ReflectionHelper.GetObjectValues(id); - } - - foreach (var key in keys) - { - object value = id; - if (!isSimpleType) - { - value = paramValues[key.Name]; - } - - Type predicateType = typeof(FieldPredicate<>).MakeGenericType(classMap.EntityType); - - IFieldPredicate fieldPredicate = Activator.CreateInstance(predicateType) as IFieldPredicate; - fieldPredicate.Not = false; - fieldPredicate.Operator = Operator.Eq; - fieldPredicate.PropertyName = key.Name; - fieldPredicate.Value = value; - predicates.Add(fieldPredicate); - } - - return predicates.Count == 1 - ? predicates[0] - : new PredicateGroup - { - Operator = GroupOperator.And, - Predicates = predicates - }; - } - - protected IPredicate GetKeyPredicate(IClassMapper classMap, T entity) where T : class - { - var whereFields = classMap.Properties.Where(p => p.KeyType != KeyType.NotAKey); - if (!whereFields.Any()) - { - throw new ArgumentException("At least one Key column must be defined."); - } - - IList predicates = (from field in whereFields - select new FieldPredicate - { - Not = false, - Operator = Operator.Eq, - PropertyName = field.Name, - Value = field.PropertyInfo.GetValue(entity, null) - }).Cast().ToList(); - - return predicates.Count == 1 - ? predicates[0] - : new PredicateGroup - { - Operator = GroupOperator.And, - Predicates = predicates - }; - } - - protected IPredicate GetSetKeyPredicate(IClassMapper classMap, object entity) where T : class - { - var whereFields = classMap.Properties.Where(p => p.KeyType != KeyType.NotAKey); - if (!whereFields.Any()) - { - throw new ArgumentException("At least one Key column must be defined."); - } - var vKeyValue = ReflectionHelper.GetObjectValues(entity); - IList predicates = (from field in whereFields - select new FieldPredicate - { - Not = false, - Operator = Operator.Eq, - PropertyName = field.Name, - Value = vKeyValue.Where(w => w.Key.Equals(field.Name, StringComparison.OrdinalIgnoreCase)).First().Value - }).Cast().ToList(); - - return predicates.Count == 1 - ? predicates[0] - : new PredicateGroup - { - Operator = GroupOperator.And, - Predicates = predicates - }; - } - - protected IPredicate GetEntityPredicate(IClassMapper classMap, object entity) - { - Type predicateType = typeof(FieldPredicate<>).MakeGenericType(classMap.EntityType); - IList predicates = new List(); - foreach (var kvp in ReflectionHelper.GetObjectValues(entity)) - { - IFieldPredicate fieldPredicate = Activator.CreateInstance(predicateType) as IFieldPredicate; - fieldPredicate.Not = false; - fieldPredicate.Operator = Operator.Eq; - fieldPredicate.PropertyName = kvp.Key; - fieldPredicate.Value = kvp.Value; - predicates.Add(fieldPredicate); - } - - return predicates.Count == 1 - ? predicates[0] - : new PredicateGroup - { - Operator = GroupOperator.And, - Predicates = predicates - }; - } - - protected GridReaderResultReader GetMultipleByBatch(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) - { - Dictionary parameters = new Dictionary(); - StringBuilder sql = new StringBuilder(); - foreach (var item in predicate.Items) - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(item.Type); - IPredicate itemPredicate = item.Value as IPredicate; - if (itemPredicate == null && item.Value != null) - { - itemPredicate = GetPredicate(classMap, item.Value); - } - - sql.AppendLine(SqlGenerator.Select(classMap, itemPredicate, item.Sort, parameters,schemaName, tableName) + SqlGenerator.Configuration.Dialect.BatchSeperator); - } - - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - SqlMapper.GridReader grid = connection.QueryMultiple(sql.ToString(), dynamicParameters, transaction, commandTimeout, CommandType.Text); - return new GridReaderResultReader(grid); - } - - protected SequenceReaderResultReader GetMultipleBySequence(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) - { - IList items = new List(); - foreach (var item in predicate.Items) - { - Dictionary parameters = new Dictionary(); - IClassMapper classMap = SqlGenerator.Configuration.GetMap(item.Type); - IPredicate itemPredicate = item.Value as IPredicate; - if (itemPredicate == null && item.Value != null) - { - itemPredicate = GetPredicate(classMap, item.Value); - } - - string sql = SqlGenerator.Select(classMap, itemPredicate, item.Sort, parameters,schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - SqlMapper.GridReader queryResult = connection.QueryMultiple(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text); - items.Add(queryResult); - } - - return new SequenceReaderResultReader(items); - } - - - protected async Task GetMultipleByBatchAsync(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) - { - Dictionary parameters = new Dictionary(); - StringBuilder sql = new StringBuilder(); - foreach (var item in predicate.Items) - { - IClassMapper classMap = SqlGenerator.Configuration.GetMap(item.Type); - IPredicate itemPredicate = item.Value as IPredicate; - if (itemPredicate == null && item.Value != null) - { - itemPredicate = GetPredicate(classMap, item.Value); - } - - sql.AppendLine(SqlGenerator.Select(classMap, itemPredicate, item.Sort, parameters, schemaName, tableName) + SqlGenerator.Configuration.Dialect.BatchSeperator); - } - - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - SqlMapper.GridReader grid = await connection.QueryMultipleAsync(sql.ToString(), dynamicParameters, transaction, commandTimeout, CommandType.Text); - return new GridReaderResultReader(grid); - } - - protected async Task GetMultipleBySequenceAsync(IDbConnection connection, GetMultiplePredicate predicate, IDbTransaction transaction, int? commandTimeout, string tableName, string schemaName) - { - IList items = new List(); - foreach (var item in predicate.Items) - { - Dictionary parameters = new Dictionary(); - IClassMapper classMap = SqlGenerator.Configuration.GetMap(item.Type); - IPredicate itemPredicate = item.Value as IPredicate; - if (itemPredicate == null && item.Value != null) - { - itemPredicate = GetPredicate(classMap, item.Value); - } - - string sql = SqlGenerator.Select(classMap, itemPredicate, item.Sort, parameters, schemaName, tableName); - DynamicParameters dynamicParameters = new DynamicParameters(); - foreach (var parameter in parameters) - { - dynamicParameters.Add(parameter.Key, parameter.Value); - } - - SqlMapper.GridReader queryResult = await connection.QueryMultipleAsync(sql, dynamicParameters, transaction, commandTimeout, CommandType.Text); - items.Add(queryResult); - } - - return new SequenceReaderResultReader(items); - } - - /// - /// 检测join模式下的条件参数类型 - /// - /// - /// - protected void VerifyJoinPredicate(IList join, object predicate) - { - //联合查询时,参数必须是IPredicate格式,不能是anonymoustype、IEnumerable> - if (join != null && join.Count > 0 && predicate != null && (predicate as IPredicate) == null) - { - throw new Exception(" join predicate = IPredicate"); - } - } - #endregion - } -} diff --git a/samples/Common/Repository.Dapper.Core/Database.cs b/samples/Common/Repository.Dapper.Core/Database.cs deleted file mode 100644 index 2bf0145bb..000000000 --- a/samples/Common/Repository.Dapper.Core/Database.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using Repository.Dapper.Core.Mapper; -using Repository.Dapper.Core.Sql; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; - -namespace Repository.Dapper.Core -{ - public partial interface IDatabase : IDisposable - { - bool HasActiveTransaction { get; } - IDbConnection Connection { get; } - void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted); - void Commit(); - void Rollback(); - void RunInTransaction(Action action); - T RunInTransaction(Func func); - void ClearCache(); - Guid GetNextGuid(); - IClassMapper GetMap() where T : class; - - } - - public partial class Database : IDatabase - { - - private readonly IDapperImplementor _dapper; - - private IDbTransaction _transaction; - - public Database(IDbConnection connection, ISqlGenerator sqlGenerator) - { - _dapper = new DapperImplementor(sqlGenerator); - Connection = connection; - - if (Connection.State != ConnectionState.Open) - { - Connection.Open(); - } - } - public Database(IOptions options, IDapperExtensionsConfiguration Configuration) - { - _dapper = new DapperImplementor(new SqlGeneratorImpl(Configuration)); - Connection = options.Value.DbConnection(); - - if (Connection.State != ConnectionState.Open) - { - Connection.Open(); - } - } - - public bool HasActiveTransaction - { - get - { - return _transaction != null; - } - } - - public IDbConnection Connection { get; private set; } - - public void Dispose() - { - if (Connection.State != ConnectionState.Closed) - { - if (_transaction != null) - { - _transaction.Rollback(); - } - - Connection.Close(); - } - } - - public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted) - { - _transaction = Connection.BeginTransaction(isolationLevel); - } - - public void Commit() - { - _transaction.Commit(); - _transaction = null; - } - - public void Rollback() - { - _transaction.Rollback(); - _transaction = null; - } - - public void RunInTransaction(Action action) - { - BeginTransaction(); - try - { - action(); - Commit(); - } - catch (Exception ex) - { - if (HasActiveTransaction) - { - Rollback(); - } - - throw ex; - } - } - - public T RunInTransaction(Func func) - { - BeginTransaction(); - try - { - T result = func(); - Commit(); - return result; - } - catch (Exception ex) - { - if (HasActiveTransaction) - { - Rollback(); - } - - throw ex; - } - } - - public void ClearCache() - { - _dapper.SqlGenerator.Configuration.ClearCache(); - } - - public Guid GetNextGuid() - { - return _dapper.SqlGenerator.Configuration.GetNextGuid(); - } - - public IClassMapper GetMap() where T : class - { - return _dapper.SqlGenerator.Configuration.GetMap(); - } - - - } - - public class DataBaseOptions - { - public ISqlDialect sqlDialect { get; set; } - - public Func DbConnection { get; set; } - } -} diff --git a/samples/Common/Repository.Dapper.Core/DatabasePartial.cs b/samples/Common/Repository.Dapper.Core/DatabasePartial.cs deleted file mode 100644 index 4cd8ba6dd..000000000 --- a/samples/Common/Repository.Dapper.Core/DatabasePartial.cs +++ /dev/null @@ -1,514 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Text; -using System.Threading.Tasks; - -namespace Repository.Dapper.Core -{ - public partial interface IDatabase - { - #region Count - long Count(object predicate = null, int? commandTimeout = null) where T : class; - long Count(string tableName, object predicate = null, int? commandTimeout = null) where T : class; - long Count(string tableName, string schemaName, object predicate = null, int? commandTimeout = null) where T : class; - - Task CountAsync(object predicate = null, int? commandTimeout = null) where T : class; - Task CountAsync(string tableName, object predicate = null, int? commandTimeout = null) where T : class; - Task CountAsync(string tableName, string schemaName, object predicate = null, int? commandTimeout = null) where T : class; - - - long Count(IList join, object predicate = null, int? commandTimeout = null) where T : class; - - Task CountAsync(IList join, object predicate = null, int? commandTimeout = null) where T : class; - - #endregion - - #region Delete - bool Delete(T entity, int? commandTimeout = null) where T : class; - bool Delete(string tableName, T entity, int? commandTimeout = null) where T : class; - bool Delete(string tableName, string schemaName, T entity, int? commandTimeout = null) where T : class; - - bool Delete(object predicate, int? commandTimeout = null) where T : class; - bool Delete(string tableName, object predicate, int? commandTimeout = null) where T : class; - bool Delete(string tableName, string schemaName, object predicate, int? commandTimeout = null) where T : class; - - Task DeleteAsync(T entity, int? commandTimeout = null) where T : class; - Task DeleteAsync(string tableName, T entity, int? commandTimeout = null) where T : class; - Task DeleteAsync(string tableName, string schemaName, T entity, int? commandTimeout = null) where T : class; - - Task DeleteAsync(object predicate, int? commandTimeout = null) where T : class; - Task DeleteAsync(string tableName, object predicate, int? commandTimeout = null) where T : class; - Task DeleteAsync(string tableName, string schemaName, object predicate, int? commandTimeout = null) where T : class; - #endregion - - #region Get - T Get(dynamic id, int? commandTimeout = null) where T : class; - T Get(dynamic id, string tableName, int? commandTimeout = null) where T : class; - T Get(dynamic id, string tableName, string schemaName, int? commandTimeout = null) where T : class; - - Task GetAsync(dynamic id, int? commandTimeout = null) where T : class; - Task GetAsync(dynamic id, string tableName, int? commandTimeout = null) where T : class; - Task GetAsync(dynamic id, string tableName, string schemaName, int? commandTimeout = null) where T : class; - - T Get(IList join, dynamic id, int? commandTimeout = null) where T : class; - T Get(IList join, IList alias, dynamic id, int? commandTimeout = null) where T : class; - - Task GetAsync(IList join, dynamic id, int? commandTimeout = null) where T : class; - Task GetAsync(IList join, IList alias, dynamic id, int? commandTimeout = null) where T : class; - #endregion - - #region GetList - IEnumerable GetList(object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - IEnumerable GetList(string tableName, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - IEnumerable GetList(string tableName, string schemaName, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - - Task> GetListAsync(object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetListAsync(string tableName, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetListAsync(string tableName, string schemaName, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - - IEnumerable GetList(IList join, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - - IEnumerable GetList(IList join, IList alias = null, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - - Task> GetListAsync(IList join, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - Task> GetListAsync(IList join, IList alias = null, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - #endregion - - #region GetMultiple - IMultipleResultReader GetMultiple(GetMultiplePredicate predicate = null, int? commandTimeout = null); - IMultipleResultReader GetMultiple(string tableName, GetMultiplePredicate predicate = null, int? commandTimeout = null); - IMultipleResultReader GetMultiple(string tableName, string schemaName, GetMultiplePredicate predicate = null, int? commandTimeout = null); - Task GetMultipleAsync(GetMultiplePredicate predicate = null, int? commandTimeout = null); - Task GetMultipleAsync(string tableName, GetMultiplePredicate predicate = null, int? commandTimeout = null); - Task GetMultipleAsync(string tableName, string schemaName, GetMultiplePredicate predicate = null, int? commandTimeout = null); - #endregion - - #region GetPage - IEnumerable GetPage(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - IEnumerable GetPage(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - IEnumerable GetPage(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - - - Task> GetPageAsync(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetPageAsync(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetPageAsync(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - IEnumerable GetPage(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - - IEnumerable GetPage(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class; - - Task> GetPageAsync(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - Task> GetPageAsync(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - #endregion - - - #region GetPages - Page GetPages(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Page GetPages(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Page GetPages(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - Task> GetPagesAsync(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetPagesAsync(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetPagesAsync(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - Page GetPages(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Page GetPages(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - Task> GetPagesAsync(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - Task> GetPagesAsync(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class; - - #endregion - - #region GetSet - IEnumerable GetSet(object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class; - IEnumerable GetSet(string tableName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class; - IEnumerable GetSet(string tableName, string schemaName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class; - Task> GetSetAsync(object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class; - Task> GetSetAsync(string tableName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class; - Task> GetSetAsync(string tableName, string schemaName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class; - - IEnumerable GetSet(IList join, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class; - - IEnumerable GetSet(IList join, IList alias, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class; - Task> GetSetAsync(IList join, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class; - - Task> GetSetAsync(IList join, IList alias, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class; - - #endregion - - #region Insert - void Insert(IEnumerable entities, int? commandTimeout = null) where T : class; - void Insert(string tableName, IEnumerable entities, int? commandTimeout = null) where T : class; - void Insert(string tableName, string schemaName, IEnumerable entities, int? commandTimeout = null) where T : class; - - dynamic Insert(T entity, int? commandTimeout = null) where T : class; - dynamic Insert(string tableName, T entity, int? commandTimeout = null) where T : class; - dynamic Insert(string tableName, string schemaName, T entity, int? commandTimeout = null) where T : class; - #endregion - - #region Update - - bool Update(T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; - bool Update(string tableName, T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; - bool Update(string tableName, string schemaName, T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; - - - bool UpdateSet(object entity, object predicate = null, int? commandTimeout = null) where T : class; - bool UpdateSet(string tableName, object entity, object predicate = null, int? commandTimeout = null) where T : class; - bool UpdateSet(string tableName, string schemaName, object entity, object predicate = null, int? commandTimeout = null) where T : class; - - - - - Task UpdateAsync(T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; - Task UpdateAsync(string tableName, T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; - Task UpdateAsync(string tableName, string schemaName, T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; - - Task UpdateSetAsync(object entity, object predicate = null, int? commandTimeout = null) where T : class; - Task UpdateSetAsync(string tableName, object entity, object predicate = null, int? commandTimeout = null) where T : class; - Task UpdateSetAsync(string tableName, string schemaName, object entity, object predicate = null, int? commandTimeout = null) where T : class; - - - #endregion - - } - public partial class Database - { - #region Count - public long Count(object predicate = null, int? commandTimeout = null) where T : class - => Count((string)null, predicate, commandTimeout); - - public long Count(string tableName, object predicate = null, int? commandTimeout = null) where T : class - => Count(tableName, null, predicate, commandTimeout); - - public long Count(string tableName, string schemaName, object predicate = null, int? commandTimeout = null) where T : class - => _dapper.Count(Connection, predicate, _transaction, commandTimeout, tableName, schemaName, null); - - public async Task CountAsync(object predicate = null, int? commandTimeout = null) where T : class - => await CountAsync((string)null, predicate, commandTimeout); - - public async Task CountAsync(string tableName, object predicate = null, int? commandTimeout = null) where T : class - => await CountAsync(tableName, null, predicate, commandTimeout); - - public async Task CountAsync(string tableName, string schemaName, object predicate = null, int? commandTimeout = null) where T : class - => await _dapper.CountAsync(Connection, predicate, _transaction, commandTimeout, tableName, schemaName, null); - - public long Count(IList join, object predicate = null, int? commandTimeout = null) where T : class - => _dapper.Count(Connection, predicate, _transaction, commandTimeout, null, null, join); - - public async Task CountAsync(IList join, object predicate = null, int? commandTimeout = null) where T : class - => await _dapper.CountAsync(Connection, predicate, _transaction, commandTimeout, null, null, join); - #endregion - - #region Delete - public bool Delete(T entity, int? commandTimeout = null) where T : class - => Delete(null, entity, commandTimeout); - - public bool Delete(string tableName, T entity, int? commandTimeout = null) where T : class - => Delete(tableName, null, entity, commandTimeout); - - public bool Delete(string tableName, string schemaName, T entity, int? commandTimeout = null) where T : class - => _dapper.Delete(Connection, entity, _transaction, commandTimeout, tableName, schemaName); - - - public bool Delete(object predicate, int? commandTimeout = null) where T : class - => Delete(null, predicate, commandTimeout); - - public bool Delete(string tableName, object predicate, int? commandTimeout = null) where T : class - => Delete(tableName, null, predicate, commandTimeout); - - public bool Delete(string tableName, string schemaName, object predicate, int? commandTimeout = null) where T : class - => _dapper.Delete(Connection, predicate, _transaction, commandTimeout, tableName, schemaName); - - - public async Task DeleteAsync(T entity, int? commandTimeout = null) where T : class - => await DeleteAsync(null, entity, commandTimeout); - - public async Task DeleteAsync(string tableName, T entity, int? commandTimeout = null) where T : class - => await DeleteAsync(tableName, null, entity, commandTimeout); - - public async Task DeleteAsync(string tableName, string schemaName, T entity, int? commandTimeout = null) where T : class - => await _dapper.DeleteAsync(Connection, entity, _transaction, commandTimeout, tableName, schemaName); - - - public async Task DeleteAsync(object predicate, int? commandTimeout = null) where T : class - => await DeleteAsync(null, predicate, commandTimeout); - - public async Task DeleteAsync(string tableName, object predicate, int? commandTimeout = null) where T : class - => await DeleteAsync(tableName, null, predicate, commandTimeout); - - public async Task DeleteAsync(string tableName, string schemaName, object predicate, int? commandTimeout = null) where T : class - => await _dapper.DeleteAsync(Connection, predicate, _transaction, commandTimeout, tableName, schemaName); - - #endregion - - #region Get - public T Get(dynamic id, int? commandTimeout = null) where T : class - => Get(id, (string)null, commandTimeout); - - public T Get(dynamic id, string tableName, int? commandTimeout = null) where T : class - => Get(id, tableName, (string)null, commandTimeout); - - public T Get(dynamic id, string tableName, string schemaName, int? commandTimeout = null) where T : class - => (T)_dapper.Get(Connection, id, _transaction, commandTimeout, tableName, schemaName, null, null); - - - public async Task GetAsync(dynamic id, int? commandTimeout = null) where T : class - => await GetAsync(id, (string)null, commandTimeout); - - public async Task GetAsync(dynamic id, string tableName, int? commandTimeout = null) where T : class - => await GetAsync(id, tableName, (string)null, commandTimeout); - - public async Task GetAsync(dynamic id, string tableName, string schemaName, int? commandTimeout = null) where T : class - => await _dapper.GetAsync(Connection, id, _transaction, commandTimeout, tableName, schemaName, null, null); - - - - public T Get(IList join, dynamic id, int? commandTimeout = null) where T : class - => Get(join, null, id, commandTimeout); - - public T Get(IList join, IList alias, dynamic id, int? commandTimeout = null) where T : class - => (T)_dapper.Get(Connection, id, _transaction, commandTimeout, null, null, join, alias); - - public async Task GetAsync(IList join, dynamic id, int? commandTimeout = null) where T : class - => await GetAsync(join, null, id, commandTimeout); - public async Task GetAsync(IList join, IList alias, dynamic id, int? commandTimeout = null) where T : class - => await _dapper.GetAsync(Connection, id, _transaction, commandTimeout, null, null, join, alias); - #endregion - - #region GetList - - public IEnumerable GetList(object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => GetList((string)null, predicate, sort, commandTimeout, buffered); - - public IEnumerable GetList(string tableName, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => GetList(tableName, null, predicate, sort, commandTimeout, buffered); - - public IEnumerable GetList(string tableName, string schemaName, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => _dapper.GetList(Connection, predicate, sort, _transaction, commandTimeout, buffered, tableName, schemaName, null, null); - - - public async Task> GetListAsync(object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetListAsync((string)null, predicate, sort, commandTimeout); - - public async Task> GetListAsync(string tableName, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetListAsync(tableName, null, predicate, sort, commandTimeout); - - public async Task> GetListAsync(string tableName, string schemaName, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await _dapper.GetListAsync(Connection, predicate, sort, _transaction, commandTimeout, tableName, schemaName, null, null); - - - - public IEnumerable GetList(IList join, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => GetList(join, null, predicate, sort, commandTimeout, buffered); - - public IEnumerable GetList(IList join, IList alias = null, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => _dapper.GetList(Connection, predicate, sort, _transaction, commandTimeout, buffered, null, null, join, alias); - - public async Task> GetListAsync(IList join, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetListAsync(join, null, predicate, sort, commandTimeout); - - public async Task> GetListAsync(IList join, IList alias = null, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await _dapper.GetListAsync(Connection, predicate, sort, _transaction, commandTimeout, null, null, join, alias); - - #endregion - - #region GetMultiple - - public IMultipleResultReader GetMultiple(GetMultiplePredicate predicate = null, int? commandTimeout = null) - => GetMultiple(null, predicate, commandTimeout); - public IMultipleResultReader GetMultiple(string tableName, GetMultiplePredicate predicate = null, int? commandTimeout = null) - => GetMultiple(tableName, null, predicate, commandTimeout); - public IMultipleResultReader GetMultiple(string tableName, string schemaName, GetMultiplePredicate predicate = null, int? commandTimeout = null) - => _dapper.GetMultiple(Connection, predicate, _transaction, commandTimeout, tableName, schemaName); - - - - - public async Task GetMultipleAsync(GetMultiplePredicate predicate = null, int? commandTimeout = null) - => await GetMultipleAsync(null, predicate, commandTimeout); - - public async Task GetMultipleAsync(string tableName, GetMultiplePredicate predicate = null, int? commandTimeout = null) - => await GetMultipleAsync(tableName, null, predicate, commandTimeout); - - public async Task GetMultipleAsync(string tableName, string schemaName, GetMultiplePredicate predicate = null, int? commandTimeout = null) - => await _dapper.GetMultipleAsync(Connection, predicate, _transaction, commandTimeout, tableName, schemaName); - - #endregion - - - #region GetPage - public IEnumerable GetPage(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => GetPage((string)null, page, resultsPerPage, predicate, sort, commandTimeout); - - public IEnumerable GetPage(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => GetPage(tableName, null, page, resultsPerPage, predicate, sort, commandTimeout); - - public IEnumerable GetPage(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => _dapper.GetPage(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, buffered, tableName, schemaName, null, null); - - - public async Task> GetPageAsync(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetPageAsync((string)null, page, resultsPerPage, predicate, sort, commandTimeout); - - public async Task> GetPageAsync(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetPageAsync(tableName, null, page, resultsPerPage, predicate, sort, commandTimeout); - - public async Task> GetPageAsync(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await _dapper.GetPageAsync(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, tableName, schemaName, null, null); - - public IEnumerable GetPage(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => GetPage(join, null, page, resultsPerPage, predicate, sort, commandTimeout); - public IEnumerable GetPage(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null, bool buffered = true) where T : class - => _dapper.GetPage(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, buffered, null, null, join, alias); - public async Task> GetPageAsync(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetPageAsync(join, null, page, resultsPerPage, predicate, sort, commandTimeout); - public async Task> GetPageAsync(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await _dapper.GetPageAsync(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, null, null, join, alias); - - #endregion - - #region GetPages - - public Page GetPages(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => GetPages((string)null, page, resultsPerPage, predicate, sort, commandTimeout); - - public Page GetPages(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => GetPages(tableName, null, page, resultsPerPage, predicate, sort, commandTimeout); - - public Page GetPages(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => _dapper.GetPages(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, tableName, schemaName, null, null); - - - public async Task> GetPagesAsync(int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetPagesAsync((string)null, page, resultsPerPage, predicate, sort, commandTimeout); - - public async Task> GetPagesAsync(string tableName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetPagesAsync(tableName, null, page, resultsPerPage, predicate, sort, commandTimeout); - - public async Task> GetPagesAsync(string tableName, string schemaName, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await _dapper.GetPagesAsync(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, tableName, schemaName, null, null); - - public Page GetPages(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => GetPages(join, null, page, resultsPerPage, predicate, sort, commandTimeout); - - public Page GetPages(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => _dapper.GetPages(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, null, null, join, alias); - public async Task> GetPagesAsync(IList join, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await GetPagesAsync(join, null, page, resultsPerPage, predicate, sort, commandTimeout); - public async Task> GetPagesAsync(IList join, IList alias, int page = 1, int resultsPerPage = 10, object predicate = null, IList sort = null, int? commandTimeout = null) where T : class - => await _dapper.GetPagesAsync(Connection, predicate, sort, page, resultsPerPage, _transaction, commandTimeout, null, null, join, alias); - - - #endregion - - #region GetSet - public IEnumerable GetSet(object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class - => GetSet((string)null, predicate, sort, firstResult, maxResults, commandTimeout, buffered); - - public IEnumerable GetSet(string tableName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class - => GetSet(tableName, null, predicate, sort, firstResult, maxResults, commandTimeout, buffered); - - public IEnumerable GetSet(string tableName, string schemaName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class - => _dapper.GetSet(Connection, predicate, sort, firstResult, maxResults, _transaction, commandTimeout, buffered, tableName, schemaName, null, null); - - - public async Task> GetSetAsync(object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class - => await GetSetAsync((string)null, predicate, sort, firstResult, maxResults, commandTimeout); - - public async Task> GetSetAsync(string tableName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class - => await GetSetAsync(tableName, null, predicate, sort, firstResult, maxResults, commandTimeout); - - public async Task> GetSetAsync(string tableName, string schemaName, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class - => await _dapper.GetSetAsync(Connection, predicate, sort, firstResult, maxResults, _transaction, commandTimeout, tableName, schemaName, null, null); - - public IEnumerable GetSet(IList join, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class - => GetSet(join, null, predicate, sort, firstResult, maxResults, commandTimeout, buffered); - - public IEnumerable GetSet(IList join, IList alias, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null, bool buffered = true) where T : class - => _dapper.GetSet(Connection, predicate, sort, firstResult, maxResults, _transaction, commandTimeout, buffered, null, null, join, alias); - - public async Task> GetSetAsync(IList join, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class - => await GetSetAsync(join, null, predicate, sort, firstResult, maxResults, commandTimeout); - - public async Task> GetSetAsync(IList join, IList alias, object predicate = null, IList sort = null, int firstResult = 1, int maxResults = 10, int? commandTimeout = null) where T : class - => await _dapper.GetSetAsync(Connection, predicate, sort, firstResult, maxResults, _transaction, commandTimeout, null, null, join, alias); - - #endregion - - #region Insert - public void Insert(IEnumerable entities, int? commandTimeout = null) where T : class - => Insert(null, entities, commandTimeout); - - public void Insert(string tableName, IEnumerable entities, int? commandTimeout = null) where T : class - => Insert(tableName, null, entities, commandTimeout); - - public void Insert(string tableName, string schemaName, IEnumerable entities, int? commandTimeout = null) where T : class - => _dapper.Insert(Connection, entities, _transaction, commandTimeout, tableName, schemaName); - - public dynamic Insert(T entity, int? commandTimeout = null) where T : class - => Insert(null, entity, commandTimeout); - - public dynamic Insert(string tableName, T entity, int? commandTimeout = null) where T : class - => Insert(tableName, null, entity, commandTimeout); - - public dynamic Insert(string tableName, string schemaName, T entity, int? commandTimeout = null) where T : class - => _dapper.Insert(Connection, entity, _transaction, commandTimeout, tableName, schemaName); - #endregion - - #region Update - - public bool Update(T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Update(null, entity, predicate, commandTimeout, ignoreAllKeyProperties); - - public bool Update(string tableName, T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => Update(tableName, null, entity, predicate, commandTimeout, ignoreAllKeyProperties); - - public bool Update(string tableName, string schemaName, T entity, object predicate = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => _dapper.Update(Connection, entity, predicate, _transaction, commandTimeout, tableName, schemaName, ignoreAllKeyProperties); - - - - public bool UpdateSet(object entity, object predicate = null, int? commandTimeout = null) where T : class - => UpdateSet(null, entity, predicate, commandTimeout); - - public bool UpdateSet(string tableName, object entity, object predicate = null, int? commandTimeout = null) where T : class - => UpdateSet(tableName, null, entity, predicate, commandTimeout); - - public bool UpdateSet(string tableName, string schemaName, object entity, object predicate = null, int? commandTimeout = null) where T : class - => _dapper.UpdateSet(Connection, entity, predicate, _transaction, commandTimeout, tableName, schemaName); - - - - - public async Task UpdateAsync(T entity, object predicate, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await UpdateAsync(null, entity, predicate, commandTimeout, ignoreAllKeyProperties); - - public async Task UpdateAsync(string tableName, T entity, object predicate, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await UpdateAsync(tableName, null, entity, predicate, commandTimeout, ignoreAllKeyProperties); - - public async Task UpdateAsync(string tableName, string schemaName, T entity, object predicate, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class - => await _dapper.UpdateAsync(Connection, entity, predicate, _transaction, commandTimeout, tableName, schemaName, ignoreAllKeyProperties); - - - - public async Task UpdateSetAsync(object entity, object predicate = null, int? commandTimeout = null) where T : class - => await UpdateSetAsync(null, entity, predicate, commandTimeout); - - public async Task UpdateSetAsync(string tableName, object entity, object predicate = null, int? commandTimeout = null) where T : class - => await UpdateSetAsync(tableName, null, entity, predicate, commandTimeout); - - public async Task UpdateSetAsync(string tableName, string schemaName, object entity, object predicate = null, int? commandTimeout = null) where T : class - => await _dapper.UpdateSetAsync(Connection, entity, predicate, _transaction, commandTimeout, tableName, schemaName); - - - #endregion - - } -} diff --git a/samples/Common/Repository.Dapper.Core/DatabaseServiceCollectionExtensions.cs b/samples/Common/Repository.Dapper.Core/DatabaseServiceCollectionExtensions.cs deleted file mode 100644 index ea01dcf60..000000000 --- a/samples/Common/Repository.Dapper.Core/DatabaseServiceCollectionExtensions.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Repository.Dapper.Core.Sql; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Data; -using System.Text; - -namespace Repository.Dapper.Core -{ - public enum ESqlDialect - { - DB2, - MySQL, - Oracle, - PostgreSql, - SqlCe, - Sqlite, - SqlServer - } - public class SqlDialectUtil - { - public static ISqlDialect ConvertESqlDialect(ESqlDialect sqlDialect) - { - ISqlDialect SqlDialect = null; - switch (sqlDialect) - { - case ESqlDialect.DB2: - SqlDialect = new DB2Dialect(); - break; - case ESqlDialect.MySQL: - SqlDialect = new MySqlDialect(); - break; - case ESqlDialect.Oracle: - SqlDialect = new OracleDialect(); - break; - case ESqlDialect.PostgreSql: - SqlDialect = new PostgreSqlDialect(); - break; - case ESqlDialect.SqlCe: - SqlDialect = new SqlCeDialect(); - break; - case ESqlDialect.Sqlite: - SqlDialect = new SqliteDialect(); - break; - case ESqlDialect.SqlServer: - SqlDialect = new SqlServerDialect(); - break; - } - return SqlDialect; - } - } - public static class DatabaseServiceCollectionExtensions - { - - /// - /// 设置SqlDialect,使用默认用法 - /// - /// - /// - /// - /// using(var con=new SqlConnection(Configuration.GetConnectionString("DefaultConnection")) - /// { - /// con.Insert(data); - /// } - /// - /// - public static IServiceCollection AddDapper(this IServiceCollection services, ESqlDialect SqlDialect) - { - DapperExtensions.Configure(SqlDialectUtil.ConvertESqlDialect(SqlDialect)); - - return services; - } - - /// - /// 使用IDatabase用法 - /// - /// - /// - /// - /// 是否同时使用扩展方法 - /// - public static IServiceCollection AddDapperDataBase(this IServiceCollection services, ESqlDialect sqlDialect, Func CreateConnection, bool UseExtension = false) - { - var SqlDialect = SqlDialectUtil.ConvertESqlDialect(sqlDialect); - services.AddOptions(); - services.Configure(opt => - { - opt.DbConnection = CreateConnection; - opt.sqlDialect = SqlDialectUtil.ConvertESqlDialect(sqlDialect); - }); - - if (UseExtension) - { - var Configuration = new DapperExtensionsConfiguration(SqlDialect); - DapperExtensions.Configure(Configuration); - services.AddSingleton(Configuration); - } - else - services.AddSingleton(); - - services.AddTransient(); - return services; - } - } -} diff --git a/samples/Common/Repository.Dapper.Core/GetMultiplePredicate.cs b/samples/Common/Repository.Dapper.Core/GetMultiplePredicate.cs deleted file mode 100644 index e931c2423..000000000 --- a/samples/Common/Repository.Dapper.Core/GetMultiplePredicate.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Repository.Dapper.Core -{ - public class GetMultiplePredicate - { - private readonly List _items; - - public GetMultiplePredicate() - { - _items = new List(); - } - - public IEnumerable Items - { - get { return _items.AsReadOnly(); } - } - - public void Add(IPredicate predicate, IList sort = null) where T : class - { - _items.Add(new GetMultiplePredicateItem - { - Value = predicate, - Type = typeof(T), - Sort = sort - }); - } - - public void Add(object id) where T : class - { - _items.Add(new GetMultiplePredicateItem - { - Value = id, - Type = typeof (T) - }); - } - - public class GetMultiplePredicateItem - { - public object Value { get; set; } - public Type Type { get; set; } - public IList Sort { get; set; } - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/GetMultipleResult.cs b/samples/Common/Repository.Dapper.Core/GetMultipleResult.cs deleted file mode 100644 index 752a8f1d6..000000000 --- a/samples/Common/Repository.Dapper.Core/GetMultipleResult.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Dapper; - -namespace Repository.Dapper.Core -{ - public interface IMultipleResultReader - { - IEnumerable Read(); - } - - public class GridReaderResultReader : IMultipleResultReader - { - private readonly SqlMapper.GridReader _reader; - - public GridReaderResultReader(SqlMapper.GridReader reader) - { - _reader = reader; - } - - public IEnumerable Read() - { - return _reader.Read(); - } - } - - public class SequenceReaderResultReader : IMultipleResultReader - { - private readonly Queue _items; - - public SequenceReaderResultReader(IEnumerable items) - { - _items = new Queue(items); - } - - public IEnumerable Read() - { - SqlMapper.GridReader reader = _items.Dequeue(); - return reader.Read(); - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Mapper/AutoClassMapper.cs b/samples/Common/Repository.Dapper.Core/Mapper/AutoClassMapper.cs deleted file mode 100644 index 29b1cc6c7..000000000 --- a/samples/Common/Repository.Dapper.Core/Mapper/AutoClassMapper.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Text; -using System.Linq; -using System.Collections.Generic; -using System; -using System.Reflection; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Repository.Dapper.Core.Mapper -{ - /// - /// Automatically maps an entity to a table using a combination of reflection and naming conventions for keys. - /// - public class AutoClassMapper : ClassMapper where T : class - { - public AutoClassMapper() - { - Type type = typeof(T); - var vTable = type.GetTypeInfo().GetCustomAttributes(typeof(TableAttribute), true).ToArray(); - var TableName = vTable.Length == 0 ? type.Name : (vTable[0] as TableAttribute).Name; - Table(TableName);// Table(type.Name); - if (vTable.Length > 0 && !string.IsNullOrWhiteSpace((vTable[0] as TableAttribute).Schema)) - Schema((vTable[0] as TableAttribute).Schema); - - var vNotKey = type.GetTypeInfo().GetCustomAttributes(typeof(NotKeyAttribute), true).ToArray(); - if (vNotKey.Length > 0) - DefinedKey(false); - AutoMap(); - } - } - - [AttributeUsage(AttributeTargets.Class)] - public sealed class NotKeyAttribute : Attribute - { - public NotKeyAttribute() - { - NoDefinedKey = true; - } - - public bool NoDefinedKey { get; set; } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Mapper/ClassMapper.cs b/samples/Common/Repository.Dapper.Core/Mapper/ClassMapper.cs deleted file mode 100644 index 4ba847cab..000000000 --- a/samples/Common/Repository.Dapper.Core/Mapper/ClassMapper.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System.Numerics; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.ComponentModel.DataAnnotations; - -namespace Repository.Dapper.Core.Mapper -{ - public interface IClassMapper - { - string SchemaName { get; } - string TableName { get; } - IList Properties { get; } - Type EntityType { get; } - } - - public interface IClassMapper : IClassMapper where T : class - { - } - - /// - /// Maps an entity to a table through a collection of property maps. - /// - public class ClassMapper : IClassMapper where T : class - { - /// - /// Gets or sets the schema to use when referring to the corresponding table name in the database. - /// - public string SchemaName { get; protected set; } - - /// - /// Gets or sets the table to use in the database. - /// - public string TableName { get; protected set; } - private bool _HasDefinedKey = true; - public bool HasDefinedKey { get { return _HasDefinedKey; } protected set { _HasDefinedKey = value; } } - - /// - /// A collection of properties that will map to columns in the database table. - /// - public IList Properties { get; private set; } - - public Type EntityType - { - get { return typeof(T); } - } - - public ClassMapper() - { - PropertyTypeKeyTypeMapping = new Dictionary - { - { typeof(byte), KeyType.Identity }, { typeof(byte?), KeyType.Identity }, - { typeof(sbyte), KeyType.Identity }, { typeof(sbyte?), KeyType.Identity }, - { typeof(short), KeyType.Identity }, { typeof(short?), KeyType.Identity }, - { typeof(ushort), KeyType.Identity }, { typeof(ushort?), KeyType.Identity }, - { typeof(int), KeyType.Identity }, { typeof(int?), KeyType.Identity }, - { typeof(uint), KeyType.Identity}, { typeof(uint?), KeyType.Identity }, - { typeof(long), KeyType.Identity }, { typeof(long?), KeyType.Identity }, - { typeof(ulong), KeyType.Identity }, { typeof(ulong?), KeyType.Identity }, - { typeof(BigInteger), KeyType.Identity }, { typeof(BigInteger?), KeyType.Identity }, - { typeof(Guid), KeyType.Guid }, { typeof(Guid?), KeyType.Guid }, - }; - - Properties = new List(); - Table(typeof(T).Name); - } - - protected Dictionary PropertyTypeKeyTypeMapping { get; private set; } - - public virtual void Schema(string schemaName) - { - SchemaName = schemaName; - } - - public virtual void Table(string tableName) - { - TableName = tableName; - } - public virtual void DefinedKey(bool hasDefinedKey) - { - HasDefinedKey = hasDefinedKey; - } - - protected virtual void AutoMap() - { - AutoMap(null); - } - - protected virtual void AutoMap(Func canMap) - { - Type type = typeof(T); - bool hasDefinedKey = Properties.Any(p => p.KeyType != KeyType.NotAKey); - PropertyMap keyMap = null; - foreach (var propertyInfo in type.GetProperties()) - { - if (Properties.Any(p => p.Name.Equals(propertyInfo.Name, StringComparison.InvariantCultureIgnoreCase))) - { - continue; - } - - if ((canMap != null && !canMap(type, propertyInfo))) - { - continue; - } - - PropertyMap map = Map(propertyInfo); - if (!hasDefinedKey && _HasDefinedKey) - { - if (string.Equals(map.PropertyInfo.Name, "id", StringComparison.InvariantCultureIgnoreCase) && !map.Ignored && !map.IsReadOnly) - { - keyMap = map; - } - - if (keyMap == null && map.PropertyInfo.Name.EndsWith("id", true, CultureInfo.InvariantCulture) && !map.Ignored && !map.IsReadOnly) - { - keyMap = map; - } - var KeyAttr = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), true).ToArray(); - if (KeyAttr.Length > 0) - keyMap = map; - } - } - - if (keyMap != null) - { - keyMap.Key(PropertyTypeKeyTypeMapping.ContainsKey(keyMap.PropertyInfo.PropertyType) - ? PropertyTypeKeyTypeMapping[keyMap.PropertyInfo.PropertyType] - : KeyType.Assigned); - } - } - - /// - /// Fluently, maps an entity property to a column - /// - protected PropertyMap Map(Expression> expression) - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - return Map(propertyInfo); - } - - /// - /// Fluently, maps an entity property to a column - /// - protected PropertyMap Map(PropertyInfo propertyInfo) - { - PropertyMap result = new PropertyMap(propertyInfo); - this.GuardForDuplicatePropertyMap(result); - Properties.Add(result); - return result; - } - - /// - /// Removes a propertymap entry - /// - /// - protected void UnMap(Expression> expression) - { - var propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - var mapping = this.Properties.Where(w => w.Name == propertyInfo.Name).SingleOrDefault(); - - if (mapping == null) - { - throw new ApplicationException("Unable to UnMap because mapping does not exist."); - } - - this.Properties.Remove(mapping); - } - - private void GuardForDuplicatePropertyMap(PropertyMap result) - { - if (Properties.Any(p => p.Name.Equals(result.Name))) - { - throw new ArgumentException(string.Format("Duplicate mapping for property {0} detected.",result.Name)); - } - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Mapper/PluralizedAutoClassMapper.cs b/samples/Common/Repository.Dapper.Core/Mapper/PluralizedAutoClassMapper.cs deleted file mode 100644 index 19c74af0e..000000000 --- a/samples/Common/Repository.Dapper.Core/Mapper/PluralizedAutoClassMapper.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Text; -using System.Linq; -using System.Collections.Generic; -using System; -using System.Text.RegularExpressions; - -namespace Repository.Dapper.Core.Mapper -{ - /// - /// Automatically maps an entity to a table using a combination of reflection and naming conventions for keys. - /// Identical to AutoClassMapper, but attempts to pluralize table names automatically. - /// Example: Person entity maps to People table - /// - public class PluralizedAutoClassMapper : AutoClassMapper where T : class - { - public override void Table(string tableName) - { - base.Table(Formatting.Pluralize(tableName)); - } - - // Adapted from: http://mattgrande.wordpress.com/2009/10/28/pluralization-helper-for-c/ - public static class Formatting - { - private static readonly IList Unpluralizables = new List { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "deer" }; - private static readonly IDictionary Pluralizations = new Dictionary - { - // Start with the rarest cases, and move to the most common - { "person", "people" }, - { "ox", "oxen" }, - { "child", "children" }, - { "foot", "feet" }, - { "tooth", "teeth" }, - { "goose", "geese" }, - // And now the more standard rules. - { "(.*)fe?$", "$1ves" }, // ie, wolf, wife - { "(.*)man$", "$1men" }, - { "(.+[aeiou]y)$", "$1s" }, - { "(.+[^aeiou])y$", "$1ies" }, - { "(.+z)$", "$1zes" }, - { "([m|l])ouse$", "$1ice" }, - { "(.+)(e|i)x$", @"$1ices"}, // ie, Matrix, Index - { "(octop|vir)us$", "$1i"}, - { "(.+(s|x|sh|ch))$", @"$1es"}, - { "(.+)", @"$1s" } - }; - - public static string Pluralize(string singular) - { - if (Unpluralizables.Contains(singular)) - return singular; - - var plural = string.Empty; - - foreach (var pluralization in Pluralizations) - { - if (Regex.IsMatch(singular, pluralization.Key)) - { - plural = Regex.Replace(singular, pluralization.Key, pluralization.Value); - break; - } - } - - return plural; - } - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Mapper/PropertyMap.cs b/samples/Common/Repository.Dapper.Core/Mapper/PropertyMap.cs deleted file mode 100644 index ab5b14ba3..000000000 --- a/samples/Common/Repository.Dapper.Core/Mapper/PropertyMap.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Reflection; - -namespace Repository.Dapper.Core.Mapper -{ - /// - /// Maps an entity property to its corresponding column in the database. - /// - public interface IPropertyMap - { - string Name { get; } - string ColumnName { get; } - bool Ignored { get; } - bool IsReadOnly { get; } - KeyType KeyType { get; } - PropertyInfo PropertyInfo { get; } - } - - /// - /// Maps an entity property to its corresponding column in the database. - /// - public class PropertyMap : IPropertyMap - { - public PropertyMap(PropertyInfo propertyInfo) - { - PropertyInfo = propertyInfo; - var ColumnAttr = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), true).ToArray(); - ColumnName = ColumnAttr.Length == 0 ? PropertyInfo.Name : (ColumnAttr[0] as ColumnAttribute).Name; // PropertyInfo.Name; - - var cIgnore = propertyInfo.GetCustomAttributes(typeof(NotMappedAttribute), true).ToArray(); - Ignored = cIgnore.Length > 0; - - //var cReadOnly = propertyInfo.GetCustomAttributes(typeof(DatabaseGeneratedAttribute), true).ToArray(); - //IsReadOnly = cReadOnly.Length > 0; - } - - /// - /// Gets the name of the property by using the specified propertyInfo. - /// - public string Name - { - get { return PropertyInfo.Name; } - } - - /// - /// Gets the column name for the current property. - /// - public string ColumnName { get; private set; } - - /// - /// Gets the key type for the current property. - /// - public KeyType KeyType { get; private set; } - - /// - /// Gets the ignore status of the current property. If ignored, the current property will not be included in queries. - /// - public bool Ignored { get; private set; } - - /// - /// Gets the read-only status of the current property. If read-only, the current property will not be included in INSERT and UPDATE queries. - /// - public bool IsReadOnly { get; private set; } - - /// - /// Gets the property info for the current property. - /// - public PropertyInfo PropertyInfo { get; private set; } - - /// - /// Fluently sets the column name for the property. - /// - /// The column name as it exists in the database. - public PropertyMap Column(string columnName) - { - ColumnName = columnName; - return this; - } - - /// - /// Fluently sets the key type of the property. - /// - /// The column name as it exists in the database. - public PropertyMap Key(KeyType keyType) - { - if (Ignored) - { - throw new ArgumentException(string.Format("'{0}' is ignored and cannot be made a key field. ", Name)); - } - - if (IsReadOnly) - { - throw new ArgumentException(string.Format("'{0}' is readonly and cannot be made a key field. ", Name)); - } - - KeyType = keyType; - return this; - } - - /// - /// Fluently sets the ignore status of the property. - /// - public PropertyMap Ignore() - { - if (KeyType != KeyType.NotAKey) - { - throw new ArgumentException(string.Format("'{0}' is a key field and cannot be ignored.", Name)); - } - - Ignored = true; - return this; - } - - /// - /// Fluently sets the read-only status of the property. - /// - public PropertyMap ReadOnly() - { - if (KeyType != KeyType.NotAKey) - { - throw new ArgumentException(string.Format("'{0}' is a key field and cannot be marked readonly.", Name)); - } - - IsReadOnly = true; - return this; - } - } - - /// - /// Used by ClassMapper to determine which entity property represents the key. - /// - public enum KeyType - { - /// - /// The property is not a key and is not automatically managed. - /// - NotAKey, - - /// - /// The property is an integery-based identity generated from the database. - /// - Identity, - - /// - /// The property is an identity generated by the database trigger. - /// - TriggerIdentity, - - /// - /// The property is a Guid identity which is automatically managed. - /// - Guid, - - /// - /// The property is a key that is not automatically managed. - /// - Assigned - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Page.cs b/samples/Common/Repository.Dapper.Core/Page.cs deleted file mode 100644 index 4788c368d..000000000 --- a/samples/Common/Repository.Dapper.Core/Page.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Repository.Dapper.Core -{ - public class Page - { - - /// - /// Ŀ - /// - public long TotalItems { get; set; } - - /// - /// ÿҳĿ - /// - public long ItemsPerPage { get; set; } - - /// - /// ǰҳ - /// - public long CurrentPage { get; set; } - - public IEnumerable Items { get; set; } - - /// - /// ҳ - /// - public long TotalPages - { - get { return (long)Math.Ceiling((decimal)TotalItems / ItemsPerPage); } - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Predicates.cs b/samples/Common/Repository.Dapper.Core/Predicates.cs deleted file mode 100644 index be96f22eb..000000000 --- a/samples/Common/Repository.Dapper.Core/Predicates.cs +++ /dev/null @@ -1,732 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using Repository.Dapper.Core.Mapper; -using Repository.Dapper.Core.Sql; - -namespace Repository.Dapper.Core -{ - public static class Predicates - { - /// - /// 创建条件 - /// Factory method that creates a new IFieldPredicate predicate: [FieldName] [Operator] [Value]. - /// Example: WHERE FirstName = 'Foo' - /// - /// The type of the entity. - /// An expression that returns the left operand [FieldName]. - /// The comparison operator. - /// The value for the predicate. - /// Effectively inverts the comparison operator. Example: WHERE FirstName <> 'Foo'. - /// An instance of IFieldPredicate. - public static IFieldPredicate Field(Expression> expression, Operator op, object value, string tableName = null, string schemaName = null, bool not = false) where T : class - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - return new FieldPredicate - { - PropertyName = propertyInfo.Name, - Operator = op, - Value = value, - Not = not, - SchemaName = schemaName, - TableName = tableName - }; - } - - public static IFieldPredicate Field(Type type,string PropertyName, Operator op, object value, string tableName = null, string schemaName = null, bool not = false) - { - PropertyInfo propertyInfo = type.GetProperties().Where(w => w.Name == PropertyName).First(); - return new FieldPredicate - { - FieldType = type, - PropertyName = propertyInfo.Name, - Operator = op, - Value = value, - Not = not, - SchemaName = schemaName, - TableName = tableName - }; - } - - /// - /// Factory method that creates a new IPropertyPredicate predicate: [FieldName1] [Operator] [FieldName2] - /// Example: WHERE FirstName = LastName - /// - /// The type of the entity for the left operand. - /// The type of the entity for the right operand. - /// An expression that returns the left operand [FieldName1]. - /// The comparison operator. - /// An expression that returns the right operand [FieldName2]. - /// Effectively inverts the comparison operator. Example: WHERE FirstName <> LastName - /// An instance of IPropertyPredicate. - public static IPropertyPredicate Property(Expression> expression, Operator op, Expression> expression2, string tableName = null, string tableName2 = null, string schemaName = null, string schemaName2 = null, bool not = false) - where T : class - where T2 : class - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - PropertyInfo propertyInfo2 = ReflectionHelper.GetProperty(expression2) as PropertyInfo; - return new PropertyPredicate - { - SchemaName = schemaName, - TableName = tableName, - SchemaName2 = schemaName2, - TableName2 = tableName2, - PropertyName = propertyInfo.Name, - PropertyName2 = propertyInfo2.Name, - Operator = op, - Not = not - }; - } - - /// - /// 关联查询列表重复设置 - /// - /// - /// - /// - /// - /// - public static IJoinAliasPredicate JoinAlia(Expression> expression, Expression> expression2) - where T : class - where T2 : class - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - PropertyInfo propertyInfo2 = ReflectionHelper.GetProperty(expression2) as PropertyInfo; - return new JoinAliasPredicate - { - PropertyName = propertyInfo.Name, - PropertyName2 = propertyInfo2.Name - }; - } - - /// - /// 设置关联查询 - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static IJoinPredicate Join(Expression> expression, Operator op, Expression> expression2, JoinOperator join = JoinOperator.Inner, string tableName = null, string tableName2 = null, string schemaName = null, string schemaName2 = null, bool not = false) - where T : class - where T2 : class - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - PropertyInfo propertyInfo2 = ReflectionHelper.GetProperty(expression2) as PropertyInfo; - return new JoinPredicate - { - SchemaName = schemaName, - TableName = tableName, - SchemaName2 = schemaName2, - TableName2 = tableName2, - Join = join, - PropertyName = propertyInfo.Name, - PropertyName2 = propertyInfo2.Name, - Operator = op, - Not = not - }; - } - - /// - /// Factory method that creates a new IPredicateGroup predicate. - /// Predicate groups can be joined together with other predicate groups. - /// - /// The grouping operator to use when joining the predicates (AND / OR). - /// A list of predicates to group. - /// An instance of IPredicateGroup. - public static IPredicateGroup Group(GroupOperator op, params IPredicate[] predicate) - { - return new PredicateGroup - { - Operator = op, - Predicates = predicate - }; - } - - /// - /// Factory method that creates a new IExistsPredicate predicate. - /// - public static IExistsPredicate Exists(IPredicate predicate, bool not = false) - where TSub : class - { - return new ExistsPredicate - { - Not = not, - Predicate = predicate - }; - } - - /// - /// Factory method that creates a new IBetweenPredicate predicate. - /// - public static IBetweenPredicate Between(Expression> expression, BetweenValues values, string tableName = null, string schemaName = null, bool not = false) - where T : class - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - return new BetweenPredicate - { - Not = not, - PropertyName = propertyInfo.Name, - Value = values, - SchemaName = schemaName, - TableName = tableName - }; - } - - /// - /// Factory method that creates a new Sort which controls how the results will be sorted. - /// - public static ISort Sort(Expression> expression, bool ascending = true, string tableName = null, string schemaName = null) - { - PropertyInfo propertyInfo = ReflectionHelper.GetProperty(expression) as PropertyInfo; - return new Sort - { - PropertyName = propertyInfo.Name, - Ascending = ascending, - SchemaName = schemaName, - TableName = tableName - }; - } - } - - /// - /// 条件 - /// - public interface IPredicate - { - /// - /// 返回条件的类 - /// - /// - Type GetPredicateType(); - - /// - /// 返回条件的sql - /// - /// - /// - /// - /// - /// - string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName); - } - - /// - /// 基本条件 - /// - public interface IBasePredicate : IPredicate - { - /// - /// 前缀 - /// - string SchemaName { get; set; } - /// - /// 表名 - /// - string TableName { get; set; } - - /// - /// 条件属性 - /// - string PropertyName { get; set; } - - } - - /// - /// 基本条件 - /// - public abstract class BasePredicate : IBasePredicate - { - public abstract Type GetPredicateType(); - - /// - /// 返回sql - /// - /// - /// - /// - /// - /// - public abstract string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName); - /// - /// 条件属性 - /// - public string PropertyName { get; set; } - /// - /// 前缀 - /// - public string SchemaName { get; set; } - /// - /// 表名 - /// - public string TableName { get; set; } - - /// - /// 返回列名 - /// - /// - /// - /// - /// - /// - /// - protected virtual string GetColumnName(bool prefix, Type entityType, ISqlGenerator sqlGenerator, string propertyName, string schemaName, string tableName) - { - IClassMapper map = GetMapper(entityType, sqlGenerator); - if (map == null) - { - throw new NullReferenceException(string.Format("Map was not found for {0}", entityType)); - } - - IPropertyMap propertyMap = map.Properties.SingleOrDefault(p => p.Name == propertyName); - if (propertyMap == null) - { - throw new NullReferenceException(string.Format("{0} was not found for {1}", propertyName, entityType)); - } - return sqlGenerator.GetColumnName(prefix,map, propertyMap, false, schemaName, tableName); - } - - protected virtual IClassMapper GetMapper(Type entityType, ISqlGenerator sqlGenerator) - { - return sqlGenerator.Configuration.GetMap(entityType); - } - } - - /// - /// 比较条件 - /// - public interface IComparePredicate : IBasePredicate - { - /// - /// 操作符 - /// - Operator Operator { get; set; } - /// - /// 操作符取反 - /// - bool Not { get; set; } - } - - public abstract class ComparePredicate : BasePredicate - { - public Operator Operator { get; set; } - public bool Not { get; set; } - - public virtual string GetOperatorString(ISqlGenerator sqlGenerator) => sqlGenerator.GetOperatorString(Operator, Not); - } - - public interface IFieldPredicate : IComparePredicate - { - object Value { get; set; } - } - - public class FieldPredicate : ComparePredicate, IFieldPredicate - where T : class - { - public override Type GetPredicateType() - { - return typeof(T); - } - public object Value { get; set; } - - public override string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - string columnName = GetColumnName(prefix,typeof(T), sqlGenerator, PropertyName, SchemaName ?? schemaName, TableName ?? tableName); - if (Value == null) - { - return string.Format("({0} IS {1}NULL)", columnName, Not ? "NOT " : string.Empty); - } - - if (Value is IEnumerable && !(Value is string)) - { - if (Operator != Operator.Eq) - { - throw new ArgumentException("Operator must be set to Eq for Enumerable types"); - } - - List @params = new List(); - foreach (var value in (IEnumerable)Value) - { - string valueParameterName = parameters.SetParameterName(this.PropertyName, value, sqlGenerator.Configuration.Dialect.ParameterPrefix); - @params.Add(valueParameterName); - } - - string paramStrings = @params.Aggregate(new StringBuilder(), (sb, s) => sb.Append((sb.Length != 0 ? ", " : string.Empty) + s), sb => sb.ToString()); - return string.Format("({0} {1}IN ({2}))", columnName, Not ? "NOT " : string.Empty, paramStrings); - } - - string parameterName = parameters.SetParameterName(this.PropertyName, this.Value, sqlGenerator.Configuration.Dialect.ParameterPrefix); - return string.Format("({0} {1} {2})", columnName, GetOperatorString(sqlGenerator), parameterName); - } - } - - public class FieldPredicate : ComparePredicate, IFieldPredicate - { - public override Type GetPredicateType() - { - return FieldType; - } - public Type FieldType { get; set; } - - public object Value { get; set; } - - public override string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - string columnName = GetColumnName(prefix,FieldType, sqlGenerator, PropertyName, SchemaName ?? schemaName, TableName ?? tableName); - if (Value == null) - { - return string.Format("({0} IS {1}NULL)", columnName, Not ? "NOT " : string.Empty); - } - - if (Value is IEnumerable && !(Value is string)) - { - if (Operator != Operator.Eq) - { - throw new ArgumentException("Operator must be set to Eq for Enumerable types"); - } - - List @params = new List(); - foreach (var value in (IEnumerable)Value) - { - string valueParameterName = parameters.SetParameterName(this.PropertyName, value, sqlGenerator.Configuration.Dialect.ParameterPrefix); - @params.Add(valueParameterName); - } - - string paramStrings = @params.Aggregate(new StringBuilder(), (sb, s) => sb.Append((sb.Length != 0 ? ", " : string.Empty) + s), sb => sb.ToString()); - return string.Format("({0} {1}IN ({2}))", columnName, Not ? "NOT " : string.Empty, paramStrings); - } - - string parameterName = parameters.SetParameterName(this.PropertyName, this.Value, sqlGenerator.Configuration.Dialect.ParameterPrefix); - return string.Format("({0} {1} {2})", columnName, GetOperatorString(sqlGenerator), parameterName); - } - } - - public interface IJoinPredicate : IComparePredicate - { - - string SchemaName2 { get; set; } - string TableName2 { get; set; } - string PropertyName2 { get; set; } - JoinOperator Join { get; set; } - IClassMapper GetLeftMapper(ISqlGenerator sqlGenerator); - IClassMapper GetRightMapper(ISqlGenerator sqlGenerator); - } - - public class JoinPredicate : ComparePredicate, IJoinPredicate - where T : class - where T2 : class - { - public override Type GetPredicateType() - { - return typeof(T); - } - public string PropertyName2 { get; set; } - - public JoinOperator Join { get; set; } - - public string SchemaName2 { get; set; } - public string TableName2 { get; set; } - - public IClassMapper GetLeftMapper(ISqlGenerator sqlGenerator) - { - return GetMapper(typeof(T), sqlGenerator); - } - - public IClassMapper GetRightMapper(ISqlGenerator sqlGenerator) - { - return GetMapper(typeof(T2), sqlGenerator); - } - - public override string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - string righttable = sqlGenerator.GetTableName(GetRightMapper(sqlGenerator), SchemaName2, TableName2); - string columnName = GetColumnName(true,typeof(T), sqlGenerator, PropertyName, SchemaName ?? schemaName, TableName ?? tableName); - string columnName2 = GetColumnName(true,typeof(T2), sqlGenerator, PropertyName2, SchemaName2, TableName2); - string vjoin = Join == JoinOperator.Full ? "full join" : Join == JoinOperator.Left ? "left join" : Join == JoinOperator.Right ? "right join" : "inner join"; - return $" {vjoin} {righttable} on {columnName} {GetOperatorString(sqlGenerator)} {columnName2}"; - } - } - - public interface IJoinAliasPredicate : IComparePredicate - { - string PropertyName2 { get; set; } - - IClassMapper GetRightMapper(ISqlGenerator sqlGenerator); - IPropertyMap GetPropertyMap(ISqlGenerator sqlGenerator); - } - public class JoinAliasPredicate : ComparePredicate, IJoinAliasPredicate - where T : class - where T2 : class - { - public override Type GetPredicateType() - { - return typeof(T); - } - public string PropertyName2 { get; set; } - - public IClassMapper GetRightMapper(ISqlGenerator sqlGenerator) - { - return GetMapper(typeof(T2), sqlGenerator); - } - - public IPropertyMap GetPropertyMap(ISqlGenerator sqlGenerator) - { - var rightMap = GetRightMapper(sqlGenerator); - var property = rightMap.Properties.Where(w => w.Name.Equals(PropertyName2)).First(); - return property; - } - - public override string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - return string.Empty; - } - } - - public interface IPropertyPredicate : IComparePredicate - { - string SchemaName2 { get; set; } - string TableName2 { get; set; } - string PropertyName2 { get; set; } - } - - - public class PropertyPredicate : ComparePredicate, IPropertyPredicate - where T : class - where T2 : class - { - public override Type GetPredicateType() - { - return typeof(T); - } - public string PropertyName2 { get; set; } - public string SchemaName2 { get; set; } - public string TableName2 { get; set; } - - public override string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - string columnName = GetColumnName(prefix,typeof(T), sqlGenerator, PropertyName, SchemaName ?? schemaName, TableName ?? tableName); - string columnName2 = GetColumnName(prefix, typeof(T2), sqlGenerator, PropertyName2, schemaName, tableName); - return string.Format("({0} {1} {2})", columnName, GetOperatorString(sqlGenerator), columnName2); - } - } - - public struct BetweenValues - { - public object Value1 { get; set; } - public object Value2 { get; set; } - } - - public interface IBetweenPredicate : IPredicate - { - string PropertyName { get; set; } - BetweenValues Value { get; set; } - bool Not { get; set; } - - } - - public class BetweenPredicate : BasePredicate, IBetweenPredicate - where T : class - { - public override Type GetPredicateType() - { - return typeof(T); - } - public override string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - string columnName = GetColumnName(prefix, typeof(T), sqlGenerator, PropertyName, SchemaName ?? schemaName, TableName ?? tableName); - string propertyName1 = parameters.SetParameterName(this.PropertyName, this.Value.Value1, sqlGenerator.Configuration.Dialect.ParameterPrefix); - string propertyName2 = parameters.SetParameterName(this.PropertyName, this.Value.Value2, sqlGenerator.Configuration.Dialect.ParameterPrefix); - return string.Format("({0} {1}BETWEEN {2} AND {3})", columnName, Not ? "NOT " : string.Empty, propertyName1, propertyName2); - } - - public BetweenValues Value { get; set; } - - public bool Not { get; set; } - } - - /// - /// Comparison operator for predicates. - /// - public enum Operator - { - /// - /// Equal to = - /// - Eq, - - /// - /// Greater than > - /// - Gt, - - /// - /// Greater than or equal to >= - /// - Ge, - - /// - /// Less than < - /// - Lt, - - /// - /// Less than or equal to <= - /// - Le, - - /// - /// Like (You can use % in the value to do wilcard searching) - /// - Like - } - - public interface IPredicateGroup : IPredicate - { - GroupOperator Operator { get; set; } - IList Predicates { get; set; } - } - - /// - /// Groups IPredicates together using the specified group operator. - /// - public class PredicateGroup : IPredicateGroup - { - public Type GetPredicateType() - { - return null; - } - public GroupOperator Operator { get; set; } - public IList Predicates { get; set; } - public string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - string seperator = Operator == GroupOperator.And ? " AND " : " OR "; - return "(" + Predicates.Aggregate(new StringBuilder(), - (sb, p) => (sb.Length == 0 ? sb : sb.Append(seperator)).Append(p.GetSql(prefix, sqlGenerator, parameters, schemaName, tableName)), - sb => - { - var s = sb.ToString(); - if (s.Length == 0) return sqlGenerator.Configuration.Dialect.EmptyExpression; - return s; - } - ) + ")"; - } - } - - public interface IExistsPredicate : IPredicate - { - IPredicate Predicate { get; set; } - bool Not { get; set; } - } - - public class ExistsPredicate : IExistsPredicate - where TSub : class - { - public Type GetPredicateType() - { - return typeof(TSub); - } - public IPredicate Predicate { get; set; } - public bool Not { get; set; } - - public string GetSql(bool prefix, ISqlGenerator sqlGenerator, IDictionary parameters, string schemaName, string tableName) - { - IClassMapper mapSub = sqlGenerator.Configuration.GetMap(typeof(TSub)); - string sql = string.Format("({0}EXISTS (SELECT 1 FROM {1} WHERE {2}))", - Not ? "NOT " : string.Empty, - sqlGenerator.GetTableName(mapSub, schemaName, tableName), - Predicate.GetSql(prefix, sqlGenerator, parameters, schemaName, tableName)); - return sql; - } - } - - public interface ISort - { - string SchemaName { get; set; } - /// - /// 表名 - /// - string TableName { get; set; } - string PropertyName { get; set; } - bool Ascending { get; set; } - string GetSql(bool prefix, ISqlGenerator sqlGenerator, string schemaName, string tableName); - } - - public class Sort : ISort - { - /// - /// 前缀 - /// - public string SchemaName { get; set; } - /// - /// 表名 - /// - public string TableName { get; set; } - public string PropertyName { get; set; } - public bool Ascending { get; set; } - - public string GetSql(bool prefix, ISqlGenerator sqlGenerator, string schemaName, string tableName) - { - return sqlGenerator.GetColumnName(prefix,sqlGenerator.Configuration.GetMap(typeof(T)), PropertyName, false, SchemaName ?? schemaName, TableName ?? tableName) + (Ascending ? " ASC" : " DESC"); - } - } - internal class SortKey : ISort - { - private IClassMapper classMapper { get; set; } - public SortKey(IClassMapper classMapper) - { - this.classMapper = classMapper; - } - - /// - /// 前缀 - /// - public string SchemaName { get; set; } - /// - /// 表名 - /// - public string TableName { get; set; } - public string PropertyName { get; set; } - public bool Ascending { get; set; } - - public string GetSql(bool prefix, ISqlGenerator sqlGenerator, string schemaName, string tableName) - { - return sqlGenerator.GetColumnName(prefix,classMapper, PropertyName, false, SchemaName ?? schemaName, TableName ?? tableName) + (Ascending ? " ASC" : " DESC"); - } - } - - /// - /// 在条件组中的操作符 Operator to use when joining predicates in a PredicateGroup. - /// - public enum GroupOperator - { - And, - Or - } - - public enum JoinOperator - { - /// - /// 内关联 - /// - Inner, - /// - /// 左关联 - /// - Left, - /// - /// 右关联 - /// - Right, - /// - /// 全关联 - /// - Full - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/ReflectionHelper.cs b/samples/Common/Repository.Dapper.Core/ReflectionHelper.cs deleted file mode 100644 index ab21ff211..000000000 --- a/samples/Common/Repository.Dapper.Core/ReflectionHelper.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; - -namespace Repository.Dapper.Core -{ - public static class ReflectionHelper - { - private static List _simpleTypes = new List - { - typeof(byte), - typeof(sbyte), - typeof(short), - typeof(ushort), - typeof(int), - typeof(uint), - typeof(long), - typeof(ulong), - typeof(float), - typeof(double), - typeof(decimal), - typeof(bool), - typeof(string), - typeof(char), - typeof(Guid), - typeof(DateTime), - typeof(DateTimeOffset), - typeof(byte[]) - }; - - public static MemberInfo GetProperty(LambdaExpression lambda) - { - Expression expr = lambda; - for (; ; ) - { - switch (expr.NodeType) - { - case ExpressionType.Lambda: - expr = ((LambdaExpression)expr).Body; - break; - case ExpressionType.Convert: - expr = ((UnaryExpression)expr).Operand; - break; - case ExpressionType.MemberAccess: - MemberExpression memberExpression = (MemberExpression)expr; - MemberInfo mi = memberExpression.Member; - return mi; - default: - return null; - } - } - } - - public static IDictionary GetObjectValues(object obj) - { - IDictionary result = new Dictionary(); - if (obj == null) - { - return result; - } - if (obj is IDictionary) - return obj as IDictionary; - - foreach (var propertyInfo in obj.GetType().GetProperties()) - { - string name = propertyInfo.Name; - object value = propertyInfo.GetValue(obj, null); - result[name] = value; - } - - return result; - } - - public static string AppendStrings(this IEnumerable list, string seperator = ", ") - { - return list.Aggregate( - new StringBuilder(), - (sb, s) => (sb.Length == 0 ? sb : sb.Append(seperator)).Append(s), - sb => sb.ToString()); - } - - public static bool IsSimpleType(Type type) - { - Type actualType = type; - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - actualType = type.GetGenericArguments()[0]; - } - - return _simpleTypes.Contains(actualType); - } - - public static string GetParameterName(this IDictionary parameters, string parameterName, char parameterPrefix) - { - return string.Format("{0}{1}_{2}", parameterPrefix, parameterName, parameters.Count); - } - - public static string SetParameterName(this IDictionary parameters, string parameterName, object value, char parameterPrefix) - { - string name = parameters.GetParameterName(parameterName, parameterPrefix); - parameters.Add(name, value); - return name; - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Repository.Dapper.Core.csproj b/samples/Common/Repository.Dapper.Core/Repository.Dapper.Core.csproj deleted file mode 100644 index fac8c0a0b..000000000 --- a/samples/Common/Repository.Dapper.Core/Repository.Dapper.Core.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - - - DapperExtensions - Xakep - netstandard2.0 - DapperExtensions - Xakep.DapperExtensions - 1.6.2.91 - true - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/Common/Repository.Dapper.Core/Sql/DB2Dialect.cs b/samples/Common/Repository.Dapper.Core/Sql/DB2Dialect.cs deleted file mode 100644 index 836960bbd..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/DB2Dialect.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public class DB2Dialect : SqlDialectBase - { - public override string GetIdentitySql(string tableName) - { - return "SELECT CAST(IDENTITY_VAL_LOCAL() AS BIGINT) AS \"ID\" FROM SYSIBM.SYSDUMMY1"; - } - - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - var startValue = ((page - 1) * resultsPerPage) + 1; - var endValue = (page * resultsPerPage); - return GetSetSql(sql, startValue, endValue, parameters); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - if (string.IsNullOrEmpty(sql)) - { - throw new ArgumentNullException("SQL"); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - int selectIndex = GetSelectEnd(sql) + 1; - string orderByClause = GetOrderByClause(sql); - if (orderByClause == null) - { - orderByClause = "ORDER BY CURRENT_TIMESTAMP"; - } - - - string projectedColumns = GetColumnNames(sql).Aggregate(new StringBuilder(), (sb, s) => (sb.Length == 0 ? sb : sb.Append(", ")).Append(GetColumnName("_TEMP", s, null)), sb => sb.ToString()); - string newSql = sql - .Replace(" " + orderByClause, string.Empty) - .Insert(selectIndex, string.Format("ROW_NUMBER() OVER(ORDER BY {0}) AS {1}, ", orderByClause.Substring(9), GetColumnName(null, "_ROW_NUMBER", null))); - - string result = string.Format("SELECT {0} FROM ({1}) AS \"_TEMP\" WHERE {2} BETWEEN @_pageStartRow AND @_pageEndRow", - projectedColumns.Trim(), newSql, GetColumnName("_TEMP", "_ROW_NUMBER", null)); - - parameters.Add("@_pageStartRow", firstResult); - parameters.Add("@_pageEndRow", maxResults); - return result; - } - - protected string GetOrderByClause(string sql) - { - int orderByIndex = sql.LastIndexOf(" ORDER BY ", StringComparison.InvariantCultureIgnoreCase); - if (orderByIndex == -1) - { - return null; - } - - string result = sql.Substring(orderByIndex).Trim(); - - int whereIndex = result.IndexOf(" WHERE ", StringComparison.InvariantCultureIgnoreCase); - if (whereIndex == -1) - { - return result; - } - - return result.Substring(0, whereIndex).Trim(); - } - - protected int GetFromStart(string sql) - { - int selectCount = 0; - string[] words = sql.Split(' '); - int fromIndex = 0; - foreach (var word in words) - { - if (word.Equals("SELECT", StringComparison.InvariantCultureIgnoreCase)) - { - selectCount++; - } - - if (word.Equals("FROM", StringComparison.InvariantCultureIgnoreCase)) - { - selectCount--; - if (selectCount == 0) - { - break; - } - } - - fromIndex += word.Length + 1; - } - - return fromIndex; - } - - protected virtual int GetSelectEnd(string sql) - { - if (sql.StartsWith("SELECT DISTINCT", StringComparison.InvariantCultureIgnoreCase)) - { - return 15; - } - - if (sql.StartsWith("SELECT", StringComparison.InvariantCultureIgnoreCase)) - { - return 6; - } - - throw new ArgumentException("SQL must be a SELECT statement.", "sql"); - } - - protected virtual IList GetColumnNames(string sql) - { - int start = GetSelectEnd(sql); - int stop = GetFromStart(sql); - string[] columnSql = sql.Substring(start, stop - start).Split(','); - List result = new List(); - foreach (string c in columnSql) - { - int index = c.IndexOf(" AS ", StringComparison.InvariantCultureIgnoreCase); - if (index > 0) - { - result.Add(c.Substring(index + 4).Trim()); - continue; - } - - string[] colParts = c.Split('.'); - result.Add(colParts[colParts.Length - 1].Trim()); - } - - return result; - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Sql/MySqlDialect.cs b/samples/Common/Repository.Dapper.Core/Sql/MySqlDialect.cs deleted file mode 100644 index a8adde9b5..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/MySqlDialect.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Repository.Dapper.Core.Sql -{ - public class MySqlDialect : SqlDialectBase - { - public override char OpenQuote - { - get { return '`'; } - } - - public override char CloseQuote - { - get { return '`'; } - } - - public override string GetIdentitySql(string tableName) - { - return "SELECT CONVERT(LAST_INSERT_ID(), SIGNED INTEGER) AS ID"; - } - - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - int startValue = page * resultsPerPage; - return GetSetSql(sql, startValue, resultsPerPage, parameters); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - string result = string.Format("{0} LIMIT @firstResult, @maxResults", sql); - parameters.Add("@firstResult", firstResult); - parameters.Add("@maxResults", maxResults); - return result; - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Sql/OracleDialect.cs b/samples/Common/Repository.Dapper.Core/Sql/OracleDialect.cs deleted file mode 100644 index 336cf7720..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/OracleDialect.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Collections.Generic; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public class OracleDialect : SqlDialectBase - { - public OracleDialect() { } - - public override string GetIdentitySql(string tableName) - { - throw new System.NotImplementedException("Oracle does not support get last inserted identity."); - } - - public override bool SupportsMultipleStatements - { - get { return false; } - } - - //from Simple.Data.Oracle implementation https://github.com/flq/Simple.Data.Oracle/blob/master/Simple.Data.Oracle/OraclePager.cs - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - var toSkip = page * resultsPerPage; - var topLimit = (page + 1) * resultsPerPage; - - var sb = new StringBuilder(); - sb.AppendLine("SELECT * FROM ("); - sb.AppendLine("SELECT \"_ss_dapper_1_\".*, ROWNUM RNUM FROM ("); - sb.Append(sql); - sb.AppendLine(") \"_ss_dapper_1_\""); - sb.AppendLine("WHERE ROWNUM <= :topLimit) \"_ss_dapper_2_\" "); - sb.AppendLine("WHERE \"_ss_dapper_2_\".RNUM > :toSkip"); - - parameters.Add(":topLimit", topLimit); - parameters.Add(":toSkip", toSkip); - - return sb.ToString(); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - var sb = new StringBuilder(); - sb.AppendLine("SELECT * FROM ("); - sb.AppendLine("SELECT \"_ss_dapper_1_\".*, ROWNUM RNUM FROM ("); - sb.Append(sql); - sb.AppendLine(") \"_ss_dapper_1_\""); - sb.AppendLine("WHERE ROWNUM <= :topLimit) \"_ss_dapper_2_\" "); - sb.AppendLine("WHERE \"_ss_dapper_2_\".RNUM > :toSkip"); - - parameters.Add(":topLimit", maxResults + firstResult); - parameters.Add(":toSkip", firstResult); - - return sb.ToString(); - } - - public override string QuoteString(string value) - { - if (value != null && value[0]=='`') - { - return string.Format("{0}{1}{2}", OpenQuote, value.Substring(1, value.Length - 2), CloseQuote); - } - return value.ToUpper(); - } - - public override char ParameterPrefix - { - get { return ':'; } - } - - public override char OpenQuote - { - get { return '"'; } - } - - public override char CloseQuote - { - get { return '"'; } - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Sql/PostgreSqlDialect.cs b/samples/Common/Repository.Dapper.Core/Sql/PostgreSqlDialect.cs deleted file mode 100644 index 9af35d41d..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/PostgreSqlDialect.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public class PostgreSqlDialect : SqlDialectBase - { - public override string GetIdentitySql(string tableName) - { - return "SELECT LASTVAL() AS Id"; - } - - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - int startValue = (page-1) * resultsPerPage; - return GetSetSql(sql, startValue < 0 ? 0 : startValue, resultsPerPage, parameters); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - string result = string.Format("{0} LIMIT @maxResults OFFSET @pageStartRowNbr", sql); - parameters.Add("@maxResults", maxResults); - parameters.Add("@pageStartRowNbr", firstResult); - return result; - } - - public override string GetColumnName(string prefix, string columnName, string alias) - { - return base.GetColumnName(prefix, columnName, alias);//.ToLower(); - } - - public override string GetTableName(string schemaName, string tableName, string alias) - { - return base.GetTableName(schemaName, tableName, alias);//.ToLower(); - } - public override string GetOperatorString(Operator Operator, bool Not) - { - switch (Operator) - { - case Operator.Gt: - return Not ? "<=" : ">"; - case Operator.Ge: - return Not ? "<" : ">="; - case Operator.Lt: - return Not ? ">=" : "<"; - case Operator.Le: - return Not ? ">" : "<="; - case Operator.Like: - return Not ? "NOT ILIKE" : "ILIKE"; - default: - return Not ? "<>" : "="; - } - } - } - -} diff --git a/samples/Common/Repository.Dapper.Core/Sql/SqlCeDialect.cs b/samples/Common/Repository.Dapper.Core/Sql/SqlCeDialect.cs deleted file mode 100644 index e5a74145a..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/SqlCeDialect.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public class SqlCeDialect : SqlDialectBase - { - public override char OpenQuote - { - get { return '['; } - } - - public override char CloseQuote - { - get { return ']'; } - } - - public override bool SupportsMultipleStatements - { - get { return false; } - } - - public override string GetTableName(string schemaName, string tableName, string alias) - { - if (string.IsNullOrWhiteSpace(tableName)) - { - throw new ArgumentNullException("TableName"); - } - - StringBuilder result = new StringBuilder(); - result.Append(OpenQuote); - if (!string.IsNullOrWhiteSpace(schemaName)) - { - result.AppendFormat("{0}_", schemaName); - } - - result.AppendFormat("{0}{1}", tableName, CloseQuote); - - - if (!string.IsNullOrWhiteSpace(alias)) - { - result.AppendFormat(" AS {0}{1}{2}", OpenQuote, alias, CloseQuote); - } - - return result.ToString(); - } - - public override string GetIdentitySql(string tableName) - { - return "SELECT CAST(@@IDENTITY AS BIGINT) AS [Id]"; - } - - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - int startValue = (page * resultsPerPage); - return GetSetSql(sql, startValue, resultsPerPage, parameters); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - string result = string.Format("{0} OFFSET @firstResult ROWS FETCH NEXT @maxResults ROWS ONLY", sql); - parameters.Add("@firstResult", firstResult); - parameters.Add("@maxResults", maxResults); - return result; - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Sql/SqlDialectBase.cs b/samples/Common/Repository.Dapper.Core/Sql/SqlDialectBase.cs deleted file mode 100644 index 339111991..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/SqlDialectBase.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public interface ISqlDialect - { - char OpenQuote { get; } - char CloseQuote { get; } - string BatchSeperator { get; } - bool SupportsMultipleStatements { get; } - char ParameterPrefix { get; } - string EmptyExpression { get; } - string GetTableName(string schemaName, string tableName, string alias); - string GetColumnName(string prefix, string columnName, string alias); - string GetIdentitySql(string tableName); - string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters); - string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters); - bool IsQuoted(string value); - string QuoteString(string value); - string GetOperatorString(Operator Operator, bool Not); - } - - public abstract class SqlDialectBase : ISqlDialect - { - public virtual char OpenQuote - { - get { return '"'; } - } - - public virtual char CloseQuote - { - get { return '"'; } - } - - public virtual string BatchSeperator - { - get { return ";" + Environment.NewLine; } - } - - public virtual bool SupportsMultipleStatements - { - get { return true; } - } - - public virtual char ParameterPrefix - { - get - { - return '@'; - } - } - - public string EmptyExpression - { - get - { - return "1=1"; - } - } - - public virtual string GetTableName(string schemaName, string tableName, string alias) - { - if (string.IsNullOrWhiteSpace(tableName)) - { - throw new ArgumentNullException("TableName", "tableName cannot be null or empty."); - } - - StringBuilder result = new StringBuilder(); - if (!string.IsNullOrWhiteSpace(schemaName)) - { - result.AppendFormat(QuoteString(schemaName) + "."); - } - - result.AppendFormat(QuoteString(tableName)); - - if (!string.IsNullOrWhiteSpace(alias)) - { - result.AppendFormat(" AS {0}", QuoteString(alias)); - } - return result.ToString(); - } - - public virtual string GetColumnName(string prefix, string columnName, string alias) - { - if (string.IsNullOrWhiteSpace(columnName)) - { - throw new ArgumentNullException("ColumnName", "columnName cannot be null or empty."); - } - - StringBuilder result = new StringBuilder(); - if (!string.IsNullOrWhiteSpace(prefix)) - { - result.AppendFormat(QuoteString(prefix) + "."); - } - - result.AppendFormat(QuoteString(columnName)); - - if (!string.IsNullOrWhiteSpace(alias)) - { - result.AppendFormat(" AS {0}", QuoteString(alias)); - } - - return result.ToString(); - } - - public abstract string GetIdentitySql(string tableName); - public abstract string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters); - public abstract string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters); - - public virtual bool IsQuoted(string value) - { - if (value.Trim()[0] == OpenQuote) - { - return value.Trim().Last() == CloseQuote; - } - - return false; - } - - public virtual string QuoteString(string value) - { - if (IsQuoted(value) || value == "*") - { - return value; - } - return string.Format("{0}{1}{2}", OpenQuote, value.Trim(), CloseQuote); - } - - public virtual string UnQuoteString(string value) - { - return IsQuoted(value) ? value.Substring(1, value.Length - 2) : value; - } - - public virtual string GetOperatorString(Operator Operator, bool Not) - { - switch (Operator) - { - case Operator.Gt: - return Not ? "<=" : ">"; - case Operator.Ge: - return Not ? "<" : ">="; - case Operator.Lt: - return Not ? ">=" : "<"; - case Operator.Le: - return Not ? ">" : "<="; - case Operator.Like: - return Not ? "NOT LIKE" : "LIKE"; - default: - return Not ? "<>" : "="; - } - } - } -} diff --git a/samples/Common/Repository.Dapper.Core/Sql/SqlGenerator.cs b/samples/Common/Repository.Dapper.Core/Sql/SqlGenerator.cs deleted file mode 100644 index dfd5379e0..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/SqlGenerator.cs +++ /dev/null @@ -1,413 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Repository.Dapper.Core.Mapper; - -namespace Repository.Dapper.Core.Sql -{ - public interface ISqlGenerator - { - IDapperExtensionsConfiguration Configuration { get; } - - string Select(IClassMapper classMap, IPredicate predicate, IList sort, IDictionary parameters, string schemaName, string tableName, IList join=null, IList alias = null); - - string SelectPaged(IClassMapper classMap, IPredicate predicate, IList sort, int page, int resultsPerPage, IDictionary parameters, string schemaName, string tableName, IList join, IList alias); - string SelectSet(IClassMapper classMap, IPredicate predicate, IList sort, int firstResult, int maxResults, IDictionary parameters, string schemaName, string tableName, IList join, IList alias); - string Count(IClassMapper classMap, IPredicate predicate, IDictionary parameters, string schemaName, string tableName, IList join); - - string Insert(IClassMapper classMap, string schemaName, string tableName); - string Update(IClassMapper classMap, IPredicate predicate, IDictionary parameters, string schemaName, string tableName); - string UpdateSet(IClassMapper classMap,object entity, IPredicate predicate, IDictionary parameters, string schemaName, string tableName); - string Delete(IClassMapper classMap, IPredicate predicate, IDictionary parameters, string schemaName, string tableName); - - string IdentitySql(IClassMapper classMap, string schemaName, string tableName); - string GetTableName(IClassMapper map, string schemaName, string tableName, IList join = null); - string GetColumnName(bool prefix,IClassMapper map, IPropertyMap property, bool includeAlias, string schemaName, string tableName, string aliasName = null); - string GetColumnName(bool prefix, IClassMapper map, string propertyName, bool includeAlias, string schemaName, string tableName); - bool SupportsMultipleStatements(); - string GetOperatorString(Operator Operator, bool Not); - } - - public class SqlGeneratorImpl : ISqlGenerator - { - public SqlGeneratorImpl(IDapperExtensionsConfiguration configuration) - { - Configuration = configuration; - } - - public IDapperExtensionsConfiguration Configuration { get; private set; } - - public virtual string Select(IClassMapper classMap, IPredicate predicate, IList sort, IDictionary parameters, string schemaName, string tableName, IList join=null, IList alias=null) - { - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - StringBuilder sql = new StringBuilder(string.Format("SELECT {0} FROM {1}", - BuildSelectColumns(classMap, schemaName, tableName,join,alias), - GetTableName(classMap, schemaName, tableName,join))); - - if (predicate != null) - { - sql.Append(" WHERE ") - .Append(predicate.GetSql(join!=null,this, parameters,schemaName,tableName)); - } - - if (sort != null && sort.Any()) - { - sql.Append(" ORDER BY ") - .Append(sort.Select(s => s.GetSql(join != null,this, schemaName,tableName)).AppendStrings()); - } - - return sql.ToString(); - } - - public virtual string SelectPaged(IClassMapper classMap, IPredicate predicate, IList sort, int page, int resultsPerPage, IDictionary parameters, string schemaName, string tableName, IList join, IList alias) - { - if (sort == null || !sort.Any()) - { - sort = classMap.Properties.Where(w => w.KeyType != KeyType.NotAKey).Select(w => (ISort)new SortKey(classMap) { PropertyName = w.Name, Ascending = true }).ToList(); - //throw new ArgumentNullException("Sort", "Sort cannot be null or empty."); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - StringBuilder innerSql = new StringBuilder(string.Format("SELECT {0} FROM {1}", - BuildSelectColumns(classMap, schemaName, tableName,join,alias), - GetTableName(classMap, schemaName, tableName,join))); - if (predicate != null) - { - innerSql.Append(" WHERE ") - .Append(predicate.GetSql(join!=null,this, parameters,schemaName,tableName)); - } - - string orderBy = sort.Select(s => s.GetSql(join != null, this, schemaName, tableName)).AppendStrings(); - innerSql.Append(" ORDER BY " + orderBy); - - string sql = Configuration.Dialect.GetPagingSql(innerSql.ToString(), page, resultsPerPage, parameters); - return sql; - } - - public virtual string SelectSet(IClassMapper classMap, IPredicate predicate, IList sort, int firstResult, int maxResults, IDictionary parameters, string schemaName, string tableName, IList join, IList alias) - { - if (sort == null || !sort.Any()) - { - sort = classMap.Properties.Where(w => w.KeyType != KeyType.NotAKey).Select(w => (ISort)new SortKey(classMap) { PropertyName = w.Name, Ascending = true }).ToList(); - //throw new ArgumentNullException("Sort", "Sort cannot be null or empty."); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - StringBuilder innerSql = new StringBuilder(string.Format("SELECT {0} FROM {1}", - BuildSelectColumns(classMap, schemaName, tableName,join,alias), - GetTableName(classMap, schemaName, tableName,join))); - if (predicate != null) - { - innerSql.Append(" WHERE ") - .Append(predicate.GetSql(join != null, this, parameters,schemaName,tableName)); - } - - string orderBy = sort.Select(s => s.GetSql(join != null, this, schemaName, tableName)).AppendStrings(); - innerSql.Append(" ORDER BY " + orderBy); - - string sql = Configuration.Dialect.GetSetSql(innerSql.ToString(), firstResult, maxResults, parameters); - return sql; - } - - - public virtual string Count(IClassMapper classMap, IPredicate predicate, IDictionary parameters, string schemaName, string tableName, IList join) - { - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - StringBuilder sql = new StringBuilder(string.Format("SELECT COUNT(*) AS {0}Total{1} FROM {2}", - Configuration.Dialect.OpenQuote, - Configuration.Dialect.CloseQuote, - GetTableName(classMap, schemaName, tableName,join))); - if (predicate != null) - { - sql.Append(" WHERE ") - .Append(predicate.GetSql(join != null, this, parameters,schemaName,tableName)); - } - - return sql.ToString(); - } - - public virtual string Insert(IClassMapper classMap, string schemaName, string tableName) - { - var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.TriggerIdentity)); - if (!columns.Any()) - { - throw new ArgumentException("No columns were mapped."); - } - - var columnNames = columns.Select(p => GetColumnName(false,classMap, p, false, schemaName, tableName)); - var parameters = columns.Select(p => Configuration.Dialect.ParameterPrefix + p.Name); - - string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", - GetTableName(classMap, schemaName, tableName), - columnNames.AppendStrings(), - parameters.AppendStrings()); - - var triggerIdentityColumn = classMap.Properties.Where(p => p.KeyType == KeyType.TriggerIdentity).ToList(); - - if (triggerIdentityColumn.Count > 0) - { - if (triggerIdentityColumn.Count > 1) - throw new ArgumentException("TriggerIdentity generator cannot be used with multi-column keys"); - - sql += string.Format(" RETURNING {0} INTO {1}IdOutParam", triggerIdentityColumn.Select(p => GetColumnName(false,classMap, p, false, schemaName, tableName)).First(), Configuration.Dialect.ParameterPrefix); - } - - return sql; - } - - public virtual string Update(IClassMapper classMap, IPredicate predicate, IDictionary parameters, string schemaName, string tableName) - { - if (predicate == null) - { - throw new ArgumentNullException("Predicate"); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.Assigned)); - if (!columns.Any()) - { - throw new ArgumentException("No columns were mapped."); - } - - var setSql = - columns.Select( - p => - string.Format( - "{0} = {1}{2}", GetColumnName(false,classMap, p, false, schemaName, tableName), Configuration.Dialect.ParameterPrefix, p.Name)); - - return string.Format("UPDATE {0} SET {1} WHERE {2}", - GetTableName(classMap, schemaName, tableName), - setSql.AppendStrings(), - predicate.GetSql(false,this, parameters,schemaName,tableName)); - } - - public virtual string UpdateSet(IClassMapper classMap, object entity, IPredicate predicate, IDictionary parameters, string schemaName, string tableName) - { - if (predicate == null) - { - throw new ArgumentNullException("Predicate"); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - var columns = classMap.Properties.Where(p => !(p.Ignored || p.IsReadOnly || p.KeyType == KeyType.Identity || p.KeyType == KeyType.Assigned)); - if (!columns.Any()) - { - throw new ArgumentException("No columns were mapped."); - } - var vColName = ReflectionHelper.GetObjectValues(entity).Select(w => w.Key); - var setSql = - columns.Where(w => vColName.Contains(w.Name)).Select( - p => - string.Format( - "{0} = {1}{2}", GetColumnName(false,classMap, p, false, schemaName, tableName), Configuration.Dialect.ParameterPrefix, p.Name)); - - return string.Format("UPDATE {0} SET {1} WHERE {2}", - GetTableName(classMap, schemaName, tableName), - setSql.AppendStrings(), - predicate.GetSql(false,this, parameters, schemaName, tableName)); - } - - public virtual string Delete(IClassMapper classMap, IPredicate predicate, IDictionary parameters, string schemaName, string tableName) - { - if (predicate == null) - { - throw new ArgumentNullException("Predicate"); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - StringBuilder sql = new StringBuilder(string.Format("DELETE FROM {0}", GetTableName(classMap, schemaName, tableName))); - sql.Append(" WHERE ").Append(predicate.GetSql(false,this, parameters,schemaName,tableName)); - return sql.ToString(); - } - - public virtual string IdentitySql(IClassMapper classMap, string schemaName, string tableName) - { - return Configuration.Dialect.GetIdentitySql(GetTableName(classMap, schemaName, tableName)); - } - - public virtual string GetTableName(IClassMapper map, string schemaName, string tableName, IList join = null) - { - if (join != null && join.Count > 0) - { - var baseClassMap = join[0].GetLeftMapper(this); - var baseTable = GetTableName(baseClassMap, join[0].SchemaName, join[0].TableName); - return $"{baseTable} {string.Join(" ", join.Select(w => w.GetSql(join != null, this, null, null, null)))}"; - } - - schemaName = string.IsNullOrWhiteSpace(schemaName) ? map.SchemaName : schemaName; - tableName = string.IsNullOrWhiteSpace(tableName) ? map.TableName : tableName; - return Configuration.Dialect.GetTableName(schemaName, tableName, null); - } - - public virtual string GetColumnName(bool prefix, IClassMapper map, IPropertyMap property, bool includeAlias, string schemaName, string tableName, string aliasName = null) - { - string alias = null; - string propertyName = property.Name; - if (aliasName != null) - { - propertyName = aliasName; - } - if (property.ColumnName != propertyName && includeAlias) - { - alias = propertyName; - } - - return Configuration.Dialect.GetColumnName(prefix ? GetTableName(map, schemaName, tableName) : null, property.ColumnName, alias); - } - - public virtual string GetColumnName(bool prefix, IClassMapper map, string propertyName, bool includeAlias, string schemaName, string tableName) - { - IPropertyMap propertyMap = map.Properties.SingleOrDefault(p => p.Name.Equals(propertyName, StringComparison.InvariantCultureIgnoreCase)); - if (propertyMap == null) - { - throw new ArgumentException(string.Format("Could not find '{0}' in Mapping.", propertyName)); - } - - return GetColumnName(prefix,map, propertyMap, includeAlias,schemaName, tableName); - } - - public virtual bool SupportsMultipleStatements() - { - return Configuration.Dialect.SupportsMultipleStatements; - } - - public virtual string BuildSelectColumns(IClassMapper classMap, string schemaName, string tableName, IList join = null, IList alias = null) - { - if (join != null && join.Count > 0) - { - Dictionary joinMap = new Dictionary(); - - foreach (var itemJoin in join) - { - var leftMap = itemJoin.GetLeftMapper(this); - var tablename = $"{leftMap.SchemaName}.{leftMap.TableName}"; - if (!joinMap.ContainsKey(tablename)) - joinMap.Add(tablename, new JoinMapper() - { - Mapper = leftMap, - SchemaName = itemJoin.SchemaName, - TableName = itemJoin.TableName - }); - var rightMap = itemJoin.GetRightMapper(this); - tablename = $"{rightMap.SchemaName}.{rightMap.TableName}"; - if (!joinMap.ContainsKey(tablename)) - joinMap.Add(tablename, new JoinMapper() - { - Mapper = rightMap, - SchemaName = itemJoin.SchemaName2, - TableName = itemJoin.TableName2 - }); - } - - var vMapPro = classMap.Properties.Select(w => w.Name).ToList(); - - List ListColumn = new List(); - - foreach (var itemMap in joinMap) - { - if (vMapPro.Count == 0) - break; - var vAllProperty = itemMap.Value.Mapper.Properties.Where(w => !w.Ignored); - for (int i = vMapPro.Count - 1; i >= 0; i--) - { - var jitem = vAllProperty.Where(w => w.Name.Equals(vMapPro[i], StringComparison.OrdinalIgnoreCase)); - if (jitem.Count() > 0) - { - ListColumn.Add(new JoinMapper() - { - AliasName = null, - Mapper = itemMap.Value.Mapper, - Propertry = jitem.First(), - SchemaName = itemMap.Value.SchemaName, - TableName = itemMap.Value.TableName - }); - vMapPro.RemoveAt(i); - } - } - } - - if (alias != null && vMapPro.Count > 0) - { - foreach (var itemAlia in alias) - { - if (vMapPro.Count == 0) - break; - - var rightMap = itemAlia.GetRightMapper(this); - var tablename = $"{rightMap.SchemaName}.{rightMap.TableName}"; - if (!joinMap.ContainsKey(tablename)) - break; - - var vrightSchemaMap = joinMap[tablename]; - var propertyMap = itemAlia.GetPropertyMap(this); - for (int i = vMapPro.Count - 1; i >= 0; i--) - { - if (itemAlia.PropertyName.Equals(vMapPro[i])) - { - ListColumn.Add(new JoinMapper() - { - AliasName = itemAlia.PropertyName, - Mapper = vrightSchemaMap.Mapper, - Propertry = propertyMap, - SchemaName = vrightSchemaMap.SchemaName, - TableName = vrightSchemaMap.TableName - }); - vMapPro.RemoveAt(i); - break; - } - } - } - } - - var jcolumns = ListColumn.Select(p => GetColumnName(true,p.Mapper, p.Propertry, true, p.SchemaName, p.TableName, p.AliasName)); - return jcolumns.AppendStrings(); - } - - var columns = classMap.Properties - .Where(p => !p.Ignored) - .Select(p => GetColumnName(false,classMap, p, true, schemaName, tableName)); - return columns.AppendStrings(); - } - - public string GetOperatorString(Operator Operator, bool Not) => Configuration.Dialect.GetOperatorString(Operator, Not); - - internal class JoinMapper - { - public IPropertyMap Propertry { get; set; } - public IClassMapper Mapper { get; set; } - public string SchemaName { get; set; } - public string TableName { get; set; } - - public string AliasName { get; set; } - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Sql/SqlServerDialect.cs b/samples/Common/Repository.Dapper.Core/Sql/SqlServerDialect.cs deleted file mode 100644 index 53e09f788..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/SqlServerDialect.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public class SqlServerDialect : SqlDialectBase - { - public override char OpenQuote - { - get { return '['; } - } - - public override char CloseQuote - { - get { return ']'; } - } - - public override string GetIdentitySql(string tableName) - { - return string.Format("SELECT CAST(SCOPE_IDENTITY() AS BIGINT) AS [Id]"); - } - - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - int startValue = ((page-1) * resultsPerPage) + 1; - return GetSetSql(sql, startValue < 1 ? 1 : startValue, resultsPerPage, parameters); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - if (string.IsNullOrEmpty(sql)) - { - throw new ArgumentNullException("SQL"); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - int selectIndex = GetSelectEnd(sql) + 1; - string orderByClause = GetOrderByClause(sql); - if (orderByClause == null) - { - orderByClause = "ORDER BY CURRENT_TIMESTAMP"; - } - - - string projectedColumns = GetColumnNames(sql).Aggregate(new StringBuilder(), (sb, s) => (sb.Length == 0 ? sb : sb.Append(", ")).Append(GetColumnName("_proj", s, null)), sb => sb.ToString()); - string newSql = sql - .Replace(" " + orderByClause, string.Empty) - .Insert(selectIndex, string.Format("ROW_NUMBER() OVER(ORDER BY {0}) AS {1}, ", orderByClause.Substring(9), GetColumnName(null, "_row_number", null))); - - string result = string.Format("SELECT TOP({0}) {1} FROM ({2}) [_proj] WHERE {3} >= @_pageStartRow ORDER BY {3}", - maxResults, projectedColumns.Trim(), newSql, GetColumnName("_proj", "_row_number", null)); - - parameters.Add("@_pageStartRow", firstResult); - return result; - } - - protected string GetOrderByClause(string sql) - { - int orderByIndex = sql.LastIndexOf(" ORDER BY ", StringComparison.InvariantCultureIgnoreCase); - if (orderByIndex == -1) - { - return null; - } - - string result = sql.Substring(orderByIndex).Trim(); - - int whereIndex = result.IndexOf(" WHERE ", StringComparison.InvariantCultureIgnoreCase); - if (whereIndex == -1) - { - return result; - } - - return result.Substring(0, whereIndex).Trim(); - } - - protected int GetFromStart(string sql) - { - int selectCount = 0; - string[] words = sql.Split(' '); - int fromIndex = 0; - foreach (var word in words) - { - if (word.Equals("SELECT", StringComparison.InvariantCultureIgnoreCase)) - { - selectCount++; - } - - if (word.Equals("FROM", StringComparison.InvariantCultureIgnoreCase)) - { - selectCount--; - if (selectCount == 0) - { - break; - } - } - - fromIndex += word.Length + 1; - } - - return fromIndex; - } - - protected virtual int GetSelectEnd(string sql) - { - if (sql.StartsWith("SELECT DISTINCT", StringComparison.InvariantCultureIgnoreCase)) - { - return 15; - } - - if (sql.StartsWith("SELECT", StringComparison.InvariantCultureIgnoreCase)) - { - return 6; - } - - throw new ArgumentException("SQL must be a SELECT statement.", "sql"); - } - - protected virtual IList GetColumnNames(string sql) - { - int start = GetSelectEnd(sql); - int stop = GetFromStart(sql); - string[] columnSql = sql.Substring(start, stop - start).Split(','); - List result = new List(); - foreach (string c in columnSql) - { - int index = c.IndexOf(" AS ", StringComparison.InvariantCultureIgnoreCase); - if (index > 0) - { - result.Add(c.Substring(index + 4).Trim()); - continue; - } - - string[] colParts = c.Split('.'); - result.Add(colParts[colParts.Length - 1].Trim()); - } - - return result; - } - } -} \ No newline at end of file diff --git a/samples/Common/Repository.Dapper.Core/Sql/SqliteDialect.cs b/samples/Common/Repository.Dapper.Core/Sql/SqliteDialect.cs deleted file mode 100644 index e21bbba56..000000000 --- a/samples/Common/Repository.Dapper.Core/Sql/SqliteDialect.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Repository.Dapper.Core.Sql -{ - public class SqliteDialect : SqlDialectBase - { - public override string GetIdentitySql(string tableName) - { - return "SELECT LAST_INSERT_ROWID() AS [Id]"; - } - - public override string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary parameters) - { - int startValue = (page - 1) * resultsPerPage; - return GetSetSql(sql, startValue < 0 ? 0 : startValue, resultsPerPage, parameters); - } - - public override string GetSetSql(string sql, int firstResult, int maxResults, IDictionary parameters) - { - if (string.IsNullOrEmpty(sql)) - { - throw new ArgumentNullException("SQL"); - } - - if (parameters == null) - { - throw new ArgumentNullException("Parameters"); - } - - var result = string.Format("{0} LIMIT @Offset, @Count", sql); - parameters.Add("@Offset", firstResult); - parameters.Add("@Count", maxResults); - return result; - } - - public override string GetColumnName(string prefix, string columnName, string alias) - { - if (string.IsNullOrWhiteSpace(columnName)) - { - throw new ArgumentNullException(columnName, "columnName cannot be null or empty."); - } - var result = new StringBuilder(); - result.AppendFormat(columnName); - if (!string.IsNullOrWhiteSpace(alias)) - { - result.AppendFormat(" AS {0}", QuoteString(alias)); - } - return result.ToString(); - } - } -} diff --git "a/samples/Common/Repository.EF.Core/BaseImpQueryOnlyRepository - \345\244\215\345\210\266.cs" "b/samples/Common/Repository.EF.Core/BaseImpQueryOnlyRepository - \345\244\215\345\210\266.cs" deleted file mode 100644 index a5cb78318..000000000 --- "a/samples/Common/Repository.EF.Core/BaseImpQueryOnlyRepository - \345\244\215\345\210\266.cs" +++ /dev/null @@ -1,150 +0,0 @@ -using DDD.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Query; -using Surging.Core.CPlatform.Ioc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace Repository.EF.Core -{ - public class BaseImpQueryOnlyRepository: BaseRepository,IQueryOnlyRepository //where T : class, IDBModel - { - private readonly DefaultDbContext _dbContext; - private readonly DbSet _set; - public BaseImpQueryOnlyRepository(string modelAssemblyName)//DefaultDbContext dbContext) - { - //if (dbContext == null) throw new ArgumentNullException(nameof(dbContext)); - - _dbContext = new DefaultDbContext(modelAssemblyName); - _dbContext.Database.EnsureCreated(); - _set = _dbContext.Set(); - } - - - - #region 所有跟添加/修改/删除无关的界面查询,也不包含报表查询 - - public virtual int Count(Expression> @where = null) where T : class, IDBModel - { - return where == null ? _set.Count() : _set.Count(@where); - } - - public virtual bool Exist(Expression> @where = null) where T : class, IDBModel - { - return Get(where).Any(); - } - - public virtual bool Exist(Expression> @where = null, params Expression>[] includes) - { - return Get(where, includes).Any(); - } - - public virtual int ExecuteSqlWithNonQuery(string sql, params object[] parameters) - { - return _dbContext.ExecuteSqlWithNonQuery(sql, parameters); - } - - public virtual T GetSingle(Guid key) - { - return _set.Find(key); - } - - public T GetSingle(Guid key, params Expression>[] includes) - { - if (includes == null) return GetSingle(key); - var query = _set.AsQueryable(); - foreach (var include in includes) - { - query = query.Include(include); - } - Expression> filter = m => m.KeyId.Equals(key); - return query.SingleOrDefault(filter.Compile()); - } - - public T GetSingle(Expression> @where = null) - { - if (where == null) return _set.SingleOrDefault(); - return _set.SingleOrDefault(@where); - } - - public T GetSingle(Expression> @where = null, params Expression>[] includes) - { - if (includes == null) return GetSingle(where); - var query = _set.AsQueryable(); - foreach (var include in includes) - { - query = query.Include(include); - } - if (where == null) return query.SingleOrDefault(); - return query.SingleOrDefault(where); - } - - public virtual IQueryable Get(Expression> @where = null) - { - return @where != null ? _set.AsNoTracking().Where(@where) : _set.AsNoTracking(); - } - - - public virtual IQueryable Get(Expression> @where = null, params Expression>[] includes) - { - if (includes == null) - return Get(where); - var query = _set.AsQueryable(); - foreach (var include in includes) - { - query = query.Include(include); - } - return @where != null ? query.AsNoTracking().Where(@where) : query.AsNoTracking(); - } - public class IncludeTree - { - public Expression> Property { get; set; } - public Expression>[] navigationPropertyPath { get; set; } - - public List< IncludeTree>[] Childs { get; set; } - } - - //static IIncludableQueryable IncludeTable( IIncludableQueryable queryable, List< IncludeTree> includeTrees) - // { - // foreach (var includeTree in includeTrees) - // { - // queryable.Include(includeTree.Property).ThenInclude((includeTree.ChildInclude)); - - // } - // } - - - - - - public virtual IList SqlQuery(string sql, params object[] parameters) where TView : class, new() - { - return _dbContext.SqlQuery(sql, parameters); - } - - - public virtual IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, Expression>[] includes, bool asc = true, params Func[] @orderby) - { - var filter = Get(where).AsQueryable(); - if (includes != null) - { - foreach (var include in includes) - { - filter = filter.Include(include); - } - } - if (orderby != null) - { - foreach (var func in orderby) - { - filter = asc ? filter.OrderBy(func).AsQueryable() : filter.OrderByDescending(func).AsQueryable(); - } - } - return filter.Skip(pageSize * (pageIndex - 1)).Take(pageSize); - } - #endregion - } -} diff --git a/samples/Common/Repository.EF.Core/BaseImpQueryOnlyRepository.cs b/samples/Common/Repository.EF.Core/BaseImpQueryOnlyRepository.cs deleted file mode 100644 index 82c9efda4..000000000 --- a/samples/Common/Repository.EF.Core/BaseImpQueryOnlyRepository.cs +++ /dev/null @@ -1,149 +0,0 @@ -using DDD.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Query; -using Surging.Core.CPlatform.Ioc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -namespace Repository.EF.Core -{ - public class BaseImpQueryOnlyRepository: BaseRepository,IQueryOnlyRepository where T : class, IDBModel - { - protected readonly DefaultDbContext _dbContext; - protected readonly DbSet _set; - public BaseImpQueryOnlyRepository()//DefaultDbContext dbContext) - { - //if (dbContext == null) throw new ArgumentNullException(nameof(dbContext)); - - _dbContext = new DefaultDbContext(); - _set = _dbContext.Set(); - } - - - - #region 所有跟添加/修改/删除无关的界面查询,也不包含报表查询 - - public virtual int Count(Expression> @where = null) - { - return where == null ? _set.Count() : _set.Count(@where); - } - - public virtual bool Exist(Expression> @where = null) - { - return Get(where).Any(); - } - - public virtual bool Exist(Expression> @where = null, params Expression>[] includes) - { - return Get(where, includes).Any(); - } - - public virtual int ExecuteSqlWithNonQuery(string sql, params object[] parameters) - { - return _dbContext.ExecuteSqlWithNonQuery(sql, parameters); - } - - public virtual T GetSingle(Guid key) - { - return _set.Find(key); - } - - public T GetSingle(Guid key, params Expression>[] includes) - { - if (includes == null) return GetSingle(key); - var query = _set.AsQueryable(); - foreach (var include in includes) - { - query = query.Include(include); - } - Expression> filter = m => m.KeyId.Equals(key); - return query.SingleOrDefault(filter.Compile()); - } - - public T GetSingle(Expression> @where = null) - { - if (where == null) return _set.SingleOrDefault(); - return _set.SingleOrDefault(@where); - } - - public T GetSingle(Expression> @where = null, params Expression>[] includes) - { - if (includes == null) return GetSingle(where); - var query = _set.AsQueryable(); - foreach (var include in includes) - { - query = query.Include(include); - } - if (where == null) return query.SingleOrDefault(); - return query.SingleOrDefault(where); - } - - public virtual IQueryable Get(Expression> @where = null) - { - return @where != null ? _set.AsNoTracking().Where(@where) : _set.AsNoTracking(); - } - - - public virtual IQueryable Get(Expression> @where = null, params Expression>[] includes) - { - if (includes == null) - return Get(where); - var query = _set.AsQueryable(); - foreach (var include in includes) - { - query = query.Include(include); - } - return @where != null ? query.AsNoTracking().Where(@where) : query.AsNoTracking(); - } - public class IncludeTree - { - public Expression> Property { get; set; } - public Expression>[] navigationPropertyPath { get; set; } - - public List< IncludeTree>[] Childs { get; set; } - } - - //static IIncludableQueryable IncludeTable( IIncludableQueryable queryable, List< IncludeTree> includeTrees) - // { - // foreach (var includeTree in includeTrees) - // { - // queryable.Include(includeTree.Property).ThenInclude((includeTree.ChildInclude)); - - // } - // } - - - - - - public virtual IList SqlQuery(string sql, params object[] parameters) where TView : class, new() - { - return _dbContext.SqlQuery(sql, parameters); - } - - - public virtual IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, Expression>[] includes, bool asc = true, params Func[] @orderby) - { - var filter = Get(where).AsQueryable(); - if (includes != null) - { - foreach (var include in includes) - { - filter = filter.Include(include); - } - } - if (orderby != null) - { - foreach (var func in orderby) - { - filter = asc ? filter.OrderBy(func).AsQueryable() : filter.OrderByDescending(func).AsQueryable(); - } - } - return filter.Skip(pageSize * (pageIndex - 1)).Take(pageSize); - } - #endregion - } -} diff --git a/samples/Common/Repository.EF.Core/BaseImpRepository.cs b/samples/Common/Repository.EF.Core/BaseImpRepository.cs deleted file mode 100644 index 8a8312319..000000000 --- a/samples/Common/Repository.EF.Core/BaseImpRepository.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using DDD.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Query; -using Surging.Core.CPlatform.Ioc; - -namespace Repository.EF.Core -{ - public class BaseImpRepository : BaseRepository,IRepository where T : IAggregate - { - private readonly string _modelAssemblyName; - private readonly DefaultDbContext _dbContext; - protected readonly DbSet _set; - public BaseImpRepository()//DefaultDbContext dbContext) - { - //if (dbContext == null) throw new ArgumentNullException(nameof(dbContext)); - - _dbContext = new DefaultDbContext(); - //_dbContext.Database.EnsureCreated(); - _set = _dbContext.Set(); - } - - - - public virtual void Delete(Guid key) - { - } - - - - public virtual void Dispose() - { - if (_dbContext != null) - { - _dbContext.Dispose(); - } - } - - public virtual T FindBy(Guid key) //where T : IAggregate - { - //TODO:想要动态地加载聚合的所有数据 - return null;// _dbContext.Set().First(a => a.KeyId == key); - } - - public void Add(T aggregate)// where T : IAggregate - { - // using (var _dbContext=new DefaultDbContext(_modelAssemblyName)) - // { - _dbContext.Set().Add(aggregate); - // _dbContext.SaveChanges(); - // } - } - public void Update(T aggregate)// where T : IAggregate - { - _dbContext.Set().Update(aggregate); - } - - public int Commit() - { - return _dbContext.SaveChanges(); - } - } -} diff --git a/samples/Common/Repository.EF.Core/ConfigHelper.cs b/samples/Common/Repository.EF.Core/ConfigHelper.cs deleted file mode 100644 index 41670aff7..000000000 --- a/samples/Common/Repository.EF.Core/ConfigHelper.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; -using Surging.Core.CPlatform.Configurations.Remote; -using Surging.Core.CPlatform.Utilities; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Repository.EF.Extensions -{ - public static class DBConfigurationExtensions - { - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, string path) - { - return AddDBFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); - } - - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, string path, bool optional) - { - return AddDBFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); - } - - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) - { - return AddDBFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); - } - - public static IConfigurationBuilder AddDBFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) - { - Check.NotNull(builder, "builder"); - Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); - if (provider == null && Path.IsPathRooted(path)) - { - provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); - path = Path.GetFileName(path); - } - var source = new DBConfigurationSource - { - FileProvider = provider, - Path = path, - Optional = optional, - ReloadOnChange = reloadOnChange - }; - builder.Add(source); - DBConfig.Configuration = builder.Build(); - return builder; - } - } - public class DBConfig - { - - public static IConfiguration Configuration { get; set; } - /* static ConfigHelper() - { - configuration = AutofacContainer.Resolve(); - } - - public static IConfigurationSection GetSection(string key) - { - return configuration.GetSection(key); - } - - public static string GetConfigurationValue(string key) - { - return configuration[key]; - } - - public static string GetConfigurationValue(string section, string key) - { - return GetSection(section)?[key]; - } - - public static string GetConnectionString(string key) - { - return configuration.GetConnectionString(key); - } - */ - } - - public class DBConfigurationSource : FileConfigurationSource - { - public string ConfigurationKeyPrefix { get; set; } - - public override IConfigurationProvider Build(IConfigurationBuilder builder) - { - FileProvider = FileProvider ?? builder.GetFileProvider(); - return new DBConfigurationProvider(this); - } - } - public class DBConfigurationProvider : FileConfigurationProvider - { - public DBConfigurationProvider(DBConfigurationSource source) : base(source) { } - - public override void Load(Stream stream) - { - var parser = new JsonConfigurationParser(); - this.Data = parser.Parse(stream, null); - } - } -} diff --git a/samples/Common/Repository.EF.Core/DbContextOption.cs b/samples/Common/Repository.EF.Core/DbContextOption.cs deleted file mode 100644 index 9f11e290b..000000000 --- a/samples/Common/Repository.EF.Core/DbContextOption.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Repository.EF.Core -{ - - public class DbContextOption - { - /// - /// 数据库连接字符串 - /// - public string ConnectionString { get; set; } - /// - /// 实体程序集名称 - /// - public string ModelAssemblyName { get; set; } - /// - /// 数据库类型 - /// - public DbType DbType { get; set; } = DbType.MSSQLSERVER; - } - - /// - /// 数据库类型枚举 - /// - public enum DbType - { - /// - /// MS SQL Server - /// - MSSQLSERVER=0, - /// - /// Oracle - /// - ORACLE, - /// - /// MySQL - /// - MYSQL, - /// - /// Sqlite - /// - SQLITE, - /// - /// in-memory database - /// - MEMORY, - /// - /// PostgreSQL - /// - NPGSQL - } -} diff --git a/samples/Common/Repository.EF.Core/DefaultDbContext.cs b/samples/Common/Repository.EF.Core/DefaultDbContext.cs deleted file mode 100644 index c15bc3696..000000000 --- a/samples/Common/Repository.EF.Core/DefaultDbContext.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Data.SqlClient; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using Config.Core.Extensions; -using DDD.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Extensions; -using Microsoft.Extensions.Configuration; -using Surging.Core.CPlatform; -using Z.EntityFramework.Plus; - -namespace Repository.EF.Core -{ - public sealed class DefaultDbContext : DbContext - { - private DbContextOption _option; - - - public DefaultDbContext() - { - _option = new DbContextOption - { - ConnectionString = DBConfig.Configuration["ConnectionString"], - ModelAssemblyName = DBConfig.Configuration["ModelAssemblyName"], - DbType = DbType.MSSQLSERVER - }; - } - /// - /// 构造函数 - /// - /// - public DefaultDbContext(DbContextOption option) - { - if(option==null) - throw new ArgumentNullException(nameof(option)); - if(string.IsNullOrEmpty(option.ConnectionString)) - throw new ArgumentNullException(nameof(option.ConnectionString)); - if (string.IsNullOrEmpty(option.ModelAssemblyName)) - throw new ArgumentNullException(nameof(option.ModelAssemblyName)); - _option = option; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - switch (_option.DbType) - { - case DbType.ORACLE: - throw new NotSupportedException("Oracle EF Core Database Provider is not yet available."); - //case DbType.MYSQL: - // optionsBuilder.UseMySql(_option.ConnectionString); - // break; - //case DbType.SQLITE: - // optionsBuilder.UseSqlite(_option.ConnectionString); - // break; - //case DbType.MEMORY: - // optionsBuilder.UseInMemoryDatabase(_option.ConnectionString); - // break; - //case DbType.NPGSQL: - // optionsBuilder.UseNpgsql(_option.ConnectionString); - // break; - default: - optionsBuilder.UseSqlServer(_option.ConnectionString); - break; - } - base.OnConfiguring(optionsBuilder); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - AddEntityTypes(modelBuilder); - base.OnModelCreating(modelBuilder); - } - - private void AddEntityTypes(ModelBuilder modelBuilder) - { - var assembly = Assembly.Load(_option.ModelAssemblyName); - var types = assembly?.GetTypes(); - var list = types?.Where(t => - t.IsClass && !t.IsGenericType && !t.IsAbstract&& - t.GetInterfaces().Any(m => m.IsGenericType && m.GetGenericTypeDefinition() == typeof(IDBModel<>))).ToList(); - if (list != null && list.Any()) - { - list.ForEach(t => - { - if (modelBuilder.Model.FindEntityType(t) == null) - modelBuilder.Model.AddEntityType(t); - }); - } - } - - /// - /// ExecuteSqlWithNonQuery - /// - /// - /// - /// - public int ExecuteSqlWithNonQuery(string sql, params object[] parameters) - { - return Database.ExecuteSqlCommand(sql, - CancellationToken.None, - parameters); - } - - /// - /// edit an entity. - /// - /// - /// - /// - public int Edit(T entity) where T : class - { - Entry(entity).State = EntityState.Modified; - return SaveChanges(); - } - - /// - /// edit entities. - /// - /// - /// - /// - public int EditRange(ICollection entities) where T : class - { - Set().AttachRange(entities.ToArray()); - return SaveChanges(); - } - - /// - /// update query datas by columns. - /// - /// - /// - /// - /// - public int Update(Expression> @where, Expression> updateExp) - where T : class - { - return Set().Where(@where).Update(updateExp); - } - - /// - /// update data by columns. - /// - /// - /// - /// - /// - public int Update(T model, params string[] updateColumns) where T : class - { - if (updateColumns != null && updateColumns.Length > 0) - { - if (Entry(model).State == EntityState.Added || - Entry(model).State == EntityState.Detached) Set().Attach(model); - foreach (var propertyName in updateColumns) - { - Entry(model).Property(propertyName).IsModified = true; - } - } - else - { - Entry(model).State = EntityState.Modified; - } - return SaveChanges(); - } - - /// - /// delete by query. - /// - /// - /// - /// - public int Delete(Expression> @where) where T : class - { - Set().Where(@where).Delete(); - return SaveChanges(); - } - - /* - /// - /// bulk insert by sqlbulkcopy, and with transaction. - /// - /// - /// - /// - public void BulkInsert(IList entities, string destinationTableName = null) where T : class - { - if (entities == null || !entities.Any()) return; - if (string.IsNullOrEmpty(destinationTableName)) - { - var mappingTableName = typeof(T).GetCustomAttribute()?.Name; - destinationTableName = string.IsNullOrEmpty(mappingTableName) ? typeof(T).Name : mappingTableName; - } - using (var dt = entities.ToDataTable()) - { - using (var conn = new SqlConnection(_option.ConnectionString)) - { - conn.Open(); - using (var tran = conn.BeginTransaction()) - { - try - { - var bulk = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran); - bulk.BatchSize = entities.Count; - bulk.DestinationTableName = destinationTableName; - bulk.EnableStreaming = true; - bulk.WriteToServerAsync(dt); - tran.Commit(); - } - catch (Exception) - { - tran.Rollback(); - throw; - } - } - conn.Close(); - } - } - } - */ - public List SqlQuery(string sql, params object[] parameters) - where T : class - where TView : class - { - return Set().FromSql(sql, parameters).Cast().ToList(); - } - - } -} \ No newline at end of file diff --git a/samples/Common/Repository.EF.Core/IQueryableExtension.cs b/samples/Common/Repository.EF.Core/IQueryableExtension.cs deleted file mode 100644 index 6a9b9ef56..000000000 --- a/samples/Common/Repository.EF.Core/IQueryableExtension.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Data.Entity.Infrastructure.DbQuery; -namespace Centa.Agency.Repository.EF -{ - /// - /// Class for IQuerable extensions methods - /// - /// Include method in IQueryable ( base contract for IObjectSet ) is - /// intended for mock Include method in ObjectQuery{T}. - /// Paginate solve not parametrized queries issues with skip and take L2E methods - /// - /// - public static class IQueryableExtensions - { - - #region Extension Methods - - /// - /// Include method for IQueryable - /// - /// Type of elements - /// Queryable object - /// Path to include - /// Queryable object with include path information - public static IQueryable Include(this IQueryable queryable, string path) - where TEntity : class - { - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException("path can not empty"); - // var query = queryable as ObjectQuery;//ObjectContext時用 - var query = queryable as DbQuery;//DbContext時用 - - if (query != null)//if is a EF ObjectQuery object - return query.Include(path); - return null; - } - - /// - /// Include extension method for IQueryable - /// - /// Type of elements in IQueryable - /// Queryable object - /// Expression with path to include - /// Queryable object with include path information - public static IQueryable Include(this IQueryable queryable, Expression> path) - where TEntity : class - { - return Include(queryable, AnalyzeExpressionPath(path)); - } - - /// - /// Paginate query in a specific page range - /// - /// Typeof entity in underlying query - /// Typeof ordered data value - /// Query to paginate - /// Order by expression used in paginate method - /// - /// At this moment Order by expression only support simple order by c=>c.CustomerCode. If you need - /// add more complex order functionality don't use this extension method - /// - /// - /// Page index - /// Page count - /// order direction - /// A paged queryable - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] - public static IQueryable Paginate(this IQueryable queryable, Expression> orderBy, int pageIndex, int pageCount, bool ascending) - where TEntity : class - { - ObjectQuery query = queryable as ObjectQuery; - - if (query != null) - { - //this paginate method use ESQL for solve problems with Parametrized queries - //in L2E and Skip/Take methods - - string orderPath = AnalyzeExpressionPath(orderBy); - - return query.Skip(string.Format(CultureInfo.InvariantCulture, "it.{0} {1}", orderPath, (ascending) ? "asc" : "desc"), "@skip", new ObjectParameter("skip", (pageIndex) * pageCount)) - .Top("@limit", new ObjectParameter("limit", pageCount)); - - } - else // for In-Memory object set - return queryable.OrderBy(orderBy).Skip((pageIndex * pageCount)).Take(pageCount); - } - - #endregion - - #region Private Methods - - static string AnalyzeExpressionPath(Expression> expression) - where TEntity : class - { - if (expression == (Expression>)null) - throw new ArgumentNullException("Argument error"); - - MemberExpression body = expression.Body as MemberExpression; - if ( - ( - (body == null) - || - !body.Member.DeclaringType.IsAssignableFrom(typeof(TEntity)) - ) - || - (body.Expression.NodeType != ExpressionType.Parameter)) - { - throw new ArgumentException("Argument error"); - } - else - return body.Member.Name; - } - #endregion - } - } diff --git a/samples/Common/Repository.EF.Core/InquiryRepository.cs b/samples/Common/Repository.EF.Core/InquiryRepository.cs deleted file mode 100644 index 1c79f86c0..000000000 --- a/samples/Common/Repository.EF.Core/InquiryRepository.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.EntityFrameworkCore; -using System.Linq.Expressions; -using System.Linq; -using Microsoft.EntityFrameworkCore.Query; - - - -namespace Repository.EF.Core.Inquiry -{ - //public class InquiryRepository : BaseImpRepository - //{ - - // public override Customer FindBy(Guid key) - // { - // return _set.Include(a => a.CusInquirys).ThenInclude(b => b.InquiryParameters).Where(a => a.KeyId == key).FirstOrDefault(); - // } - - //} -} diff --git a/samples/Common/Repository.EF.Core/Properties/PublishProfiles/FolderProfile.pubxml b/samples/Common/Repository.EF.Core/Properties/PublishProfiles/FolderProfile.pubxml deleted file mode 100644 index 6c005a7a9..000000000 --- a/samples/Common/Repository.EF.Core/Properties/PublishProfiles/FolderProfile.pubxml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - FileSystem - Debug - netcoreapp2.0 - bin\Release\PublishOutput - - \ No newline at end of file diff --git a/samples/Common/Repository.EF.Core/Repository.EF.Core.csproj b/samples/Common/Repository.EF.Core/Repository.EF.Core.csproj deleted file mode 100644 index a7952b432..000000000 --- a/samples/Common/Repository.EF.Core/Repository.EF.Core.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - netcoreapp2.0 - - - - bin\Debug\netstandard2.0\ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/Common/Repository.EF.Core/SqlHelper.cs b/samples/Common/Repository.EF.Core/SqlHelper.cs deleted file mode 100644 index aede601d6..000000000 --- a/samples/Common/Repository.EF.Core/SqlHelper.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Repository.EF.Core -{ - public class SqlHelper - { - /// - /// 参数拼装 - /// - /// 参数名称 - /// 参数类型 - /// 参数值 - /// 拼装后的参数对象 - public static SqlParameter MakeParam(string parameterName, SqlDbType parameterType, object parameterValue) - { - SqlParameter p = new SqlParameter(); - p.ParameterName = parameterName; - p.SqlDbType = parameterType; - if (parameterValue == null) - { - p.Value = DBNull.Value; - } - else - { - if (parameterType == SqlDbType.Structured) - { - Type type = parameterValue.GetType(); - if (type.IsGenericType)//判断是否是泛型 - { - string t = type.GetGenericArguments()[0].Name; //泛型的类型 - switch (t) - { - case "Guid": - p.TypeName = "GuidCollectionTVP"; - p.Value = InitialCollectionTVP(parameterValue as List); - break; - case "Int32": - p.TypeName = "IntCollectionTVP"; - p.Value = InitialCollectionTVP(parameterValue as List); - break; - case "String": - p.TypeName = "StringCollectionTVP"; - p.Value = InitialCollectionTVP(parameterValue as List); - break; - default: - p.Value = parameterValue; - break; - } - } - else - { - p.Value = parameterValue; - } - - } - else - { - p.Value = parameterValue; - } - } - - return p; - } - - /* - /// - /// 参数拼装 - /// - /// 参数名称 - /// 参数类型 - /// 参数值 - /// 拼装后的参数对象 - public static SqlParameter MakeParam(string parameterName, DbType parameterType, object parameterValue) - { - SqlParameter p = new SqlParameter(); - p.ParameterName = parameterName; - p.DbType = parameterType; - if (parameterValue == null) - { - p.Value = DBNull.Value; - } - else - { - p.Value = parameterValue; - } - - return p; - } - - */ - /// - /// 初始化CollectionTVP - /// - /// 数据列表 - /// DataTable - public static DataTable InitialCollectionTVP(List list) - { - DataTable dt = new DataTable(); - dt.Columns.Add("Item", typeof(T)); - if (list == null | list.Count == 0) - { - return dt; - } - - foreach (T item in list) - { - dt.Rows.Add(item); - } - - return dt; - } - /// - /// 过滤sql注入2015/7/25 xingyongkang - /// - /// - /// - public static string CheckKeyWord(string keyWord) - { - //过滤关键字 - string StrKeyWord = @"select|insert|delete|from|count\(|drop table|update|truncate|asc\(|mid\(|char\(|xp_cmdshell|exec master|netlocalgroup administrators|:|net user|""|or|and"; - if (Regex.IsMatch(keyWord, StrKeyWord, RegexOptions.IgnoreCase)) - { - return ""; - } - return keyWord; - } - } -} diff --git a/samples/Common/Repository.EF.Core/UnitOfWork.cs b/samples/Common/Repository.EF.Core/UnitOfWork.cs deleted file mode 100644 index 4a12170a3..000000000 --- a/samples/Common/Repository.EF.Core/UnitOfWork.cs +++ /dev/null @@ -1,64 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Centa.Agency.Repository.EF -{ - public class UnitOfWork : IUnitOfWork - { - private bool disposed = false; - private DefaultDbContext _context; - public UnitOfWork()//DefaultDbContext context) - { - _context = new DefaultDbContext();// context; - } - /* - dbContext = CallContext.GetData(provider.ConnectionStringName) as AppDbContext; - if (dbContext == null) - { - dbContext = new AppDbContext(provider.ConnectionString); - dbContext.Configuration.ValidateOnSaveEnabled = false; - //将新创建的 ef上下文对象 存入线程 - CallContext.SetData(provider.ConnectionStringName, dbContext); - } - - */ - public int Commit() - { - using (var tran = _context.Database.CurrentTransaction ?? _context.Database.BeginTransaction()) - { - try - { - var result = _context.SaveChanges(); - tran.Commit(); - return result; - } - catch (Exception) - { - tran.Rollback(); - throw; - } - } - } - - protected virtual void Dispose(bool disposing) - { - if (!this.disposed) - { - if (disposing) - { - _context.Dispose(); - } - } - this.disposed = true; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - } -} diff --git a/samples/GateWay.WebApi/Areas/AuthManger/Controllers/AuthController.cs b/samples/GateWay.WebApi/Areas/AuthManger/Controllers/AuthController.cs deleted file mode 100644 index 665bcbd7b..000000000 --- a/samples/GateWay.WebApi/Areas/AuthManger/Controllers/AuthController.cs +++ /dev/null @@ -1,250 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using Application.Interface.Auth; -using Application.Interface.Org; -using Application.Service.Auth.Dto; -using DTO.Core; -using GateWay.WebApi.Controllers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; -using Surging.Core.ApiGateWay; -using Surging.Core.ApiGateWay.OAuth; -using Surging.Core.Caching.DependencyResolution; -using Surging.Core.CPlatform; -using Surging.Core.CPlatform.Filters.Implementation; -using Surging.Core.CPlatform.Routing; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.ProxyGenerator; -using Surging.Core.ProxyGenerator.Implementation; -using GateWayAppConfig = Surging.Core.ApiGateWay.AppConfig; - -namespace GateWay.WebApi.Areas.OrgManger.Controllers -{ - - [Produces("application/json")] - [Route("api/[controller]")] - public class AuthController : BaseApiController - { - private readonly IServiceProxyProvider _serviceProxyProvider; - private readonly IServiceRouteProvider _serviceRouteProvider; - private readonly IAuthorizationServerProvider _authorizationServerProvider; - - private IAuthAppService _authProxy; - public AuthController() - { - _authProxy = serviceProxyFactory.CreateProxy(); - _serviceProxyProvider = ServiceLocator.GetService(); - _serviceRouteProvider = ServiceLocator.GetService(); //serviceRouteProvider; - _authorizationServerProvider = ServiceLocator.GetService();// authorizationServerProvider; - - } - #region 角色 - [HttpGet] - private async Task Get() - { - Dictionary model = new Dictionary(); - model.Add("req",JsonConvert.SerializeObject( new { - UserName= "SuperMan", - Pwd= "123456", - CorporationKeyId= Guid.Parse("8C100FEE-2D1D-4B70-A27D-13D65DCD5E38") - })); - string path = "api/authapp/signin"; - string serviceKey = "Auth"; - var serviceProxyProvider = ServiceLocator.GetService(); - var res = await serviceProxyProvider.Invoke(model, path, serviceKey); - return res; - } - - [HttpGet] - public async Task> DomainPermissions(CommonCMDReq req) - { - var result = await _authProxy.FindDomainPermissions(req); - return ServiceResult.Create(true, result); - } - - - [HttpPost("SignIn")] - public async Task> SignIn(LoginReq req) - { - //要注意参数类型 - var model = new Dictionary(); - model.Add("req", JsonConvert.SerializeObject(req)); - var serviceKey = "Auth"; - ServiceResult result = ServiceResult.Create(false, null); - var path = GateWayAppConfig.AuthorizationRoutePath; - if (OnAuthorization(path, model, ref result)) - { - if (path == GateWayAppConfig.AuthorizationRoutePath) - { - var token = await _authorizationServerProvider.GenerateTokenCredential(model); - if (token != null) - { - //查询当前用户的权限,返回给客户端 - var tmp = JsonConvert.DeserializeObject(_authorizationServerProvider.GetPayloadString(token)); - var identify = JsonConvert.DeserializeObject(tmp); - Dictionary reqQueryUserPermission = new Dictionary(); - reqQueryUserPermission.Add("req", JsonConvert.SerializeObject(new - { - Identify = identify - })); - string servicePath = "api/orgapp/QueryUserPermission"; - var res = await _serviceProxyProvider.Invoke(reqQueryUserPermission, servicePath); - if (res!=null&&res.OperateFlag) - { - result = ServiceResult.Create(true,new { token = token, auth=res.Result }); - result.StatusCode = (int)ServiceStatusCode.Success; - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - } - } - else - { - if (!string.IsNullOrEmpty(serviceKey)) - { - - result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, path, serviceKey)); - result.StatusCode = (int)ServiceStatusCode.Success; - } - else - { - result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, path)); - result.StatusCode = (int)ServiceStatusCode.Success; - } - } - } - return result; - } - #endregion - - #region Private - private bool OnAuthorization(string path, Dictionary model, ref ServiceResult result) - { - bool isSuccess = true; - var route = _serviceRouteProvider.GetRouteByPath(path).Result; - if (route.ServiceDescriptor.EnableAuthorization()) - { - if (route.ServiceDescriptor.AuthType() == AuthorizationType.JWT.ToString()) - { - isSuccess = ValidateJwtAuthentication(route, model, ref result); - } - else - { - isSuccess = ValidateAppSecretAuthentication(route, path, model, ref result); - } - - } - return isSuccess; - } - - private bool ValidateJwtAuthentication(ServiceRoute route, Dictionary model, ref ServiceResult result) - { - bool isSuccess = true; - var author = HttpContext.Request.Headers["Authorization"]; - if (author.Count > 0) - { - if (route.Address.Any(p => p.DisableAuth == false)) - { - isSuccess = _authorizationServerProvider.ValidateClientAuthentication(author).Result; - if (!isSuccess) - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - } - else - { - var keyValue = model.FirstOrDefault(); - if (!(keyValue.Value is IConvertible) || !typeof(IConvertible).GetTypeInfo().IsAssignableFrom(keyValue.Value.GetType())) - { - dynamic instance = keyValue.Value; - instance.Payload = _authorizationServerProvider.GetPayloadString(author); - model.Remove(keyValue.Key); - model.Add(keyValue.Key, instance); - } - } - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; - isSuccess = false; - } - return isSuccess; - } - - private bool ValidateAppSecretAuthentication(ServiceRoute route, string path, - Dictionary model, ref ServiceResult result) - { - bool isSuccess = true; - DateTime time; - var author = HttpContext.Request.Headers["Authorization"]; - if (route.Address.Any(p => p.DisableAuth == false)) - { - if (!string.IsNullOrEmpty(path) && model.ContainsKey("timeStamp") && author.Count > 0) - { - if (DateTime.TryParse(model["timeStamp"].ToString(), out time)) - { - var seconds = (DateTime.Now - time).TotalSeconds; - if (seconds <= 3560 && seconds >= 0) - { - if (!route.Address.Any(p => GetMD5($"{p.Token}{time.ToString("yyyy-MM-dd hh:mm:ss") }") == author.ToString())) - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; - isSuccess = false; - } - } - return isSuccess; - } - - private string GetMD5(string encypStr) - { - try - { - var md5 = MD5.Create(); - var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(encypStr)); - var sb = new StringBuilder(); - foreach (byte b in bs) - { - sb.Append(b.ToString("X2")); - } - //所有字符转为大写 - return sb.ToString().ToLower(); - } - catch (Exception e) - { - Console.Error.WriteLine(e.StackTrace); - return null; - } - } - #endregion - } -} \ No newline at end of file diff --git a/samples/GateWay.WebApi/Areas/OrgManger/Controllers/CorpMangerController.cs b/samples/GateWay.WebApi/Areas/OrgManger/Controllers/CorpMangerController.cs deleted file mode 100644 index bdcd0cd9e..000000000 --- a/samples/GateWay.WebApi/Areas/OrgManger/Controllers/CorpMangerController.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Application.Interface.Org; -using DTO.Core; -using GateWay.WebApi.Controllers; -using Microsoft.AspNetCore.Mvc; -using Surging.Core.ApiGateWay; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.ProxyGenerator; - -namespace GateWay.WebApi -{ - [Route("api/corp"), CustomAuthorizeFilter] - public class CorpController : BaseApiController - { - private IOrgAppService _orgProxy; - - public CorpController() - { - _orgProxy = serviceProxyFactory.CreateProxy(); - } - - - #region 公司 - [HttpPost] - public async Task> RegisterCorporation(CorpEditReq req) - { - var result = await _orgProxy.RegisterCorporation(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - [HttpPut("activate")] - public async Task> ActivateCorporation(CommonCMDReq req) - { - var result = await _orgProxy.ActivateCorporation(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - [HttpGet("tree")] - public async Task> GetCorpTree(BaseTreeSearchReq req) - { - - var result = await _orgProxy.FindCorps(req); - return ServiceResult.Create(true, result); - } - - #endregion - #region 部门管理 - [HttpGet("org/tree")] - public async Task> GetOrgTree(BaseTreeSearchReq req) - { - - var result = await _orgProxy.FindDepartments(req); - return ServiceResult.Create(true, result); - } - - [HttpGet("org/info")] - public ServiceResult GetInfo(KeyIdReq req) - { - return ServiceResult.Create(true, ""); - } - - [HttpPost("org")] - public async Task> Post(DeptEditReq req) - { - - var result = await _orgProxy.CreateDepartment(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - [HttpPut("org")] - public async Task> Put(DeptEditReq req) - { - - var result = await _orgProxy.ModifyDepartment(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - [HttpDelete("org")] - public async Task> Delete(KeyIdReq req) - { - var result = await _orgProxy.RemoveDepartment(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - #endregion - - } -} diff --git a/samples/GateWay.WebApi/Areas/OrgManger/Controllers/EmployeeController.cs b/samples/GateWay.WebApi/Areas/OrgManger/Controllers/EmployeeController.cs deleted file mode 100644 index 94e923900..000000000 --- a/samples/GateWay.WebApi/Areas/OrgManger/Controllers/EmployeeController.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Application.Interface.Org; -using DTO.Core; -using GateWay.WebApi.Controllers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Surging.Core.ApiGateWay; - -namespace GateWay.WebApi.Areas.OrgManger.Controllers -{ - //[Produces("application/json")] - [Route("api/[controller]")] - public class EmployeeController : BaseApiController - { - private IOrgAppService _orgProxy; - - public EmployeeController() - { - _orgProxy = serviceProxyFactory.CreateProxy(); - } - - - #region 员工 - [HttpPost] - public async Task> Post(EmployeeEditReq req) - { - //HttpContext.Request.Headers - var result = await _orgProxy.CreateEmployee(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - [HttpGet("list")] - public async Task> GetRoleTree(BasePagedRequestDto req) - { - var result = await _orgProxy.FindEmployeePageBy(req); - return ServiceResult.Create(true, result); - } - - - #endregion - - - } -} \ No newline at end of file diff --git a/samples/GateWay.WebApi/Areas/OrgManger/Controllers/RoleMangerController.cs b/samples/GateWay.WebApi/Areas/OrgManger/Controllers/RoleMangerController.cs deleted file mode 100644 index b1fd0dfc0..000000000 --- a/samples/GateWay.WebApi/Areas/OrgManger/Controllers/RoleMangerController.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Application.Interface.Org; -using DTO.Core; -using GateWay.WebApi.Controllers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Surging.Core.ApiGateWay; - -namespace GateWay.WebApi.Areas.OrgManger.Controllers -{ - //[Produces("application/json")] - [Route("api/[controller]")] - public class RoleController : BaseApiController - { - private IOrgAppService _orgProxy; - - public RoleController() - { - _orgProxy = serviceProxyFactory.CreateProxy(); - } - - - #region 角色 - [HttpPost] - public async Task> Post(RoleEditReq req) - { - var result = await _orgProxy.CreateRole(req); - return ServiceResult.Create(result.OperateFlag, result.OperateResult); - } - - [HttpGet("list")] - public async Task> GetRoleTree(CommonCMDReq req) - { - var result = await _orgProxy.FindCorpRoles(req); - return ServiceResult.Create(true, result); - } - - - #endregion - - #region 角色包含的权限 - - #endregion - } -} \ No newline at end of file diff --git a/samples/GateWay.WebApi/Configs/appsettings.Development.json b/samples/GateWay.WebApi/Configs/appsettings.Development.json deleted file mode 100644 index fa8ce71a9..000000000 --- a/samples/GateWay.WebApi/Configs/appsettings.Development.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/samples/GateWay.WebApi/Configs/appsettings.json b/samples/GateWay.WebApi/Configs/appsettings.json deleted file mode 100644 index 26bb0ac7a..000000000 --- a/samples/GateWay.WebApi/Configs/appsettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "Debug": { - "LogLevel": { - "Default": "Warning" - } - }, - "Console": { - "LogLevel": { - "Default": "Warning" - } - } - } -} diff --git a/samples/GateWay.WebApi/Configs/cacheSettings.json b/samples/GateWay.WebApi/Configs/cacheSettings.json deleted file mode 100644 index ab9c7e43d..000000000 --- a/samples/GateWay.WebApi/Configs/cacheSettings.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "CachingSettings": [ - { - "Id": "ddlCache", - "Class": "Surging.Core.Caching.RedisCache.RedisContext,Surging.Core.Caching", - "Properties": [ - { - "Name": "appRuleFile", - "Ref": "rule" - }, - { - "Name": "dataContextPool", - "Ref": "ddls_sample", - "Maps": [ - { - "Name": "Redis", - "Properties": [ - { - "value": "127.0.0.1:6379::1" - } - ] - }, - { - "Name": "MemoryCache" - } - ] - }, - { - "Name": "defaultExpireTime", - "value": "120" - }, - { - "Name": "connectTimeout", - "Value": "120" - }, - { - "Name": "minSize", - "Value": "1" - }, - { - "Name": "maxSize", - "Value": "10" - } - ] - } - ] -} diff --git a/samples/GateWay.WebApi/Configs/gatewaySettings.json b/samples/GateWay.WebApi/Configs/gatewaySettings.json deleted file mode 100644 index 24fa1cba2..000000000 --- a/samples/GateWay.WebApi/Configs/gatewaySettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "AccessTokenExpireTimeSpan": "30", - "AuthorizationRoutePath": "api/authapp/signin", - "AuthorizationServiceKey": "Auth", - "TokenEndpointPath": "api/Auth", - "Register": { - "Provider": "Consul", - "Address": "127.0.0.1:8500" - } -} diff --git a/samples/GateWay.WebApi/Controllers/AuthController.cs b/samples/GateWay.WebApi/Controllers/AuthController.cs deleted file mode 100644 index 93e141624..000000000 --- a/samples/GateWay.WebApi/Controllers/AuthController.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.ProxyGenerator; - -namespace Centa.Agency.WebApi.Controllers -{ - /// - /// 身份认证 - /// - [Route("api/[controller]")] - public class AuthController : Controller - { - /// - /// 登录 - /// - /// - [HttpPost("token")] - public object SignIn( [FromBody]Dictionary model) - { - model.Add("user", JsonConvert.SerializeObject(new - { - Name = "fanly", - Age = 18, - UserId = 1 - })); - string path = "api/AuthApp/SignIn"; - string serviceKey = "Auth"; - - - var serviceProxyProvider = ServiceLocator.GetService(); - return serviceProxyProvider.Invoke(model, path, serviceKey).Result; - - } - } -} diff --git a/samples/GateWay.WebApi/Controllers/BaseApiController.cs b/samples/GateWay.WebApi/Controllers/BaseApiController.cs deleted file mode 100644 index d484b5799..000000000 --- a/samples/GateWay.WebApi/Controllers/BaseApiController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Caching.Distributed; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.ProxyGenerator; - -namespace GateWay.WebApi.Controllers -{ - [Produces("application/json")] - [Route("api/BaseApi")] - public class BaseApiController : Controller //ControllerBase - { - protected IServiceProxyFactory serviceProxyFactory = ServiceLocator.GetService(); - protected readonly IDistributedCache _cache; - } -} \ No newline at end of file diff --git a/samples/GateWay.WebApi/Controllers/ServicesController.cs b/samples/GateWay.WebApi/Controllers/ServicesController.cs deleted file mode 100644 index c298b28fb..000000000 --- a/samples/GateWay.WebApi/Controllers/ServicesController.cs +++ /dev/null @@ -1,219 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Surging.Core.ApiGateWay; -using Surging.Core.ApiGateWay.OAuth; -using Surging.Core.CPlatform; -using Surging.Core.CPlatform.Filters.Implementation; -using Surging.Core.CPlatform.Routing; -using Surging.Core.ProxyGenerator; -using Surging.Core.ProxyGenerator.Utilitys; -using System; -using System.Collections.Generic; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using System.Linq; -using GateWayAppConfig = Surging.Core.ApiGateWay.AppConfig; -using System.Reflection; -using Surging.Core.CPlatform.Utilities; - -namespace GateWay.WebApi -{ - /// - /// 身份认证 - /// - [Route("api/[controller]")] - public class AuthController : Controller - { - private readonly IServiceProxyProvider _serviceProxyProvider; - private readonly IServiceRouteProvider _serviceRouteProvider; - private readonly IAuthorizationServerProvider _authorizationServerProvider; - - - public AuthController() - /* IServiceProxyProvider serviceProxyProvider, - IServiceRouteProvider serviceRouteProvider, - IAuthorizationServerProvider authorizationServerProvider) - */ - { - // ServiceLocator.GetService(); // - //_serviceProxyProvider = serviceProxyProvider; - //_serviceRouteProvider = serviceRouteProvider; - //_authorizationServerProvider = authorizationServerProvider; - - _serviceProxyProvider = ServiceLocator.GetService(); - _serviceRouteProvider = ServiceLocator.GetService(); //serviceRouteProvider; - _authorizationServerProvider = ServiceLocator.GetService();// authorizationServerProvider; - - - } - - [HttpGet] - public IEnumerable Get() - { - return new string[] { "value1", "value2" }; - } - - /// - /// 登录 - /// - /// - /// - /// - /// - [HttpPost] - public async Task> Post(string path, string serviceKey, Dictionary model) - { - model = model ?? new Dictionary(); - ServiceResult result = ServiceResult.Create(false, null); - path = string.IsNullOrEmpty(path) ? - GateWayAppConfig.AuthorizationRoutePath : path.ToLower(); - if (OnAuthorization(path, model, ref result)) - { - if (path == GateWayAppConfig.AuthorizationRoutePath) - { - var token = await _authorizationServerProvider.GenerateTokenCredential(model); - if (token != null) - { - result = ServiceResult.Create(true, token); - result.StatusCode = (int)ServiceStatusCode.Success; - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - } - } - else - { - if (!string.IsNullOrEmpty(serviceKey)) - { - - result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, path, serviceKey)); - result.StatusCode = (int)ServiceStatusCode.Success; - } - else - { - result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, path)); - result.StatusCode = (int)ServiceStatusCode.Success; - } - } - } - return result; - } - - private bool OnAuthorization(string path, Dictionary model, ref ServiceResult result) - { - bool isSuccess = true; - var route = _serviceRouteProvider.GetRouteByPath(path).Result; - if (route.ServiceDescriptor.EnableAuthorization()) - { - if (route.ServiceDescriptor.AuthType() == AuthorizationType.JWT.ToString()) - { - isSuccess = ValidateJwtAuthentication(route, model, ref result); - } - else - { - isSuccess = ValidateAppSecretAuthentication(route, path, model, ref result); - } - - } - return isSuccess; - } - - public bool ValidateJwtAuthentication(ServiceRoute route, Dictionary model, ref ServiceResult result) - { - bool isSuccess = true; - var author = HttpContext.Request.Headers["Authorization"]; - if (author.Count > 0) - { - if (route.Address.Any(p => p.DisableAuth == false)) - { - isSuccess = _authorizationServerProvider.ValidateClientAuthentication(author).Result; - if (!isSuccess) - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - } - else - { - var keyValue = model.FirstOrDefault(); - if (!(keyValue.Value is IConvertible) || !typeof(IConvertible).GetTypeInfo().IsAssignableFrom(keyValue.Value.GetType())) - { - dynamic instance = keyValue.Value; - instance.Payload = _authorizationServerProvider.GetPayloadString(author); - model.Remove(keyValue.Key); - model.Add(keyValue.Key, instance); - } - } - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; - isSuccess = false; - } - return isSuccess; - } - - private bool ValidateAppSecretAuthentication(ServiceRoute route, string path, - Dictionary model, ref ServiceResult result) - { - bool isSuccess = true; - DateTime time; - var author = HttpContext.Request.Headers["Authorization"]; - if (route.Address.Any(p => p.DisableAuth == false)) - { - if (!string.IsNullOrEmpty(path) && model.ContainsKey("timeStamp") && author.Count > 0) - { - if (DateTime.TryParse(model["timeStamp"].ToString(), out time)) - { - var seconds = (DateTime.Now - time).TotalSeconds; - if (seconds <= 3560 && seconds >= 0) - { - if (!route.Address.Any(p => GetMD5($"{p.Token}{time.ToString("yyyy-MM-dd hh:mm:ss") }") == author.ToString())) - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; - isSuccess = false; - } - } - return isSuccess; - } - - public static string GetMD5(string encypStr) - { - try - { - var md5 = MD5.Create(); - var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(encypStr)); - var sb = new StringBuilder(); - foreach (byte b in bs) - { - sb.Append(b.ToString("X2")); - } - //所有字符转为大写 - return sb.ToString().ToLower(); - } - catch (Exception e) - { - Console.Error.WriteLine(e.StackTrace); - return null; - } - } - } -} diff --git a/samples/GateWay.WebApi/Controllers/ValuesController.cs b/samples/GateWay.WebApi/Controllers/ValuesController.cs deleted file mode 100644 index f09497629..000000000 --- a/samples/GateWay.WebApi/Controllers/ValuesController.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; - -namespace GateWay.WebApi -{ - [Route("api/[controller]")] - public class ValuesController : Controller - { - [HttpGet] - public IEnumerable Get() - { - return new string[] { "value1", "value2" }; - } - - [HttpGet("{id}")] - public string Get(int id) - { - return "value"; - } - - [HttpPost] - public void Post([FromBody]string value) - { - } - - [HttpPut("{id}")] - public void Put(int id, [FromBody]string value) - { - } - - [HttpDelete("{id}")] - public void Delete(int id) - { - } - } -} diff --git a/samples/GateWay.WebApi/CustomExceptionFilterAttribute.cs b/samples/GateWay.WebApi/CustomExceptionFilterAttribute.cs deleted file mode 100644 index 93393e9e7..000000000 --- a/samples/GateWay.WebApi/CustomExceptionFilterAttribute.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Surging.Core.ApiGateWay; -using Surging.Core.ApiGateWay.OAuth; -using Surging.Core.CPlatform.Utilities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GateWay.WebApi -{ - public class ResponeMsg - { - public string IsSucceed { get; set; } - public int StatusCode { get; set; } - public string Message { get; set; } - } - - public class CustomExceptionFilterAttribute : ExceptionFilterAttribute - { - private readonly IHostingEnvironment _hostingEnvironment; - private readonly IModelMetadataProvider _modelMetadataProvider; - - public CustomExceptionFilterAttribute( - IHostingEnvironment hostingEnvironment, - IModelMetadataProvider modelMetadataProvider) - { - _hostingEnvironment = hostingEnvironment; - _modelMetadataProvider = modelMetadataProvider; - } - - public override void OnException(ExceptionContext context) - { - if (!_hostingEnvironment.IsDevelopment()) - { - return; - } - var result = ServiceResult.Create(false, errorMessage: "request fail"); - result.StatusCode = 400; - context.Result = new JsonResult(result); - } - } - - public class CustomAuthorizeFilter : Attribute, IAuthorizationFilter - { - public void OnAuthorization(AuthorizationFilterContext context) - { - var isSuccess = false; - var _authorizationServerProvider = ServiceLocator.GetService(); - var author = context.HttpContext.Request.Headers["Authorization"]; - if(author.Count > 0) - { - isSuccess = _authorizationServerProvider.ValidateClientAuthentication(author).Result; - } - if (true||!isSuccess) - { - context.Result = new UnauthorizedResult(); - } - - /* var entry = - Dns.GetHostEntryAsync(context.HttpContext.Connection.RemoteIpAddress) - .GetAwaiter() - .GetResult(); - if (!entry.HostName.EndsWith(".MyDomain", - StringComparison.OrdinalIgnoreCase)) - { - context.Result = new UnauthorizedResult(); - } - */ - } - } -} - diff --git a/samples/GateWay.WebApi/GateWay.WebApi.csproj b/samples/GateWay.WebApi/GateWay.WebApi.csproj deleted file mode 100644 index b97ec5f3d..000000000 --- a/samples/GateWay.WebApi/GateWay.WebApi.csproj +++ /dev/null @@ -1,51 +0,0 @@ - - - - netcoreapp2.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\pack\Surging.Core.ApiGateWay.dll - - - - diff --git a/samples/GateWay.WebApi/HiddenApiFilter.cs b/samples/GateWay.WebApi/HiddenApiFilter.cs deleted file mode 100644 index bc9021507..000000000 --- a/samples/GateWay.WebApi/HiddenApiFilter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Swashbuckle.AspNetCore.Swagger; -using Swashbuckle.AspNetCore.SwaggerGen; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace GateWay.WebApi -{ - /// - /// 隐藏接口,不生成到swagger文档展示 - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] - - public partial class HiddenApiAttribute : Attribute { } - public class HiddenApiFilter : IDocumentFilter - { - /// - /// 重写Apply方法,移除隐藏接口的生成 - /// - /// - /// - public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) - { - foreach (ApiDescriptionGroup apiDescriptionGroup in context.ApiDescriptionsGroups.Items) - { - foreach (var apiDescription in apiDescriptionGroup.Items) - { - if(apiDescription.ControllerAttributes().First(c => c is HiddenApiAttribute)!=null) //if (Enumerable.OfType(apiDescription.ControllerAttributes().Where(c=>c is HiddenApiAttribute).ToList()) - { - string key = "/" + apiDescription.RelativePath; - if (key.Contains("?")) - { - int idx = key.IndexOf("?", StringComparison.Ordinal); - key = key.Substring(0, idx); - } - swaggerDoc.Paths.Remove(key); - } - } - - } - } - } -} diff --git a/samples/GateWay.WebApi/Program.cs b/samples/GateWay.WebApi/Program.cs deleted file mode 100644 index 42bc45609..000000000 --- a/samples/GateWay.WebApi/Program.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace GateWay.WebApi -{ - public class Program - { - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .UseUrls("http://*:729") - .UseKestrel(options => - { - options.Limits.MaxConcurrentConnections = 100; - options.Limits.MaxConcurrentUpgradedConnections = 100; - options.Limits.MaxRequestBodySize = 10 * 1024; - options.Limits.MinRequestBodyDataRate = - new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10)); - options.Limits.MinResponseDataRate = - new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10)); - }) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseStartup() - .UseApplicationInsights() - .Build(); - host.Run(); - // BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .Build(); - } -} diff --git a/samples/GateWay.WebApi/Properties/launchSettings.json b/samples/GateWay.WebApi/Properties/launchSettings.json deleted file mode 100644 index c5d069c3f..000000000 --- a/samples/GateWay.WebApi/Properties/launchSettings.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:729/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "api/values", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Centa.Agency.WebApi": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "api/values", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:56956/" - } - } -} \ No newline at end of file diff --git a/samples/GateWay.WebApi/ScaffoldingReadMe.txt b/samples/GateWay.WebApi/ScaffoldingReadMe.txt deleted file mode 100644 index 19b66d8a3..000000000 --- a/samples/GateWay.WebApi/ScaffoldingReadMe.txt +++ /dev/null @@ -1,12 +0,0 @@ -Scaffolding has generated all the files and added the required dependencies. - -However the Application's Startup code may required additional changes for things to work end to end. -Add the following code to the Configure method in your Application's Startup class if not already done: - - app.UseMvc(routes => - { - route.MapRoute( - name : "areas", - template : "{area:exists}/{controller=Home}/{action=Index}/{id?}" - ); - }); diff --git a/samples/GateWay.WebApi/Startup.cs b/samples/GateWay.WebApi/Startup.cs deleted file mode 100644 index 942233503..000000000 --- a/samples/GateWay.WebApi/Startup.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using Autofac; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Swashbuckle.AspNetCore.Swagger; -using Newtonsoft.Json.Serialization; -using ApiGateWayConfig = Surging.Core.ApiGateWay.AppConfig; -using Surging.Core.CPlatform; -using Surging.Core.ProxyGenerator; -using Surging.Core.Consul; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.DotNetty; -using Surging.Core.Consul.Configurations; -using Surging.Core.ApiGateWay.OAuth.Implementation.Configurations; -using Autofac.Extensions.DependencyInjection; -using Surging.Core.ApiGateWay; -using Surging.Core.Caching.Configurations; -using Surging.Core.Codec.MessagePack; -using Microsoft.AspNetCore.Mvc; - -namespace GateWay.WebApi -{ - public class Startup - { - public IConfiguration Configuration { get; } - public IContainer ApplicationContainer { get; private set; } - - public Startup(IHostingEnvironment env) - { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddCacheFile("Configs/cacheSettings.json", optional: false) - .AddJsonFile("Configs/appsettings.json", optional: true, reloadOnChange: true) - .AddGatewayFile("Configs/gatewaySettings.json", optional: false) - .AddJsonFile($"Configs/appsettings.{env.EnvironmentName}.json", optional: true); - Configuration = builder.Build(); - } - - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - RegisterAutofac(services); - // Register the Swagger generator, defining one or more Swagger documents - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new Info { Title = "网关 API", Version = "v1" }); - c.DescribeAllParametersInCamelCase(); - }); - - // services.AddResponseCaching(); - - //分布式缓存 Microsoft.Extensions.Caching.Redis NuGet package - /*services.AddDistributedRedisCache(options => - { - options.Configuration = "servername"; - options.InstanceName = "Shopping"; - });*/ - //基于 的身份认证 - /* services.AddCookieAuthentication(CookieAuthenticationDefaults.Authenticatio - nScheme, options => - { - options.LoginPath = "/Account/Login/"; - options.AccessDeniedPath = "/Account/Forbidden/"; - options.LogoutPath = "/Account/Logout"; - options.ReturnUrlParameter = "ReturnUrl"; - }); - - Microsoft.AspNetCore.Identity.EntityFrameworkCore - - services.AddEntityFramework() -.AddSqlServer() -.AddDbContext(options => -options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString -"])); -services.AddIdentity() -.AddEntityFrameworkStores() -.AddDefaultTokenProviders(); - - - services.AddCors(); - - - - - - - - */ - } - - private IServiceProvider RegisterAutofac(IServiceCollection services) - { - var registerConfig = ApiGateWayConfig.Register; - services.AddMvc(options => - { - options.Filters.Add(typeof(CustomExceptionFilterAttribute)); - //options.CacheProfiles.Add("5minutes", new CacheProfile - //{ - // Duration = 5 * 60, - // Location = ResponseCacheLocation.Any, - // VaryByHeader = "Accept-Language" - //}); - //[ResponseCache(CacheProfileName = "5minutes")] - }).AddJsonOptions(options => - { - options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; - options.SerializerSettings.ContractResolver = new DefaultContractResolver(); - }); - services.AddLogging(); - var builder = new ContainerBuilder(); - builder.Populate(services); - builder.AddMicroService(option => - { - option.AddClient(); - // option.AddClientIntercepted(typeof(CacheProviderInterceptor)); - option.UseConsulManager(new ConfigInfo(registerConfig.Address)); - option.UseDotNettyTransport(); - option.AddApiGateWay(); - option.UseJsonCodec(); - // option.UseMessagePackCodec(); - builder.Register(m => new CPlatformContainer(ServiceLocator.Current)); - }); - ServiceLocator.Current = builder.Build(); - return new AutofacServiceProvider(ServiceLocator.Current); - - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - - - } - else - { - app.UseExceptionHandler("/Home/Error"); - } - app.UseStaticFiles(); - - // app.UseAuthentication(); - //app.UseCors(builder => builder.WithOrigins("http://mysite.com")); - //app.UseResponseCaching(); - app.UseMvc(); - - // Enable middleware to serve generated Swagger as a JSON endpoint. - app.UseSwagger(); - - // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint. - app.UseSwaggerUI(c => - { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "网关 API V1"); - }); - - } - } -} diff --git a/samples/GateWay.WebApi/appsettings.Development.json b/samples/GateWay.WebApi/appsettings.Development.json deleted file mode 100644 index fa8ce71a9..000000000 --- a/samples/GateWay.WebApi/appsettings.Development.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/samples/GateWay.WebApi/appsettings.json b/samples/GateWay.WebApi/appsettings.json deleted file mode 100644 index 26bb0ac7a..000000000 --- a/samples/GateWay.WebApi/appsettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "Debug": { - "LogLevel": { - "Default": "Warning" - } - }, - "Console": { - "LogLevel": { - "Default": "Warning" - } - } - } -} diff --git a/samples/LogServer/Application.Interface.SysLog/Application.Interface.SysLog.csproj b/samples/LogServer/Application.Interface.SysLog/Application.Interface.SysLog.csproj deleted file mode 100644 index 8b977eded..000000000 --- a/samples/LogServer/Application.Interface.SysLog/Application.Interface.SysLog.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - diff --git a/samples/LogServer/Application.Interface.SysLog/ILogAppService.cs b/samples/LogServer/Application.Interface.SysLog/ILogAppService.cs deleted file mode 100644 index db0c2c0aa..000000000 --- a/samples/LogServer/Application.Interface.SysLog/ILogAppService.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Surging.Core.CPlatform.Ioc; -using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Application.Interface.SysLog -{ - public class LogListViewDto - { - /// - /// 日志类型 - /// - public string LogType { get; set; } - - /// - /// 日志类型 - /// - public DateTime CreateTime { get; set; } - - /// - /// 操作部门 - /// - public string OpDept { get; set; } - - /// - /// 操作人 - /// - public string OpUser { get; set; } - } - [ServiceBundle("api/{Service}")] - public interface ILogAppService : IServiceKey - { - /// - /// 列表分页查询 - /// - /// - [Service(Date = "2018-1-20", Director = "刘旭东", Name = "查询日志")] - //[Authorization(AuthType = AuthorizationType.JWT)] - // [BindEvent("修改系统参数的事件|订单支付的事件")] - Task> PagedQuery(int pageIndex,int pageSize); - - - } -} diff --git a/samples/LogServer/Application.Service.SysLog/Application.Service.SysLog.csproj b/samples/LogServer/Application.Service.SysLog/Application.Service.SysLog.csproj deleted file mode 100644 index 72bd41272..000000000 --- a/samples/LogServer/Application.Service.SysLog/Application.Service.SysLog.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - - - - - diff --git a/samples/LogServer/Application.Service.SysLog/LogAppService.cs b/samples/LogServer/Application.Service.SysLog/LogAppService.cs deleted file mode 100644 index 717e0794e..000000000 --- a/samples/LogServer/Application.Service.SysLog/LogAppService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Application.Interface.SysLog; -using Surging.Core.ProxyGenerator; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Application.Service.SysLog -{ - public class LogAppService : ProxyServiceBase, ILogAppService - { - public Task> PagedQuery(int pageIndex, int pageSize) - { - throw new NotImplementedException(); - } - } -} diff --git a/samples/LogServer/HostService/Configs/log4net.config b/samples/LogServer/HostService/Configs/log4net.config deleted file mode 100644 index 42fd16880..000000000 --- a/samples/LogServer/HostService/Configs/log4net.config +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/LogServer/HostService/HostService.csproj b/samples/LogServer/HostService/HostService.csproj deleted file mode 100644 index 2339f49f1..000000000 --- a/samples/LogServer/HostService/HostService.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - Exe - netcoreapp2.0 - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - diff --git a/samples/LogServer/HostService/Program.cs b/samples/LogServer/HostService/Program.cs deleted file mode 100644 index 0b4ed6bc8..000000000 --- a/samples/LogServer/HostService/Program.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Autofac; -using Surging.Core.Codec.MessagePack; -using Surging.Core.Consul; -using Surging.Core.Consul.Configurations; -using Surging.Core.CPlatform; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.DotNetty; -using Surging.Core.EventBusRabbitMQ; -using Surging.Core.ServiceHosting; -using Surging.Core.ServiceHosting.Internal.Implementation; -using System; -using System.Text; -using Surging.Core.Log4net; -using Surging.Core.ProxyGenerator; - -namespace Centa.HostService.SysLog -{ - public class Program - { - static void Main(string[] args) - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - var host = new ServiceHostBuilder() - //.RegisterServices(provider => - //{ - // //这里写自己的注册 - //}) - .RegisterServices(builder => - { - builder.AddMicroService(option => - { - option.AddServiceRuntime(); - option.AddRelateService(); - option.UseConsulManager(new ConfigInfo("127.0.0.1:8500")); - option.UseDotNettyTransport(); - option.UseRabbitMQTransport(); - option.AddRabbitMQAdapt(); - // option.UseMessagePackCodec(); - option.UseJsonCodec(); - builder.Register(p => new CPlatformContainer(ServiceLocator.Current)); - }); - }) - .SubscribeAt() - .UseLog4net("Configs/log4net.config") - .UseServer(options => - { - options.Ip = "127.0.0.1"; - options.Port = 2018; - options.Token = "True"; - options.ExecutionTimeoutInMilliseconds = 30000; - options.MaxConcurrentRequests = 200; - }) - // .UseProxy() - .UseStartup() - .Build(); - - using (host.Run()) - { - Console.WriteLine($"服务端启动成功,{DateTime.Now}。"); - Console.ReadLine(); - } - } - } -} diff --git a/samples/LogServer/HostService/Startup.cs b/samples/LogServer/HostService/Startup.cs deleted file mode 100644 index 1b90c95a5..000000000 --- a/samples/LogServer/HostService/Startup.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.EventBusRabbitMQ.Configurations; -using System; - -namespace Centa.HostService.SysLog -{ - public class Startup - { - public Startup() - { - var config = new ConfigurationBuilder() - .SetBasePath(AppContext.BaseDirectory); - ConfigureEventBus(config); - ConfigureCache(config); - } - - public IContainer ConfigureServices(ContainerBuilder builder) - { - var services = new ServiceCollection(); - ConfigureLogging(services); - builder.Populate(services); - ServiceLocator.Current = builder.Build(); - return ServiceLocator.Current; - } - - public void Configure(IContainer app) - { - app.Resolve().AddConsole((c, l) => (int)l >= 3); - } - - #region 私有方法 - /// - /// 配置日志服务 - /// - /// - private void ConfigureLogging(IServiceCollection services) - { - services.AddLogging(); - } - - private static void ConfigureEventBus(IConfigurationBuilder build) - { - build - .AddEventBusFile("eventBusSettings.json", optional: false); - } - - /// - /// 配置缓存服务 - /// - private void ConfigureCache(IConfigurationBuilder build) - { - // build.AddCacheFile("cacheSettings.json", optional: false); - } - #endregion - - } -} diff --git a/samples/LogServer/HostService/cacheSettings.json b/samples/LogServer/HostService/cacheSettings.json deleted file mode 100644 index ab9c7e43d..000000000 --- a/samples/LogServer/HostService/cacheSettings.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "CachingSettings": [ - { - "Id": "ddlCache", - "Class": "Surging.Core.Caching.RedisCache.RedisContext,Surging.Core.Caching", - "Properties": [ - { - "Name": "appRuleFile", - "Ref": "rule" - }, - { - "Name": "dataContextPool", - "Ref": "ddls_sample", - "Maps": [ - { - "Name": "Redis", - "Properties": [ - { - "value": "127.0.0.1:6379::1" - } - ] - }, - { - "Name": "MemoryCache" - } - ] - }, - { - "Name": "defaultExpireTime", - "value": "120" - }, - { - "Name": "connectTimeout", - "Value": "120" - }, - { - "Name": "minSize", - "Value": "1" - }, - { - "Name": "maxSize", - "Value": "10" - } - ] - } - ] -} diff --git a/samples/LogServer/HostService/eventBusSettings.json b/samples/LogServer/HostService/eventBusSettings.json deleted file mode 100644 index d5d4487b7..000000000 --- a/samples/LogServer/HostService/eventBusSettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "EventBusConnection": "localhost", - "EventBusUserName": "guest", - "EventBusPassword": "guest" -} - diff --git a/samples/MicroService.sln b/samples/MicroService.sln deleted file mode 100644 index 64818f727..000000000 --- a/samples/MicroService.sln +++ /dev/null @@ -1,206 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2010 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FrontEnd", "FrontEnd", "{16D922E9-E971-4E09-8957-2BEC03950B59}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Doc", "Doc", "{6B3A06FA-EF30-4CB4-955F-AF7FE2E9C60D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{24CC1A19-D3EE-4B3E-89EC-012BA4AFD112}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LogServer", "LogServer", "{11EC931F-CFB3-4395-BB64-1295DBA7CC3D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1-Distributed Services", "1-Distributed Services", "{7B1CB514-E30D-4D9D-B0DD-AC31AD7BB543}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2-Application Services", "2-Application Services", "{4AE3BF33-FE59-4FD2-BB67-E4CB313708C5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4-Repository", "4-Repository", "{7ED005CB-4A0C-4E2A-8723-EF98EDC58037}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repository.Dapper.Core", "Common\Repository.Dapper.Core\Repository.Dapper.Core.csproj", "{52B3EA74-1B2C-44B2-A617-9F32B3135818}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repository.EF.Core", "Common\Repository.EF.Core\Repository.EF.Core.csproj", "{2F30368D-2ECE-4833-AE7B-0FDC34BA3102}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DDD.Core", "Common\DDD.Core\DDD.Core.csproj", "{FABAFCF3-4A9A-4853-8178-CFA7FC93E8BB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTO.Core", "Common\DTO.Core\DTO.Core.csproj", "{93CC491E-83CD-47B6-8142-5F4CD28AC614}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostService", "LogServer\HostService\HostService.csproj", "{FBB4AF83-CD4A-4428-8C10-676B2658006A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.Interface.SysLog", "LogServer\Application.Interface.SysLog\Application.Interface.SysLog.csproj", "{631D7361-D683-4909-91F1-5C3324DCA282}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.Service.SysLog", "LogServer\Application.Service.SysLog\Application.Service.SysLog.csproj", "{53D00367-E40B-472A-935F-4C27B5762128}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AuthServer", "AuthServer", "{1AFE40BE-F129-457C-AA23-C9A19D6ADF4F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1-Distributed Services", "1-Distributed Services", "{0AB757EA-7849-4461-9849-40D49B3E86ED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostService", "AuthServer\HostService\HostService.csproj", "{6313CF74-D8EE-4D18-93FD-6F2DAC33D90E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2-Application Services", "2-Application Services", "{904FEED6-3597-4BFB-9BF3-5DA54DC705A3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.Interface.Auth", "AuthServer\Application.Interface.Auth\Application.Interface.Auth.csproj", "{936B0D84-8B2A-4DEA-A287-0290EC64C017}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.Service.Auth", "AuthServer\Application.Service.Auth\Application.Service.Auth.csproj", "{6E4677D6-60A5-4868-B92A-6FE8FF1714D2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4-Repository", "4-Repository", "{95507E5B-2725-4263-93A0-4DF88A32C9D1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OrgServer", "OrgServer", "{6850BB45-B72B-45FD-969B-58A5852FE52D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1-Distributed Services", "1-Distributed Services", "{977B9CD7-FA17-417F-8577-2A13E7D6AFB9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2-Application Services", "2-Application Services", "{7F1BD8CD-4F80-4586-B3BE-B8B159E224A5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4-Repository", "4-Repository", "{27935240-E1E5-4D55-AFA2-27AA92681789}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostService", "OrgServer\HostService\HostService.csproj", "{C19A5D2C-8E75-41AE-A1FF-D63D25CB98A0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.Interface.Org", "OrgServer\Application.Interface.Org\Application.Interface.Org.csproj", "{F47E8649-62A3-4B7F-8B81-13E995D17DAF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.Service.Org", "OrgServer\Application.Service.Org\Application.Service.Org.csproj", "{797C2369-5E7D-4CA3-8AAC-15BE4604E7C7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App.Core", "Common\App.Core\App.Core.csproj", "{027BA86B-43EE-4825-A3E3-A988F847A1CA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3-Domain", "3-Domain", "{9924D2D9-6D66-44CA-B5F8-9A46ACD637C5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Domain.Org", "OrgServer\Domain\Domain.Org.csproj", "{F44DCA50-03E6-46CF-9694-E15915C9F443}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3-Domain", "3-Domain", "{13D4465F-E298-46DD-822D-048BCF99CC47}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Domain.Auth", "AuthServer\Domain\Domain.Auth.csproj", "{2D571933-83F7-4D36-A0DB-3A47EAC64930}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repository.Auth", "AuthServer\Repository.Auth\Repository.Auth.csproj", "{543EEE3D-7A8D-44F1-86AB-B5EADB3579B2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repository.Org", "OrgServer\Repository.Org\Repository.Org.csproj", "{B884CB7A-70E7-4710-A49A-3F22E90BBF1E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Config.Core", "Common\Config.Core\Config.Core.csproj", "{91E42C03-C901-4085-A89F-B6BEED95E25F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GateWay.WebApi", "GateWay.WebApi\GateWay.WebApi.csproj", "{49370CFD-21BC-4B4E-8AB9-8CC8B18C3180}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {52B3EA74-1B2C-44B2-A617-9F32B3135818}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {52B3EA74-1B2C-44B2-A617-9F32B3135818}.Debug|Any CPU.Build.0 = Debug|Any CPU - {52B3EA74-1B2C-44B2-A617-9F32B3135818}.Release|Any CPU.ActiveCfg = Release|Any CPU - {52B3EA74-1B2C-44B2-A617-9F32B3135818}.Release|Any CPU.Build.0 = Release|Any CPU - {2F30368D-2ECE-4833-AE7B-0FDC34BA3102}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F30368D-2ECE-4833-AE7B-0FDC34BA3102}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F30368D-2ECE-4833-AE7B-0FDC34BA3102}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F30368D-2ECE-4833-AE7B-0FDC34BA3102}.Release|Any CPU.Build.0 = Release|Any CPU - {FABAFCF3-4A9A-4853-8178-CFA7FC93E8BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FABAFCF3-4A9A-4853-8178-CFA7FC93E8BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FABAFCF3-4A9A-4853-8178-CFA7FC93E8BB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FABAFCF3-4A9A-4853-8178-CFA7FC93E8BB}.Release|Any CPU.Build.0 = Release|Any CPU - {93CC491E-83CD-47B6-8142-5F4CD28AC614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93CC491E-83CD-47B6-8142-5F4CD28AC614}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93CC491E-83CD-47B6-8142-5F4CD28AC614}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93CC491E-83CD-47B6-8142-5F4CD28AC614}.Release|Any CPU.Build.0 = Release|Any CPU - {FBB4AF83-CD4A-4428-8C10-676B2658006A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FBB4AF83-CD4A-4428-8C10-676B2658006A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBB4AF83-CD4A-4428-8C10-676B2658006A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FBB4AF83-CD4A-4428-8C10-676B2658006A}.Release|Any CPU.Build.0 = Release|Any CPU - {631D7361-D683-4909-91F1-5C3324DCA282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {631D7361-D683-4909-91F1-5C3324DCA282}.Debug|Any CPU.Build.0 = Debug|Any CPU - {631D7361-D683-4909-91F1-5C3324DCA282}.Release|Any CPU.ActiveCfg = Release|Any CPU - {631D7361-D683-4909-91F1-5C3324DCA282}.Release|Any CPU.Build.0 = Release|Any CPU - {53D00367-E40B-472A-935F-4C27B5762128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {53D00367-E40B-472A-935F-4C27B5762128}.Debug|Any CPU.Build.0 = Debug|Any CPU - {53D00367-E40B-472A-935F-4C27B5762128}.Release|Any CPU.ActiveCfg = Release|Any CPU - {53D00367-E40B-472A-935F-4C27B5762128}.Release|Any CPU.Build.0 = Release|Any CPU - {6313CF74-D8EE-4D18-93FD-6F2DAC33D90E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6313CF74-D8EE-4D18-93FD-6F2DAC33D90E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6313CF74-D8EE-4D18-93FD-6F2DAC33D90E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6313CF74-D8EE-4D18-93FD-6F2DAC33D90E}.Release|Any CPU.Build.0 = Release|Any CPU - {936B0D84-8B2A-4DEA-A287-0290EC64C017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {936B0D84-8B2A-4DEA-A287-0290EC64C017}.Debug|Any CPU.Build.0 = Debug|Any CPU - {936B0D84-8B2A-4DEA-A287-0290EC64C017}.Release|Any CPU.ActiveCfg = Release|Any CPU - {936B0D84-8B2A-4DEA-A287-0290EC64C017}.Release|Any CPU.Build.0 = Release|Any CPU - {6E4677D6-60A5-4868-B92A-6FE8FF1714D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E4677D6-60A5-4868-B92A-6FE8FF1714D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E4677D6-60A5-4868-B92A-6FE8FF1714D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E4677D6-60A5-4868-B92A-6FE8FF1714D2}.Release|Any CPU.Build.0 = Release|Any CPU - {C19A5D2C-8E75-41AE-A1FF-D63D25CB98A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C19A5D2C-8E75-41AE-A1FF-D63D25CB98A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C19A5D2C-8E75-41AE-A1FF-D63D25CB98A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C19A5D2C-8E75-41AE-A1FF-D63D25CB98A0}.Release|Any CPU.Build.0 = Release|Any CPU - {F47E8649-62A3-4B7F-8B81-13E995D17DAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F47E8649-62A3-4B7F-8B81-13E995D17DAF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F47E8649-62A3-4B7F-8B81-13E995D17DAF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F47E8649-62A3-4B7F-8B81-13E995D17DAF}.Release|Any CPU.Build.0 = Release|Any CPU - {797C2369-5E7D-4CA3-8AAC-15BE4604E7C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {797C2369-5E7D-4CA3-8AAC-15BE4604E7C7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {797C2369-5E7D-4CA3-8AAC-15BE4604E7C7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {797C2369-5E7D-4CA3-8AAC-15BE4604E7C7}.Release|Any CPU.Build.0 = Release|Any CPU - {027BA86B-43EE-4825-A3E3-A988F847A1CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {027BA86B-43EE-4825-A3E3-A988F847A1CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {027BA86B-43EE-4825-A3E3-A988F847A1CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {027BA86B-43EE-4825-A3E3-A988F847A1CA}.Release|Any CPU.Build.0 = Release|Any CPU - {F44DCA50-03E6-46CF-9694-E15915C9F443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F44DCA50-03E6-46CF-9694-E15915C9F443}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F44DCA50-03E6-46CF-9694-E15915C9F443}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F44DCA50-03E6-46CF-9694-E15915C9F443}.Release|Any CPU.Build.0 = Release|Any CPU - {2D571933-83F7-4D36-A0DB-3A47EAC64930}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2D571933-83F7-4D36-A0DB-3A47EAC64930}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2D571933-83F7-4D36-A0DB-3A47EAC64930}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2D571933-83F7-4D36-A0DB-3A47EAC64930}.Release|Any CPU.Build.0 = Release|Any CPU - {543EEE3D-7A8D-44F1-86AB-B5EADB3579B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {543EEE3D-7A8D-44F1-86AB-B5EADB3579B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {543EEE3D-7A8D-44F1-86AB-B5EADB3579B2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {543EEE3D-7A8D-44F1-86AB-B5EADB3579B2}.Release|Any CPU.Build.0 = Release|Any CPU - {B884CB7A-70E7-4710-A49A-3F22E90BBF1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B884CB7A-70E7-4710-A49A-3F22E90BBF1E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B884CB7A-70E7-4710-A49A-3F22E90BBF1E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B884CB7A-70E7-4710-A49A-3F22E90BBF1E}.Release|Any CPU.Build.0 = Release|Any CPU - {91E42C03-C901-4085-A89F-B6BEED95E25F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {91E42C03-C901-4085-A89F-B6BEED95E25F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {91E42C03-C901-4085-A89F-B6BEED95E25F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {91E42C03-C901-4085-A89F-B6BEED95E25F}.Release|Any CPU.Build.0 = Release|Any CPU - {49370CFD-21BC-4B4E-8AB9-8CC8B18C3180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {49370CFD-21BC-4B4E-8AB9-8CC8B18C3180}.Debug|Any CPU.Build.0 = Debug|Any CPU - {49370CFD-21BC-4B4E-8AB9-8CC8B18C3180}.Release|Any CPU.ActiveCfg = Release|Any CPU - {49370CFD-21BC-4B4E-8AB9-8CC8B18C3180}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {7B1CB514-E30D-4D9D-B0DD-AC31AD7BB543} = {11EC931F-CFB3-4395-BB64-1295DBA7CC3D} - {4AE3BF33-FE59-4FD2-BB67-E4CB313708C5} = {11EC931F-CFB3-4395-BB64-1295DBA7CC3D} - {7ED005CB-4A0C-4E2A-8723-EF98EDC58037} = {11EC931F-CFB3-4395-BB64-1295DBA7CC3D} - {52B3EA74-1B2C-44B2-A617-9F32B3135818} = {24CC1A19-D3EE-4B3E-89EC-012BA4AFD112} - {2F30368D-2ECE-4833-AE7B-0FDC34BA3102} = {24CC1A19-D3EE-4B3E-89EC-012BA4AFD112} - {FABAFCF3-4A9A-4853-8178-CFA7FC93E8BB} = {24CC1A19-D3EE-4B3E-89EC-012BA4AFD112} - {93CC491E-83CD-47B6-8142-5F4CD28AC614} = {24CC1A19-D3EE-4B3E-89EC-012BA4AFD112} - {FBB4AF83-CD4A-4428-8C10-676B2658006A} = {7B1CB514-E30D-4D9D-B0DD-AC31AD7BB543} - {631D7361-D683-4909-91F1-5C3324DCA282} = {4AE3BF33-FE59-4FD2-BB67-E4CB313708C5} - {53D00367-E40B-472A-935F-4C27B5762128} = {4AE3BF33-FE59-4FD2-BB67-E4CB313708C5} - {0AB757EA-7849-4461-9849-40D49B3E86ED} = {1AFE40BE-F129-457C-AA23-C9A19D6ADF4F} - {6313CF74-D8EE-4D18-93FD-6F2DAC33D90E} = {0AB757EA-7849-4461-9849-40D49B3E86ED} - {904FEED6-3597-4BFB-9BF3-5DA54DC705A3} = {1AFE40BE-F129-457C-AA23-C9A19D6ADF4F} - {936B0D84-8B2A-4DEA-A287-0290EC64C017} = {904FEED6-3597-4BFB-9BF3-5DA54DC705A3} - {6E4677D6-60A5-4868-B92A-6FE8FF1714D2} = {904FEED6-3597-4BFB-9BF3-5DA54DC705A3} - {95507E5B-2725-4263-93A0-4DF88A32C9D1} = {1AFE40BE-F129-457C-AA23-C9A19D6ADF4F} - {977B9CD7-FA17-417F-8577-2A13E7D6AFB9} = {6850BB45-B72B-45FD-969B-58A5852FE52D} - {7F1BD8CD-4F80-4586-B3BE-B8B159E224A5} = {6850BB45-B72B-45FD-969B-58A5852FE52D} - {27935240-E1E5-4D55-AFA2-27AA92681789} = {6850BB45-B72B-45FD-969B-58A5852FE52D} - {C19A5D2C-8E75-41AE-A1FF-D63D25CB98A0} = {977B9CD7-FA17-417F-8577-2A13E7D6AFB9} - {F47E8649-62A3-4B7F-8B81-13E995D17DAF} = {7F1BD8CD-4F80-4586-B3BE-B8B159E224A5} - {797C2369-5E7D-4CA3-8AAC-15BE4604E7C7} = {7F1BD8CD-4F80-4586-B3BE-B8B159E224A5} - {027BA86B-43EE-4825-A3E3-A988F847A1CA} = {24CC1A19-D3EE-4B3E-89EC-012BA4AFD112} - {9924D2D9-6D66-44CA-B5F8-9A46ACD637C5} = {6850BB45-B72B-45FD-969B-58A5852FE52D} - {F44DCA50-03E6-46CF-9694-E15915C9F443} = {9924D2D9-6D66-44CA-B5F8-9A46ACD637C5} - {13D4465F-E298-46DD-822D-048BCF99CC47} = {1AFE40BE-F129-457C-AA23-C9A19D6ADF4F} - {2D571933-83F7-4D36-A0DB-3A47EAC64930} = {13D4465F-E298-46DD-822D-048BCF99CC47} - {543EEE3D-7A8D-44F1-86AB-B5EADB3579B2} = {95507E5B-2725-4263-93A0-4DF88A32C9D1} - {B884CB7A-70E7-4710-A49A-3F22E90BBF1E} = {27935240-E1E5-4D55-AFA2-27AA92681789} - {91E42C03-C901-4085-A89F-B6BEED95E25F} = {24CC1A19-D3EE-4B3E-89EC-012BA4AFD112} - {49370CFD-21BC-4B4E-8AB9-8CC8B18C3180} = {16D922E9-E971-4E09-8957-2BEC03950B59} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9536404C-EF7E-42FF-A785-CAADEA7C08A5} - EndGlobalSection -EndGlobal diff --git a/samples/OrgServer/Application.Interface.Org/Application.Interface.Org.csproj b/samples/OrgServer/Application.Interface.Org/Application.Interface.Org.csproj deleted file mode 100644 index e4da24ad5..000000000 --- a/samples/OrgServer/Application.Interface.Org/Application.Interface.Org.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - diff --git a/samples/OrgServer/Application.Interface.Org/DTO/DeptAddReq.cs b/samples/OrgServer/Application.Interface.Org/DTO/DeptAddReq.cs deleted file mode 100644 index ab9879432..000000000 --- a/samples/OrgServer/Application.Interface.Org/DTO/DeptAddReq.cs +++ /dev/null @@ -1,111 +0,0 @@ -using DTO.Core; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Application.Interface.Org -{ - public class DeptEditReq : EntityCUDReq - { - /// - /// 所属公司ID - /// - - public Guid CorporationKeyId { get; set; } - public Guid? DepartmentKeyId { get; set; } - - /// - /// 部门名称 - /// - - public string DepartmentName { get; set; } - - /// - /// 部门名称简拼 - /// - - public string NameSpell { get; set; } - - /// - /// 部门编号 - /// - - public string DepartmentNo { get; set; } - - - - /// - /// 部门负责人KeyId - /// - - public Guid? DeptCheifKeyId { get; set; } - /// - /// 部门上一级负责人 - /// - - public Guid? ParentDeptCheifKeyId { get; set; } - /// - /// 部门上一级负责人部门ID - /// - - public Guid? ParentDeptCheifDeptId { get; set; } - /// - /// 父部门KeyId - /// - - public Guid? ParentDeptKeyId { get; set; } - - /// - /// 部门电话 - /// - - public string Telephone { get; set; } - - /// - /// 部门来源(null为A+系统新增,1为CCAI系统新增) - /// - - public int? SourceObjectFlag { get; set; } - - /// - /// 纬度 - /// - - public string Latitude { get; set; } - /// - /// 经度 - /// - - public string Longitude { get; set; } - - /// - /// 部门类型(普通额外公客池、客源市场) - /// - - // public DepartmentTypeEnum? DepartmentType { get; set; } - } - - public class CorpEditReq: EntityCUDReq - { - public string CorpName { get; set; } - - } - - public class RoleEditReq : EntityCUDReq - { - public string RoleName { get; set; } - - } - - public class EmployeeEditReq : EntityCUDReq - { - public string Name { get; set; } - public string Mobile { get; set; } - public Guid DeptKeyId { get; set; } - public Guid RoleKeyId { get; set; } - public string RoleName { get; set; } - - - - } -} diff --git a/samples/OrgServer/Application.Interface.Org/EVENT/CorporationActivated.cs b/samples/OrgServer/Application.Interface.Org/EVENT/CorporationActivated.cs deleted file mode 100644 index a157e80bd..000000000 --- a/samples/OrgServer/Application.Interface.Org/EVENT/CorporationActivated.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Surging.Core.CPlatform.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Application.Interface.Org.EVENT -{ - /// - /// 新注册公司被激活的事件 - /// - public class CorporationActivatedEvent: IntegrationEvent - { - public Guid CorpId { get; set; } - public string Email { get; set; } - public string EmpId { get; set; } - - } -} diff --git a/samples/OrgServer/Application.Interface.Org/EVENT/ICorpEventHandler.cs b/samples/OrgServer/Application.Interface.Org/EVENT/ICorpEventHandler.cs deleted file mode 100644 index 2d1ae5637..000000000 --- a/samples/OrgServer/Application.Interface.Org/EVENT/ICorpEventHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Application.Interface.Org -{ - /// - /// 事件处理器 - /// - public interface ICorpEventHandler //: IIntegrationEventHandler - { - } -} diff --git a/samples/OrgServer/Application.Interface.Org/IOrgAppService.cs b/samples/OrgServer/Application.Interface.Org/IOrgAppService.cs deleted file mode 100644 index e4ff25a6a..000000000 --- a/samples/OrgServer/Application.Interface.Org/IOrgAppService.cs +++ /dev/null @@ -1,142 +0,0 @@ -using DTO.Core; -using Surging.Core.CPlatform.Ioc; -using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; -using Surging.Core.CPlatform.Support; -using Surging.Core.CPlatform.Support.Attributes; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Application.Interface.Org -{ - [ServiceBundle("api/{Service}")] - public interface IOrgAppService : IServiceKey - { - #region CMD - #region 公司管理 - - /// - /// 注册一个新公司 - /// - /// - /// - [Service(Date = "2018-2-12", Director = "刘旭东", Name = "注册一个新公司")] - Task RegisterCorporation(CorpEditReq req); - - /// - /// 激活一个新公司 - /// 手机短信或者邮箱确认 - /// - /// - /// - [Service(Date = "2018-2-12", Director = "刘旭东", Name = "激活一个新公司")] - Task ActivateCorporation(CommonCMDReq req); - - /// - /// 修改公司信息 - /// - /// - /// - [Service(Date = "2018-2-12", Director = "刘旭东", Name = "修改公司信息")] - Task EditCorporation(CorpEditReq req); - #endregion - - #region 权限管理 - - #endregion - - #endregion - - - #region Query - - #region 公司 - /// - /// 所有公司列表 - /// - /// - /// - [Service(Date = "2018-1-30", Director = "刘旭东", Name = "所有公司列表")] - Task FindCorps(BaseTreeSearchReq req); - #endregion - - #region 部门管理 - - /// - /// 当前用户所在公司全部部门列表 - /// 使用场景:部门树加载显示 - /// - /// - /// 全部部门列表 - //[Command(Strategy = StrategyType.Failover, RequestCacheEnabled = false)] - [Service(Date = "2018-1-30", Director = "刘旭东", Name = "当前用户所在公司全部部门列表")] - Task FindDepartments(BaseTreeSearchReq req); - - /// - /// 添加一个新部门 - /// - /// - /// 操作结果 - [Service(Date = "2018-2-1", Director = "刘旭东", Name = "添加一个新部门")] - Task CreateDepartment(DeptEditReq req); - - /// - /// 修改一个部门 - /// - /// - /// - [Service(Date = "2018-2-1", Director = "刘旭东", Name = "修改一个部门")] - Task ModifyDepartment(DeptEditReq req); - - /// - /// 删除一个部门 - /// - /// - /// - [Service(Date = "2018-2-1", Director = "刘旭东", Name = "删除一个部门")] - Task RemoveDepartment(KeyIdReq req); - - #endregion 部门管理 - - #region 权限管理 - /// - /// 添加一个新角色 - /// - /// - /// - [Service(Date = "2018-2-1", Director = "刘旭东", Name = "添加一个新角色")] - Task CreateRole(RoleEditReq req); - - /// - /// 查询用户的所有权限 - /// - /// - /// - [Service(Date = "2018-2-14", Director = "刘旭东", Name = "查询用户的所有权限")] - Task QueryUserPermission(CommonCMDReq req); - - [Service(Date = "2018-2-14", Director = "刘旭东", Name = "查询公司的所有角色")] - Task FindCorpRoles(CommonCMDReq req); - - #endregion - - #region 员工管理 - /// - /// 添加一个新员工 - /// - /// - /// - [Service(Date = "2018-2-1", Director = "刘旭东", Name = "添加一个新员工")] - Task CreateEmployee(EmployeeEditReq req); - - /// - /// 分页查询员工 - /// - /// - /// - [Service(Date = "2018-2-1", Director = "刘旭东", Name = "分页查询员工")] - Task FindEmployeePageBy(BasePagedRequestDto req); - #endregion - #endregion - } -} diff --git a/samples/OrgServer/Application.Service.Org/Application.Service.Org.csproj b/samples/OrgServer/Application.Service.Org/Application.Service.Org.csproj deleted file mode 100644 index d80fece76..000000000 --- a/samples/OrgServer/Application.Service.Org/Application.Service.Org.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - - - - - - - - - - diff --git a/samples/OrgServer/Application.Service.Org/Query/OrgAppService.cs b/samples/OrgServer/Application.Service.Org/Query/OrgAppService.cs deleted file mode 100644 index b1613de4a..000000000 --- a/samples/OrgServer/Application.Service.Org/Query/OrgAppService.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Application.Interface.Org; -using DTO.Core; -using Surging.Core.Caching; -using Surging.Core.CPlatform.Ioc; -using Surging.Core.ProxyGenerator; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Linq.Expressions; -using Domain.Org.Entity; - -namespace Application.Service.Org -{ - public partial class OrgAppService - { - public Task FindCorps(BaseTreeSearchReq req) - { - BaseTreeResponseDto rsp = new BaseTreeResponseDto(); - rsp.Tree = _queryCorpRepository.Get(a => !a.IsDelete).Select(a => new BaseTreeDto - { - Id = a.CorporationKeyId.ToString(), - Name = a.Name, - PId = Guid.Empty.ToString() - }).ToList(); - - return Task.FromResult(rsp); - } - - public Task FindDepartments(BaseTreeSearchReq req) - { - BaseTreeResponseDto rsp = new BaseTreeResponseDto(); - var rows = _queryOrgRepository.Get(a => !a.IsDelete && a.CorporationKeyId == req.Identify.CorporationKeyId).Select(a => new BaseTreeDto - { - Id = a.CorporationKeyId.ToString(), - Name = a.Name, - PId = a.ParentKeyId.ToString() - }).ToList(); - rsp.Tree = rows; - return Task.FromResult(rsp); - } - - public Task QueryUserPermission(CommonCMDReq req) - { - var rsp = new BaseListResponseDto(); - var rows = _queryEmployeeRepository.FindUserRolePermission(Guid.Parse(req.Identify.Token)); - rsp.Result = new - { - pages = rows.Where(a => a.PermissionType == 1)?.Select(a => new - { - name = a.Name, - no = a.No, - }), - actions = rows.Where(a => a.PermissionType == 2)?.Select(a => new - { - name = a.Name, - no = a.No, - }) - }; - rsp.OperateFlag = true; - return Task.FromResult(rsp); - - } - - - public Task FindCorpRoles(CommonCMDReq req) - { - var rsp = new BaseListResponseDto(); - var rows = _queryCorpRepository.Get(a=>a.CorporationKeyId== req.Identify.CorporationKeyId,a=>a.CorpRoles).FirstOrDefault()?.CorpRoles.ToList(); - rsp.Result = rows?.Select(a=>new { roleName=a.Name,roleId=a.KeyId }).ToList(); - rsp.OperateFlag = true; - return Task.FromResult(rsp); - - } - - public Task FindEmployeePageBy(BasePagedRequestDto req) - { - var rsp = new BaseListResponseDto(); - var rows = _queryEmployeeRepository.GetByPagination(a => !a.IsDelete&&a.CorporationKeyId==req.Identify.CorporationKeyId, req.PageSize, req.PageIndex,null).ToList(); - rsp.Result = rows; - rsp.OperateFlag = true; - return Task.FromResult(rsp); - } - } -} diff --git a/samples/OrgServer/Application.Service.Org/UseCases/OrgAppService.cs b/samples/OrgServer/Application.Service.Org/UseCases/OrgAppService.cs deleted file mode 100644 index 191bbc943..000000000 --- a/samples/OrgServer/Application.Service.Org/UseCases/OrgAppService.cs +++ /dev/null @@ -1,280 +0,0 @@ -using App.Core; -using Application.Interface.Org; -using Domain.Org.Entity; -using DTO.Core; -using Repository.EF.Core; -using Surging.Core.Caching; -using Surging.Core.CPlatform.Ioc; -using Surging.Core.ProxyGenerator; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Threading.Tasks; -using Domain.Org.Aggregate; -using Application.Interface.Org.EVENT; -using Repository.Org; - -namespace Application.Service.Org -{ - [ModuleName("Org")] - public partial class OrgAppService : BaseAppService, IOrgAppService - { - private readonly OrgRepository _repository; - private readonly CorpQueryRepository _queryCorpRepository; - private readonly OrgQueryRepository _queryOrgRepository; - private readonly EmployeeQueryRepository _queryEmployeeRepository; - - // private ICacheProvider _cacheProvider; - public OrgAppService(OrgRepository repository, OrgQueryRepository queryOrgRepository, CorpQueryRepository queryCorpRepository, EmployeeQueryRepository queryEmployeeRepository) - // : base(repository)//, queryOnlyRepository) - { - _repository = repository; - _queryCorpRepository = queryCorpRepository; - _queryOrgRepository = queryOrgRepository; - _queryEmployeeRepository = queryEmployeeRepository; - } - #region 公司 - - public Task RegisterCorporation(CorpEditReq req) - { - //是否已经被注册? - var existCorp = _queryCorpRepository.Exist(a => !a.IsDelete && a.Name == req.CorpName); - if (!existCorp) - { - var aCorp = new Corporation - { - CorporationKeyId = Guid.NewGuid(), - Name = req.CorpName, - No = req.CorpName, - Version = 1, - CreateTime = DateTime.Now, - UpdateTime = DateTime.Now, - IsDelete = false - }; - _repository.Add(aCorp); - _repository.Commit(); - return Task.FromResult(new OperateResultRsp - { - OperateFlag = true, - OperateResult = "注册成功" - }); - } - else - { - return Task.FromResult(new OperateResultRsp - { - OperateFlag = false, - OperateResult = "该企业已经被注册" - }); - } - - } - - public Task ActivateCorporation(CommonCMDReq req) - { - var rsp = new OperateResultRsp - { - OperateFlag = false, - OperateResult = "参数错误" - }; - try - { - if (!string.IsNullOrEmpty(req.CommonCMD)) - { - var corp = _queryCorpRepository.Get(a => a.CorporationKeyId == req.Identify.CorporationKeyId).FirstOrDefault(); - corp.IsDelete = false; - var empId = corp.Activate(); - - _repository.Commit(); - rsp.OperateFlag = true; - rsp.OperateResult = "激活成功"; - Publish(new CorporationActivatedEvent() - { - CorpId = req.Identify.CorporationKeyId, - Email = req.CommonCMD, - EmpId = empId - }); - } - } - catch (Exception ex) - { - string msg = ex.Message; - } - return Task.FromResult(rsp); - - // return rsp; - } - - public Task EditCorporation(CorpEditReq req) - { - throw new NotImplementedException(); - } - #endregion - - #region 部门 - - public Task CreateDepartment(DeptEditReq req) - { - if (req.CorporationKeyId != Guid.Empty) - { - var corp = _repository.FindBy(req.CorporationKeyId); - if (corp != null) - { - corp.Departments.Add(new Department() - { - Name = req.DepartmentName, - No = req.DepartmentNo, - DepartmentType = DepartmentCategory.Bizz, - ParentKeyId = req.ParentDeptKeyId.GetValueOrDefault(), - Version = 1, - CreateTime = DateTime.Now, - UpdateTime = DateTime.Now, - IsDelete = false - }); - } - else - { - - } - } - else - { - return Task.FromResult(new OperateResultRsp - { - OperateFlag = false, - OperateResult = string.Empty - }); - } - _repository.Commit(); - return Task.FromResult(new OperateResultRsp - { - OperateFlag = true, - OperateResult = string.Empty - }); - } - - - - public Task ModifyDepartment(DeptEditReq req) - { - var corp = _repository.FindBy(req.CorporationKeyId); - if (corp != null) - { - var dept = corp.Departments.FirstOrDefault(c => c.KeyId == req.DepartmentKeyId.Value); - if (dept != null) - { - dept.Name = req.DepartmentName; - dept.No = req.DepartmentNo; - } - } - _repository.Commit(); - return Task.FromResult(new OperateResultRsp - { - OperateFlag = true, - OperateResult = string.Empty - }); - - } - - - - public Task RemoveDepartment(KeyIdReq req) - { - var corporation = _repository.FindBy(req.Identify.CorporationKeyId); - var dept = corporation.Departments.FirstOrDefault(c => c.KeyId == req.KeyId); - if (dept != null) - { - dept.IsDelete = true; - } - _repository.Commit(); - return Task.FromResult(new OperateResultRsp - { - OperateFlag = true, - OperateResult = string.Empty - }); - } - - - #endregion - - #region 角色 - public Task CreateRole(RoleEditReq req) - { - OperateResultRsp rsp = new OperateResultRsp(); - var corporation = _repository.FindBy(req.Identify.CorporationKeyId); - if (corporation != null) - { - if (!corporation.CorpRoles.Exists(a => a.Name == req.RoleName.Trim())) - { - var corpRole = new CorpRole - { - Name = req.RoleName, - CorporationKeyId = req.Identify.CorporationKeyId, - - }; - corpRole.SetEditer(null); - corpRole.KeyId = Guid.NewGuid(); - corporation.CorpRoles.Add(corpRole); - _repository.Commit(); - rsp.OperateFlag = true; - } - else - { - rsp.OperateFlag = false; - rsp.FlagErrorMsg = "角色名字已经存在"; - } - } - else - { - rsp.OperateFlag = false; - rsp.FlagErrorMsg = "当前公司编号错误"; - } - return Task.FromResult(rsp); - } - - - #endregion - - #region 员工 - public Task CreateEmployee(EmployeeEditReq req) - { - OperateResultRsp rsp = new OperateResultRsp(); - var corporation = _repository.FindBy(req.Identify.CorporationKeyId); - if (corporation != null) - { - var dept = corporation.Departments.FirstOrDefault(a => a.KeyId == req.DeptKeyId); - if (dept != null) - { - var emp = new Employee - { - Name = req.Name, - CorporationKeyId = req.Identify.CorporationKeyId, - DepartmentKeyId=req.DeptKeyId, - RoleKeyId = req.RoleKeyId, - RoleName = req.RoleName - - }; - emp.SetEditer(null); - emp.KeyId = Guid.NewGuid(); - dept.Employees.Add(emp); - _repository.Commit(); - rsp.OperateFlag = true; - } - else - { - rsp.OperateFlag = false; - rsp.FlagErrorMsg = "角色名字已经存在"; - } - } - else - { - rsp.OperateFlag = false; - rsp.FlagErrorMsg = "当前公司编号错误"; - } - return Task.FromResult(rsp); - } - - - #endregion - } -} diff --git a/samples/OrgServer/Domain/Aggregate/Corporation.cs b/samples/OrgServer/Domain/Aggregate/Corporation.cs deleted file mode 100644 index 95cc29c56..000000000 --- a/samples/OrgServer/Domain/Aggregate/Corporation.cs +++ /dev/null @@ -1,79 +0,0 @@ -using DDD.Core; -using Domain.Org.Entity; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Org.Aggregate -{ - [Table("Org_Corporations")] - public class Corporation : IAggregate - { - /// - /// 这个字段没有用,禁止使用 - /// - [NotMapped] - public override Guid KeyId { get => base.KeyId; set => base.KeyId = value; } - - [Key] - public override Guid CorporationKeyId { get; set; } - - public virtual List Departments { get; set; } - public virtual List CorpRoles { get; set; } - - /// - /// 注册后激活,初始化管理员数据 - /// - public string Activate() - { - //是否已经存在虚拟部门 - var dept = this.Departments.Find(a => !a.IsDelete && a.Name == "" && a.ParentKeyId == CorporationKeyId); - if(dept==null) - { - //添加虚拟部门 - dept = new Department() - { - Name=string.Empty, - CorporationKeyId=CorporationKeyId, - KeyId=Guid.NewGuid(), - CreateTime=DateTime.Now, - CreateUserKeyId=Guid.Empty, - No="000000", - ParentKeyId=CorporationKeyId, - UpdateTime=DateTime.Now, - UpdateUserKeyId=Guid.Empty, - Address=string.Empty, - NameSpell=string.Empty, - Telephone=string.Empty, - DepartmentType= DepartmentCategory.Sysinternal, - Employees=new List (), - IsDelete=false, - Version=1 - - }; - //添加管理员对应的员工 - var empid = Guid.NewGuid(); - dept.Employees.Add(new Employee() - { - Name="超级管理员", - No = "SuperManger", - KeyId=empid, - CorporationKeyId=CorporationKeyId, - CreateTime=DateTime.Now, - CreateUserKeyId=Guid.Empty, - DepartmentKeyId= dept.KeyId, - UpdateTime=DateTime.Now, - UpdateUserKeyId=Guid.Empty, - Version=1 - }); - return empid.ToString(); - } - else - { - return string.Empty; - } - } - } -} diff --git a/samples/OrgServer/Domain/Domain.Org.csproj b/samples/OrgServer/Domain/Domain.Org.csproj deleted file mode 100644 index 3ca3b9dd8..000000000 --- a/samples/OrgServer/Domain/Domain.Org.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/OrgServer/Domain/DomainEvents/EventHandling/InquiryEditedHandler.cs b/samples/OrgServer/Domain/DomainEvents/EventHandling/InquiryEditedHandler.cs deleted file mode 100644 index 8f8b1e201..000000000 --- a/samples/OrgServer/Domain/DomainEvents/EventHandling/InquiryEditedHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Surging.Core.CPlatform.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace Domain.DomainEvents.Inquiry -{ - public class InquiryEditedHandler : IIntegrationEventHandler - { - public async Task Handle(InquiryEditedEvent @event) - { - - await Task.FromResult("InquiryEditedEvent更改名字》"+@event.CustomerName+"请进行下一步操作"); - } - } -} diff --git a/samples/OrgServer/Domain/DomainEvents/PublishEvent/InquiryEditedEvent.cs b/samples/OrgServer/Domain/DomainEvents/PublishEvent/InquiryEditedEvent.cs deleted file mode 100644 index 3807072ae..000000000 --- a/samples/OrgServer/Domain/DomainEvents/PublishEvent/InquiryEditedEvent.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Surging.Core.CPlatform.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Domain.DomainEvents.Inquiry -{ - public class InquiryEditedEvent: IntegrationEvent - { - public Guid CustomerKeyId { get; set; } - public string CustomerName { get; set; } - - } -} diff --git a/samples/OrgServer/Domain/Entity/CorpRole.cs b/samples/OrgServer/Domain/Entity/CorpRole.cs deleted file mode 100644 index eb58fd86a..000000000 --- a/samples/OrgServer/Domain/Entity/CorpRole.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DDD.Core; -using Domain.Org.ValueObject; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Org.Entity -{ - /// - /// 公司下的角色 - /// - [Table("Org_CorpRoles")] - public class CorpRole: BaseEntity - { - - public virtual List RolePermissions { get; set; } - - } -} diff --git a/samples/OrgServer/Domain/Entity/Department.cs b/samples/OrgServer/Domain/Entity/Department.cs deleted file mode 100644 index f10a8738a..000000000 --- a/samples/OrgServer/Domain/Entity/Department.cs +++ /dev/null @@ -1,40 +0,0 @@ -using DDD.Core; -using Domain.Org.Aggregate; -using Domain.Org.Entity; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Org.Entity -{ - [Table("Org_Departments")] - public class Department : BaseEntity - { - public Guid ParentKeyId { get; set; } - - public string NameSpell { get; set; } - - public string Telephone { get; set; } - public string Address { get; set; } - public DepartmentCategory DepartmentType { get; set; } - - - [ForeignKey("CorporationKeyId")] - public Corporation OwnCorporation { get; set; } - public virtual List Employees { get; set; } - } - - public enum DepartmentCategory - { - /// - /// 系统为企业内置的虚拟部门 - /// - Sysinternal=0, - /// - /// 公司自己添加维护的部门 - /// - Bizz =1 - } -} diff --git a/samples/OrgServer/Domain/Entity/Employee.cs b/samples/OrgServer/Domain/Entity/Employee.cs deleted file mode 100644 index bf28259cb..000000000 --- a/samples/OrgServer/Domain/Entity/Employee.cs +++ /dev/null @@ -1,30 +0,0 @@ -using DDD.Core; -using Domain.Org.ValueObject; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Org.Entity -{ - [Table("Org_Employees")] - public class Employee : BaseEntity - { - public string NameSpell { get; set; } - public string Mobile { get; set; } - public string WxNo { get; set; } - public string Email { get; set; } - public string PhotoPath { get; set; } - public string Sex { get; set; } - public string Signature { get; set; } - - public Guid DepartmentKeyId { get; set; } - [ForeignKey("DepartmentKeyId")] - public Department OwnDepartment { get; set; } - /// - /// 员工拥有的角色 - /// - public Guid RoleKeyId{ get;set;} - public string RoleName{ get;set; } - } -} diff --git a/samples/OrgServer/Domain/ValueObject/EmployeeRole.cs b/samples/OrgServer/Domain/ValueObject/EmployeeRole.cs deleted file mode 100644 index 64cd5616a..000000000 --- a/samples/OrgServer/Domain/ValueObject/EmployeeRole.cs +++ /dev/null @@ -1,15 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Org.ValueObject -{ - public class EmployeeRole: BaseValueObject - { - [ForeignKey("Employee")] - public Guid EmployeeKeyId { get; set; } - - } -} diff --git a/samples/OrgServer/Domain/ValueObject/RolePermission.cs b/samples/OrgServer/Domain/ValueObject/RolePermission.cs deleted file mode 100644 index 7abe11323..000000000 --- a/samples/OrgServer/Domain/ValueObject/RolePermission.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DDD.Core; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace Domain.Org.ValueObject -{ - /// - /// 角色下的权限 - /// - [Table("Org_Role_Permissions")] - public class RolePermission : BaseValueObject - { - /// - /// 服务ID(模块) - /// - public Guid SubDomainKeyId { get; set; } - /// - /// 具体的权限,页面和动作 - /// - public Guid SubDomainPermissionKeyId { get; set; } - - public int PermissionType { get; set; } - - - - [ForeignKey("CorpRole")] - public Guid CorpRoleKeyId { get; set; } - - } -} diff --git a/samples/OrgServer/HostService/Configs/log4net.config b/samples/OrgServer/HostService/Configs/log4net.config deleted file mode 100644 index 42fd16880..000000000 --- a/samples/OrgServer/HostService/Configs/log4net.config +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/OrgServer/HostService/HostService.csproj b/samples/OrgServer/HostService/HostService.csproj deleted file mode 100644 index 6af0a37d2..000000000 --- a/samples/OrgServer/HostService/HostService.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - Exe - netcoreapp2.0 - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - diff --git a/samples/OrgServer/HostService/Program.cs b/samples/OrgServer/HostService/Program.cs deleted file mode 100644 index 5133ac408..000000000 --- a/samples/OrgServer/HostService/Program.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Autofac; -using Surging.Core.Codec.MessagePack; -using Surging.Core.Consul; -using Surging.Core.Consul.Configurations; -using Surging.Core.CPlatform; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.DotNetty; -using Surging.Core.EventBusRabbitMQ; -using Surging.Core.ServiceHosting; -using Surging.Core.ServiceHosting.Internal.Implementation; -using System; -using System.Text; -using Surging.Core.Log4net; -using Surging.Core.ProxyGenerator; - -namespace Centa.HostService.Org -{ - public class Program - { - static void Main(string[] args) - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - var host = new ServiceHostBuilder() - //.RegisterServices(provider => - //{ - // //这里写自己的注册 - //}) - .RegisterServices(builder => - { - builder.AddMicroService(option => - { - option.AddServiceRuntime(); - option.AddRelateService(); - option.UseConsulManager(new ConfigInfo("127.0.0.1:8500")); - option.UseDotNettyTransport(); - option.UseRabbitMQTransport(); - option.AddRabbitMQAdapt(); - //option.UseMessagePackCodec(); - option.UseJsonCodec(); - builder.Register(p => new CPlatformContainer(ServiceLocator.Current)); - }); - }) - .SubscribeAt() - .UseLog4net("Configs/log4net.config") - .UseServer(options => - { - options.Ip = "127.0.0.1"; - options.Port = 10242; - options.Token = "True"; - options.ExecutionTimeoutInMilliseconds = 30000; - options.MaxConcurrentRequests = 200; - }) - .UseProxy() - .UseStartup() - .Build(); - - using (host.Run()) - { - Console.Title = "组织管理"; - Console.WriteLine($"组织管理——服务端启动成功,{DateTime.Now}。"); - Console.ReadLine(); - } - } - } -} diff --git a/samples/OrgServer/HostService/Startup.cs b/samples/OrgServer/HostService/Startup.cs deleted file mode 100644 index 3f488ae1a..000000000 --- a/samples/OrgServer/HostService/Startup.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Config.Core.Extensions; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Surging.Core.CPlatform.Utilities; -using Surging.Core.EventBusRabbitMQ.Configurations; -using System; - -namespace Centa.HostService.Org -{ - public class Startup - { - public Startup() - { - var config = new ConfigurationBuilder() - .SetBasePath(AppContext.BaseDirectory); - ConfigureEventBus(config); - ConfigureCache(config); - ConfigureDB(config); - - } - - public IContainer ConfigureServices(ContainerBuilder builder) - { - var services = new ServiceCollection(); - ConfigureLogging(services); - builder.Populate(services); - ServiceLocator.Current = builder.Build(); - return ServiceLocator.Current; - } - - public void Configure(IContainer app) - { - app.Resolve().AddConsole((c, l) => (int)l >= 3); - } - - #region 私有方法 - /// - /// 配置日志服务 - /// - /// - private void ConfigureLogging(IServiceCollection services) - { - services.AddLogging(); - } - - private static void ConfigureEventBus(IConfigurationBuilder build) - { - build - .AddEventBusFile("eventBusSettings.json", optional: false); - } - - /// - /// 配置缓存服务 - /// - private void ConfigureCache(IConfigurationBuilder build) - { - // build.AddCacheFile("cacheSettings.json", optional: false); - } - - private void ConfigureDB(IConfigurationBuilder build) - { - build.AddDBFile("dbSettings.json", optional: false); - } - #endregion - - } -} diff --git a/samples/OrgServer/HostService/cacheSettings.json b/samples/OrgServer/HostService/cacheSettings.json deleted file mode 100644 index ab9c7e43d..000000000 --- a/samples/OrgServer/HostService/cacheSettings.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "CachingSettings": [ - { - "Id": "ddlCache", - "Class": "Surging.Core.Caching.RedisCache.RedisContext,Surging.Core.Caching", - "Properties": [ - { - "Name": "appRuleFile", - "Ref": "rule" - }, - { - "Name": "dataContextPool", - "Ref": "ddls_sample", - "Maps": [ - { - "Name": "Redis", - "Properties": [ - { - "value": "127.0.0.1:6379::1" - } - ] - }, - { - "Name": "MemoryCache" - } - ] - }, - { - "Name": "defaultExpireTime", - "value": "120" - }, - { - "Name": "connectTimeout", - "Value": "120" - }, - { - "Name": "minSize", - "Value": "1" - }, - { - "Name": "maxSize", - "Value": "10" - } - ] - } - ] -} diff --git a/samples/OrgServer/HostService/dbSettings.json b/samples/OrgServer/HostService/dbSettings.json deleted file mode 100644 index 35262d07c..000000000 --- a/samples/OrgServer/HostService/dbSettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionString": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Web_A2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", - "ModelAssemblyName": "Domain.Org" -} - diff --git a/samples/OrgServer/HostService/eventBusSettings.json b/samples/OrgServer/HostService/eventBusSettings.json deleted file mode 100644 index d5d4487b7..000000000 --- a/samples/OrgServer/HostService/eventBusSettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "EventBusConnection": "localhost", - "EventBusUserName": "guest", - "EventBusPassword": "guest" -} - diff --git a/samples/OrgServer/Repository.Org/OrgRepository.cs b/samples/OrgServer/Repository.Org/OrgRepository.cs deleted file mode 100644 index e30e44e3e..000000000 --- a/samples/OrgServer/Repository.Org/OrgRepository.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Repository.EF.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Domain.Org.Entity; -using Domain.Org.ValueObject; -using System.Data.SqlClient; -using System.Data; -using Domain.Org.Aggregate; - -namespace Repository.Org -{ - public class OrgRepository : BaseImpRepository - { - public override Corporation FindBy(Guid key) - { - return _set.Include(a => a.Departments).ThenInclude(a => a.Employees) - .Include(a=>a.CorpRoles) - .SingleOrDefault(a => a.CorporationKeyId == key); - } - } - - public class CorpQueryRepository : BaseImpQueryOnlyRepository - { - - } - - public class OrgQueryRepository : BaseImpQueryOnlyRepository - { - } - - public class EmployeeQueryRepository : BaseImpQueryOnlyRepository - { - - public List FindUserRolePermission(Guid empId) - { - return _dbContext.Set().AsNoTracking().Where(a=>a.KeyId==empId).Join(_dbContext.Set().AsNoTracking(), a => a.RoleKeyId, b => b.CorpRoleKeyId,(a,b)=>b).ToList(); - } - } - - public class RolePermissionQueryRepository : BaseImpQueryOnlyRepository - { - } -} diff --git a/samples/OrgServer/Repository.Org/Repository.Org.csproj b/samples/OrgServer/Repository.Org/Repository.Org.csproj deleted file mode 100644 index 3ed970561..000000000 --- a/samples/OrgServer/Repository.Org/Repository.Org.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netcoreapp2.0 - - - - ..\HostService\bin\Debug - - - - - - - - diff --git a/samples/pack/Surging.Core.ApiGateWay.dll b/samples/pack/Surging.Core.ApiGateWay.dll deleted file mode 100644 index 8d68e8355..000000000 Binary files a/samples/pack/Surging.Core.ApiGateWay.dll and /dev/null differ diff --git a/sh.exe.stackdump b/sh.exe.stackdump index ddee04880..14051f161 100644 --- a/sh.exe.stackdump +++ b/sh.exe.stackdump @@ -1,11 +1,11 @@ Stack trace: Frame Function Args -001802FEFA0 0018005D14E (0018022B7F0, 0018021DC39, 001802FEFA0, 000FFFFB9F0) -001802FEFA0 00180046609 (00000000002, 00000000003, 00000000002, 000C0000000) -001802FEFA0 00180046642 (00000000002, 001802FF2B0, 001802FEFA0, 00000000008) -001802FEFA0 00180057602 (00000000000, 000FFFFCC35, 000FFFFCC53, 0018021C490) -000FFFFCCB0 001800576B0 (645C655C725C635C, 695C745C6E5C655C, 6D5C2D5C6C5C615C, 675C615C6E5C615C) -000FFFFCCB0 00180046DA5 (00000000000, 00000000000, 00000000000, 00000000000) -00000000000 00180045873 (00000000000, 00000000000, 00000000000, 00000000000) -000FFFFFFF0 00180045924 (00000000000, 00000000000, 00000000000, 00000000000) +00000010002 0018005E0DE (0018023E7F0, 00180230C39, 00000010002, 000FFFFBA00) +00000010002 001800468F9 (00000000002, 00180320420, 00000000002, 00180320420) +00000010002 00180046932 (00000000002, 00180320730, 00000010002, 00000000008) +00000010002 0018005799C (00000000000, 00180230F2F, 00180047D9E, 635C655C785C655C) +000FFFFCCD0 00180057A40 (745C685C275C205C, 3A5C735C705C745C, 695C675C2F5C2F5C, 625C755C685C745C) +000FFFFCCD0 00180047081 (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 00180045A03 (00000000000, 00000000000, 00000000000, 00000000000) +000FFFFFFF0 00180045AB4 (00000000000, 00000000000, 00000000000, 00000000000) End of stack trace diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 000000000..99dce6d7d --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,7 @@ +[*.cs] + +# CS8601: 引用类型赋值可能为 null。 +dotnet_diagnostic.CS8601.severity = none + +# CS8618: 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 +dotnet_diagnostic.CS8618.severity = none diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsQueryDecoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsQueryDecoder.cs new file mode 100644 index 000000000..d6db25035 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsQueryDecoder.cs @@ -0,0 +1,86 @@ +using DotNetty.Transport.Channels.Sockets; +using System; +using System.Collections.Generic; +using DotNetty.Transport.Channels; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; + +namespace DotNetty.Codecs.DNS +{ + public class DatagramDnsQueryDecoder : MessageToMessageDecoder + { + private readonly IDnsRecordDecoder recordDecoder; + + public DatagramDnsQueryDecoder() : this(new DefaultDnsRecordDecoder()) { } + + public DatagramDnsQueryDecoder(IDnsRecordDecoder recordDecoder) + { + this.recordDecoder = recordDecoder ?? throw new ArgumentNullException(nameof(recordDecoder)); + } + + protected override void Decode(IChannelHandlerContext context, DatagramPacket message, List output) + { + IByteBuffer buffer = message.Content; + IDnsQuery query = NewQuery(message, buffer); + bool success = false; + + try + { + int questionCount = buffer.ReadUnsignedShort(); + int answerCount = buffer.ReadUnsignedShort(); + int authorityRecordCount = buffer.ReadUnsignedShort(); + int additionalRecordCount = buffer.ReadUnsignedShort(); + + DecodeQuestions(query, buffer, questionCount); + DecodeRecords(query, DnsSection.ANSWER, buffer, answerCount); + DecodeRecords(query, DnsSection.AUTHORITY, buffer, authorityRecordCount); + DecodeRecords(query, DnsSection.ADDITIONAL, buffer, additionalRecordCount); + + output.Add(query); + success = true; + } + finally + { + if (!success) + query.Release(); + } + } + + private static IDnsQuery NewQuery(DatagramPacket packet, IByteBuffer buffer) + { + int id = buffer.ReadUnsignedShort(); + int flags = buffer.ReadUnsignedShort(); + if (flags >> 15 == 1) + throw new CorruptedFrameException("not a query"); + + IDnsQuery query = new DatagramDnsQuery( + packet.Sender, packet.Recipient, id, + DnsOpCode.From((byte)(flags >> 11 & 0xf))); + + query.IsRecursionDesired = (flags >> 8 & 1) == 1; + query.Z = flags >> 4 & 0x7; + return query; + } + + private void DecodeQuestions(IDnsQuery query, IByteBuffer buffer, int questionCount) + { + for (int i = questionCount; i > 0; i--) + { + query.AddRecord(DnsSection.QUESTION, recordDecoder.DecodeQuestion(buffer)); + } + } + + private void DecodeRecords(IDnsQuery query, DnsSection section, IByteBuffer buffer, int count) + { + for (int i = count; i > 0; i--) + { + IDnsRecord r = recordDecoder.DecodeRecord(buffer); + if (r == null) + break; + + query.AddRecord(section, r); + } + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsQueryEncoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsQueryEncoder.cs new file mode 100644 index 000000000..4280b8bed --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsQueryEncoder.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using DotNetty.Transport.Channels; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; +using System.Net; +using DotNetty.Transport.Channels.Sockets; + +namespace DotNetty.Codecs.DNS +{ + public class DatagramDnsQueryEncoder : MessageToMessageEncoder> + { + private readonly IDnsRecordEncoder recordEncoder; + + public DatagramDnsQueryEncoder() : this(new DefaultDnsRecordEncoder()) { } + + public DatagramDnsQueryEncoder(IDnsRecordEncoder recordEncoder) + { + this.recordEncoder = recordEncoder ?? throw new ArgumentNullException(nameof(recordEncoder)); + } + + protected override void Encode(IChannelHandlerContext context, IAddressedEnvelope message, List output) + { + EndPoint recipient = message.Recipient; + IDnsQuery query = message.Content; + IByteBuffer buffer = AllocateBuffer(context, message); + bool success = false; + + try + { + EncodeHeader(query, buffer); + EncodeQuestions(query, buffer); + EncodeRecords(query, DnsSection.ADDITIONAL, buffer); + success = true; + } + finally + { + if (!success) + buffer.Release(); + } + + output.Add(new DatagramPacket(buffer, recipient, null)); + } + + private IByteBuffer AllocateBuffer(IChannelHandlerContext ctx, + IAddressedEnvelope message) => ctx.Allocator.Buffer(1024); + + private void EncodeHeader(IDnsQuery query, IByteBuffer buffer) + { + buffer.WriteShort(query.Id); + int flags = 0; + flags |= (query.OpCode.ByteValue & 0xFF) << 14; + if (query.IsRecursionDesired) + flags |= 1 << 8; + + buffer.WriteShort(flags); + buffer.WriteShort(query.Count(DnsSection.QUESTION)); + buffer.WriteShort(0); + buffer.WriteShort(0); + buffer.WriteShort(query.Count(DnsSection.ADDITIONAL)); + } + + private void EncodeQuestions(IDnsQuery query, IByteBuffer buffer) + { + int count = query.Count(DnsSection.QUESTION); + for (int i = 0; i < count; i++) + { + recordEncoder.EncodeQuestion(query.GetRecord(DnsSection.QUESTION, i), buffer); + } + } + + private void EncodeRecords(IDnsQuery query, DnsSection section, IByteBuffer buffer) + { + int count = query.Count(section); + for (int i = 0; i < count; i++) + { + recordEncoder.EncodeRecord(query.GetRecord(section, i), buffer); + } + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsResponseDecoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsResponseDecoder.cs new file mode 100644 index 000000000..c39c48da0 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsResponseDecoder.cs @@ -0,0 +1,85 @@ +using DotNetty.Transport.Channels.Sockets; +using System; +using System.Collections.Generic; +using DotNetty.Transport.Channels; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; + +namespace DotNetty.Codecs.DNS +{ + public class DatagramDnsResponseDecoder : MessageToMessageDecoder + { + private readonly IDnsRecordDecoder recordDecoder; + + public DatagramDnsResponseDecoder() : this(new DefaultDnsRecordDecoder()) { } + + public DatagramDnsResponseDecoder(IDnsRecordDecoder recordDecoder) + { + this.recordDecoder = recordDecoder ?? throw new ArgumentNullException(nameof(recordDecoder)); + } + + protected override void Decode(IChannelHandlerContext context, DatagramPacket message, List output) + { + IByteBuffer buffer = message.Content; + IDnsResponse response = NewResponse(message, buffer); + bool success = false; + + try + { + int questionCount = buffer.ReadUnsignedShort(); + int answerCount = buffer.ReadUnsignedShort(); + int authorityRecordCount = buffer.ReadUnsignedShort(); + int additionalRecordCount = buffer.ReadUnsignedShort(); + + DecodeQuestions(response, buffer, questionCount); + DecodeRecords(response, DnsSection.ANSWER, buffer, answerCount); + DecodeRecords(response, DnsSection.AUTHORITY, buffer, authorityRecordCount); + DecodeRecords(response, DnsSection.ADDITIONAL, buffer, additionalRecordCount); + + output.Add(response); + success = true; + } + finally + { + if (!success) + response.Release(); + } + } + + private static IDnsResponse NewResponse(DatagramPacket packet, IByteBuffer buffer) + { + int id = buffer.ReadUnsignedShort(); + int flags = buffer.ReadUnsignedShort(); + if (flags >> 15 == 0) throw new CorruptedFrameException("not a response"); + + IDnsResponse response = new DatagramDnsResponse( + packet.Sender, + packet.Recipient, + id, + DnsOpCode.From((byte)(flags >> 1 & 0xf)), + DnsResponseCode.From((byte)(flags & 0xf))); + return response; + } + + private void DecodeQuestions(IDnsResponse response, IByteBuffer buffer, int questionCount) + { + for (int i = questionCount - 1; i > 0; i--) + { + response.AddRecord(DnsSection.QUESTION, recordDecoder.DecodeQuestion(buffer)); + } + } + + private void DecodeRecords(IDnsResponse response, DnsSection section, IByteBuffer buffer, int count) + { + for (int i = count - 1; i > 0; i--) + { + IDnsRecord r = recordDecoder.DecodeRecord(buffer); + if (r == null) + break; + + response.AddRecord(section, r); + } + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsResponseEncoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsResponseEncoder.cs new file mode 100644 index 000000000..55473698b --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DatagramDnsResponseEncoder.cs @@ -0,0 +1,100 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Codecs.DNS.Records; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Sockets; +using System; +using System.Collections.Generic; +using System.Net; + +namespace DotNetty.Codecs.DNS +{ + public class DatagramDnsResponseEncoder : MessageToMessageEncoder> + { + private IDnsRecordEncoder recordEncoder; + + public DatagramDnsResponseEncoder() : this(new DefaultDnsRecordEncoder()) { } + + public DatagramDnsResponseEncoder(IDnsRecordEncoder recordEncoder) + { + this.recordEncoder = recordEncoder ?? throw new ArgumentNullException(nameof(recordEncoder)); + } + + protected override void Encode(IChannelHandlerContext context, IAddressedEnvelope message, List output) + { + EndPoint recipient = message.Recipient; + IDnsResponse response = message.Content; + if (response != null) + { + IByteBuffer buffer = AllocateBuffer(context, message); + + bool success = false; + try + { + EncodeHeader(response, buffer); + EncodeQuestions(response, buffer); + EncodeRecords(response, DnsSection.ANSWER, buffer); + EncodeRecords(response, DnsSection.AUTHORITY, buffer); + EncodeRecords(response, DnsSection.ADDITIONAL, buffer); + success = true; + } + finally + { + if (!success) + buffer.Release(); + } + + output.Add(new DatagramPacket(buffer,null, recipient)); + } + } + + protected IByteBuffer AllocateBuffer(IChannelHandlerContext ctx, + IAddressedEnvelope message) => ctx.Allocator.Buffer(1024); + + private static void EncodeHeader(IDnsResponse response, IByteBuffer buffer) + { + buffer.WriteShort(response.Id); + int flags = 32768; + flags |= (response.OpCode.ByteValue & 0xFF) << 11; + if (response.IsAuthoritativeAnswer) + flags |= 1 << 10; + + if (response.IsTruncated) + flags |= 1 << 9; + + if (response.IsRecursionDesired) + flags |= 1 << 8; + + if (response.IsRecursionAvailable) + flags |= 1 << 7; + + flags |= response.Z << 4; + flags |= response.Code.IntValue; + buffer.WriteShort(flags); + buffer.WriteShort(response.Count(DnsSection.QUESTION)); + buffer.WriteShort(response.Count(DnsSection.ANSWER)); + buffer.WriteShort(response.Count(DnsSection.AUTHORITY)); + buffer.WriteShort(response.Count(DnsSection.ADDITIONAL)); + } + + private void EncodeQuestions(IDnsResponse response, IByteBuffer buffer) + { + int count = response.Count(DnsSection.QUESTION); + for (int i = 0; i < count; i++) + { + recordEncoder.EncodeQuestion(response.GetRecord(DnsSection.QUESTION, i), buffer); + } + } + + private void EncodeRecords(IDnsResponse response, DnsSection section, IByteBuffer buffer) + { + int count = response.Count(section); + for (int i = 0; i < count; i++) + { + recordEncoder.EncodeRecord(response.GetRecord(section, i), buffer); + } + } + + + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DefaultDnsRecordDecoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DefaultDnsRecordDecoder.cs new file mode 100644 index 000000000..25158faf4 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DefaultDnsRecordDecoder.cs @@ -0,0 +1,120 @@ +using System.Text; +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; + +namespace DotNetty.Codecs.DNS +{ + public class DefaultDnsRecordDecoder : IDnsRecordDecoder + { + private const string ROOT = "."; + + internal DefaultDnsRecordDecoder() { } + + public IDnsQuestion DecodeQuestion(IByteBuffer inputBuffer) + { + string name = DecodeName(inputBuffer); + DnsRecordType type = DnsRecordType.From(inputBuffer.ReadUnsignedShort()); + var recordClass = (DnsRecordClass)inputBuffer.ReadUnsignedShort(); + return new DefaultDnsQuestion(name, type, recordClass); + } + + public IDnsRecord DecodeRecord(IByteBuffer inputBuffer) + { + int startOffset = inputBuffer.ReaderIndex; + string name = DecodeName(inputBuffer); + + int endOffset = inputBuffer.WriterIndex; + if (endOffset - startOffset < 10) + { + inputBuffer.SetReaderIndex(startOffset); + return null; + } + + DnsRecordType type = DnsRecordType.From(inputBuffer.ReadUnsignedShort()); + var recordClass = (DnsRecordClass)inputBuffer.ReadUnsignedShort(); + long ttl = inputBuffer.ReadUnsignedInt(); + int length = inputBuffer.ReadUnsignedShort(); + int offset = inputBuffer.ReaderIndex; + + if (endOffset - offset < length) + { + inputBuffer.SetReaderIndex(startOffset); + return null; + } + + IDnsRecord record = DecodeRecord(name, type, recordClass, ttl, inputBuffer, offset, length); + inputBuffer.SetReaderIndex(offset + length); + return record; + } + + protected IDnsRecord DecodeRecord(string name, DnsRecordType type, DnsRecordClass dnsClass, long timeToLive, + IByteBuffer inputBuffer, int offset, int length) + { + if (type == DnsRecordType.PTR) + return new DefaultDnsPtrRecord(name, dnsClass, timeToLive, DecodeName(inputBuffer.SetIndex(offset, offset + length))); + + return new DefaultDnsRawRecord(name, type, dnsClass, timeToLive, inputBuffer.SetIndex(offset, offset + length)); + } + + public static string DecodeName(IByteBuffer inputBuffer) + { + int position = -1; + int @checked = 0; + int end = inputBuffer.WriterIndex; + int readable = inputBuffer.ReadableBytes; + + if (readable == 0) + return ROOT; + + var name = new StringBuilder(readable << 1); + while (inputBuffer.IsReadable()) + { + int len = inputBuffer.ReadByte() & 0xff; + bool pointer = (len & 0xc0) == 0xc0; + + if (pointer) + { + if (position == -1) + position = inputBuffer.ReaderIndex + 1; + + if (!inputBuffer.IsReadable()) + throw new CorruptedFrameException("truncated pointer in a name"); + + int next = (len & 0x3f) << 8 | (inputBuffer.ReadByte() & 0xff); + if (next >= end) + throw new CorruptedFrameException("name has an out-of-range pointer"); + + inputBuffer.SetReaderIndex(next); + + @checked += 2; + if (@checked >= end) + throw new CorruptedFrameException("name contains a loop"); + } + else if (len != 0) + { + if (!inputBuffer.IsReadable(len)) + throw new CorruptedFrameException("truncated label in a name"); + + name.Append(inputBuffer.ToString(inputBuffer.ReaderIndex, len, Encoding.UTF8)) + .Append('.'); + inputBuffer.SkipBytes(len); + } + else + { + break; + } + } + + if (position != -1) + inputBuffer.SetReaderIndex(position); + + if (name.Length == 0) + return ROOT; + + if (name[name.Length - 1] != '.') + name.Append('.'); + + return name.ToString(); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DefaultDnsRecordEncoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DefaultDnsRecordEncoder.cs new file mode 100644 index 000000000..4c58502e3 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DefaultDnsRecordEncoder.cs @@ -0,0 +1,171 @@ +using System; +using System.Text; +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; +using System.Net.Sockets; +using DotNetty.Common.Utilities; + +namespace DotNetty.Codecs.DNS +{ + public class DefaultDnsRecordEncoder : IDnsRecordEncoder + { + private const int PREFIX_MASK = sizeof(byte) - 1; + private const string ROOT = "."; + + internal DefaultDnsRecordEncoder() { } + + public void EncodeQuestion(IDnsQuestion question, IByteBuffer output) + { + EncodeName(question.Name, output); + output.WriteShort(question.Type.IntValue); + output.WriteShort((int)question.DnsClass); + } + + public void EncodeRecord(IDnsRecord record, IByteBuffer output) + { + if (record is IDnsQuestion) + { + EncodeQuestion((IDnsQuestion)record, output); + } + else if (record is IDnsPtrRecord) + { + EncodePtrRecord((IDnsPtrRecord)record, output); + } + else if (record is IDnsOptEcsRecord) + { + EncodeOptEcsRecord((IDnsOptEcsRecord)record, output); + } + else if (record is IDnsOptPseudoRecord) + { + EncodeOptPseudoRecord((IDnsOptPseudoRecord)record, output); + } + else if (record is IDnsRawRecord) + { + EncodeRawRecord((IDnsRawRecord)record, output); + } + else + { + throw new UnsupportedMessageTypeException(record.Type.Name); + } + } + + private void EncodeRawRecord(IDnsRawRecord record, IByteBuffer output) + { + EncodeRecordCore(record, output); + + IByteBuffer content = record.Content; + int contentLen = content.ReadableBytes; + output.WriteShort(contentLen); + output.WriteBytes(content, content.ReaderIndex, contentLen); + } + + private void EncodeOptPseudoRecord(IDnsOptPseudoRecord record, IByteBuffer output) + { + EncodeRecordCore(record, output); + output.WriteShort(0); + } + + private void EncodeOptEcsRecord(IDnsOptEcsRecord record, IByteBuffer output) + { + EncodeRecordCore(record, output); + + int sourcePrefixLength = record.SourcePrefixLength; + int scopePrefixLength = record.ScopePrefixLength; + int lowOrderBitsToPreserve = sourcePrefixLength & PREFIX_MASK; + + byte[] bytes = record.Address; + int addressBits = bytes.Length << 3; + if (addressBits < sourcePrefixLength || sourcePrefixLength < 0) + throw new ArgumentException($"{sourcePrefixLength}: {sourcePrefixLength} (expected 0 >= {addressBits})"); + + short addressNumber = (short)(bytes.Length == 4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6); + int payloadLength = CalculateEcsAddressLength(sourcePrefixLength, lowOrderBitsToPreserve); + int fullPayloadLength = 2 + 2 + 2 + 1 + 1 + payloadLength; + + output.WriteShort(fullPayloadLength); + output.WriteShort(8); + output.WriteShort(fullPayloadLength - 4); + output.WriteShort(addressNumber); + output.WriteByte(sourcePrefixLength); + output.WriteByte(scopePrefixLength); + + if (lowOrderBitsToPreserve > 0) + { + int bytesLength = payloadLength - 1; + output.WriteBytes(bytes, 0, bytesLength); + output.WriteByte(PadWithZeros(bytes[bytesLength], lowOrderBitsToPreserve)); + } + else + { + output.WriteBytes(bytes, 0, payloadLength); + } + } + + private static int CalculateEcsAddressLength(int sourcePrefixLength, int lowOrderBitsToPreserve) + { + return sourcePrefixLength.RightUShift(3) + (lowOrderBitsToPreserve != 0 ? 1 : 0); + } + + private void EncodePtrRecord(IDnsPtrRecord record, IByteBuffer output) + { + EncodeRecordCore(record, output); + EncodeName(record.HostName, output); + } + + private void EncodeRecordCore(IDnsRecord record, IByteBuffer output) + { + EncodeName(record.Name, output); + output.WriteShort(record.Type.IntValue); + output.WriteShort((int)record.DnsClass); + output.WriteInt((int)record.TimeToLive); + } + + protected void EncodeName(string name, IByteBuffer buffer) + { + if (ROOT.Equals(name)) + { + buffer.WriteByte(0); + return; + } + + string[] labels = name.Split('.'); + foreach (var label in labels) + { + int labelLen = label.Length; + if (labelLen == 0) + break; + + buffer.WriteByte(labelLen); + buffer.WriteBytes(Encoding.UTF8.GetBytes(label)); //TODO: Use ByteBufferUtil.WriteAscii() when available + } + buffer.WriteByte(0); + } + + private static byte PadWithZeros(byte b, int lowOrderBitsToPreserve) + { + switch (lowOrderBitsToPreserve) + { + case 0: + return 0; + case 1: + return (byte)(0x80 & b); + case 2: + return (byte)(0xC0 & b); + case 3: + return (byte)(0xE0 & b); + case 4: + return (byte)(0xF0 & b); + case 5: + return (byte)(0xF8 & b); + case 6: + return (byte)(0xFC & b); + case 7: + return (byte)(0xFE & b); + case 8: + return b; + default: + throw new ArgumentException($"lowOrderBitsToPreserve: {lowOrderBitsToPreserve}"); + } + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsOpCode.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsOpCode.cs new file mode 100644 index 000000000..0b3943885 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsOpCode.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetty.Codecs.DNS +{ + public class DnsOpCode + { + public static readonly DnsOpCode QUERY = new DnsOpCode(0x00, "QUERY"); + + public static readonly DnsOpCode IQUERY = new DnsOpCode(0x01, "IQUERY"); + + public static readonly DnsOpCode STATUS = new DnsOpCode(0x02, "STATUS"); + + public static readonly DnsOpCode NOTIFY = new DnsOpCode(0x04, "NOTIFY"); + + public static readonly DnsOpCode UPDATE = new DnsOpCode(0x05, "UPDATE"); + + public byte ByteValue { get; } + public string Name { get; } + private string text; + + public static DnsOpCode From(int byteValue) + { + switch (byteValue) + { + case 0x00: + return QUERY; + case 0x01: + return IQUERY; + case 0x02: + return STATUS; + case 0x04: + return NOTIFY; + case 0x05: + return UPDATE; + default: + return new DnsOpCode(byteValue); + } + } + + public DnsOpCode(int byteValue, string name = "UNKNOWN") + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + ByteValue = (byte)byteValue; + } + + public override bool Equals(object obj) + { + if (this == obj) + return true; + + if (!(obj is DnsOpCode)) + return false; + + return ByteValue == ((DnsOpCode)obj).ByteValue; + } + + public override int GetHashCode() + { + return ByteValue; + } + + public override string ToString() + { + string text = this.text; + if (string.IsNullOrWhiteSpace(text)) + this.text = text = $"{Name}({ByteValue & 0xFF})"; + + return text; + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsQueryEncoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsQueryEncoder.cs new file mode 100644 index 000000000..a29f10ec6 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsQueryEncoder.cs @@ -0,0 +1,62 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Codecs.DNS.Records; +using DotNetty.Transport.Channels; +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetty.Codecs.DNS +{ + sealed class DnsQueryEncoder + { + private readonly IDnsRecordEncoder recordEncoder; + + public DnsQueryEncoder() : this(new DefaultDnsRecordEncoder()) { } + + public DnsQueryEncoder(IDnsRecordEncoder recordEncoder) + { + this.recordEncoder = recordEncoder ?? throw new ArgumentNullException(nameof(recordEncoder)); + } + + public void Encode(IDnsQuery query, IByteBuffer buffer) + { + EncodeHeader(query, buffer); + EncodeQuestions(query, buffer); + EncodeRecords(query, DnsSection.ADDITIONAL, buffer); + } + + private void EncodeHeader(IDnsQuery query, IByteBuffer buffer) + { + buffer.WriteShort(query.Id); + int flags = 0; + flags |= (query.OpCode.ByteValue & 0xFF) << 14; + if (query.IsRecursionDesired) + flags |= 1 << 8; + + buffer.WriteShort(flags); + buffer.WriteShort(query.Count(DnsSection.QUESTION)); + buffer.WriteShort(0); + buffer.WriteShort(0); + buffer.WriteShort(query.Count(DnsSection.ADDITIONAL)); + } + + private void EncodeQuestions(IDnsQuery query, IByteBuffer buffer) + { + int count = query.Count(DnsSection.QUESTION); + for (int i = 0; i < count; i++) + { + recordEncoder.EncodeQuestion(query.GetRecord(DnsSection.QUESTION, i), buffer); + } + } + + private void EncodeRecords(IDnsQuery query, DnsSection section, IByteBuffer buffer) + { + int count = query.Count(section); + for (int i = 0; i < count; i++) + { + recordEncoder.EncodeRecord(query.GetRecord(section, i), buffer); + } + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsResponseDecoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsResponseDecoder.cs new file mode 100644 index 000000000..0876d940f --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsResponseDecoder.cs @@ -0,0 +1,90 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Messages; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace DotNetty.Codecs.DNS +{ + public class DnsResponseDecoder where T : EndPoint + { + private readonly IDnsRecordDecoder recordDecoder; + + public DnsResponseDecoder(IDnsRecordDecoder recordDecoder) + { + this.recordDecoder = recordDecoder ?? throw new ArgumentNullException(nameof(recordDecoder)); + } + + public IDnsResponse Decode(T sender, T recipient, IByteBuffer buffer) + { + int id = buffer.ReadUnsignedShort(); + int flags = buffer.ReadUnsignedShort(); + if (flags >> 15 == 0) + { + throw new CorruptedFrameException("not a response"); + } + + IDnsResponse response = NewResponse( + sender, + recipient, + id, + new DnsOpCode((byte)(flags >> 11 & 0xf)), DnsResponseCode.From((flags & 0xf))); + + response.IsRecursionDesired = (flags >> 8 & 1) == 1; + response.IsAuthoritativeAnswer = (flags >> 10 & 1) == 1; + response.IsTruncated = (flags >> 9 & 1) == 1; + response.IsRecursionAvailable = (flags >> 7 & 1) == 1; + response.Z = flags >> 4 & 0x7; + + bool success = false; + try + { + int questionCount = buffer.ReadUnsignedShort(); + int answerCount = buffer.ReadUnsignedShort(); + int authorityRecordCount = buffer.ReadUnsignedShort(); + int additionalRecordCount = buffer.ReadUnsignedShort(); + + DecodeQuestions(response, buffer, questionCount); + DecodeRecords(response, DnsSection.ANSWER, buffer, answerCount); + DecodeRecords(response, DnsSection.AUTHORITY, buffer, authorityRecordCount); + DecodeRecords(response, DnsSection.ADDITIONAL, buffer, additionalRecordCount); + success = true; + return response; + } + finally + { + if (!success) + { + response.Release(); + } + } + } + + protected virtual IDnsResponse NewResponse(T sender, T recipient, int id, + DnsOpCode opCode, DnsResponseCode responseCode) => new DefaultDnsResponse(id, opCode, responseCode); + + + private void DecodeQuestions(IDnsResponse response, IByteBuffer buf, int questionCount) + { + for (int i = questionCount; i > 0; i--) + { + response.AddRecord(DnsSection.QUESTION, recordDecoder.DecodeQuestion(buf)); + } + } + + private void DecodeRecords(IDnsResponse response, DnsSection section, IByteBuffer buf, int count) + { + for (int i = count; i > 0; i--) + { + var r = recordDecoder.DecodeRecord(buf); + if (r == null) + { + break; + } + + response.AddRecord(section, r); + } + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsSection.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsSection.cs new file mode 100644 index 000000000..946502a12 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DnsSection.cs @@ -0,0 +1,10 @@ +namespace DotNetty.Codecs.DNS +{ + public enum DnsSection + { + QUESTION, + ANSWER, + AUTHORITY, + ADDITIONAL + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DotNetty.Codecs.DNS.csproj b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DotNetty.Codecs.DNS.csproj new file mode 100644 index 000000000..ab99a9e77 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/DotNetty.Codecs.DNS.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0;net472 + false + 1.6.1 + + + + + + + + + + + + + + + + + + + diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/IDnsRecordDecoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/IDnsRecordDecoder.cs new file mode 100644 index 000000000..39deb4c62 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/IDnsRecordDecoder.cs @@ -0,0 +1,11 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; + +namespace DotNetty.Codecs.DNS +{ + public interface IDnsRecordDecoder + { + IDnsQuestion DecodeQuestion(IByteBuffer inputBuffer); + IDnsRecord DecodeRecord(IByteBuffer inputBuffer); + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/IDnsRecordEncoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/IDnsRecordEncoder.cs new file mode 100644 index 000000000..e7521ae81 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/IDnsRecordEncoder.cs @@ -0,0 +1,11 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Records; + +namespace DotNetty.Codecs.DNS +{ + public interface IDnsRecordEncoder + { + void EncodeQuestion(IDnsQuestion question, IByteBuffer output); + void EncodeRecord(IDnsRecord record, IByteBuffer output); + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/AbstractDnsMessage.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/AbstractDnsMessage.cs new file mode 100644 index 000000000..ecb245217 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/AbstractDnsMessage.cs @@ -0,0 +1,323 @@ +using DotNetty.Codecs.DNS.Records; +using DotNetty.Common; +using DotNetty.Common.Utilities; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace DotNetty.Codecs.DNS.Messages +{ + public class AbstractDnsMessage : AbstractReferenceCounted, IDnsMessage + { + private static readonly ResourceLeakDetector leakDetector = ResourceLeakDetector.Create(); + private readonly IResourceLeakTracker leak; + private const DnsSection SECTION_QUESTION = DnsSection.QUESTION; + private const int SECTION_COUNT = 4; + private object questions; + private object answers; + private object authorities; + private object additionals; + + public int Id { get; set; } + public DnsOpCode OpCode { get; set; } + public bool IsRecursionDesired { get; set; } + public int Z { get; set; } + + protected AbstractDnsMessage(int id) : this(id, DnsOpCode.QUERY) { } + + protected AbstractDnsMessage(int id, DnsOpCode opcode) + { + Id = id; + OpCode = opcode; + leak = leakDetector.Track(this); + } + + public int Count() + { + int count = 0; + for (int i = 0; i < SECTION_COUNT; i++) + { + count += Count((DnsSection)i); + } + return count; + } + + public int Count(DnsSection section) + { + object records = SectionAt(section); + if (records == null) + return 0; + + if (records is IDnsRecord) + return 1; + + List recordList = (List)records; + return recordList.Count; + } + + private object SectionAt(DnsSection section) + { + switch (section) + { + case DnsSection.QUESTION: + return questions; + case DnsSection.ANSWER: + return answers; + case DnsSection.AUTHORITY: + return authorities; + case DnsSection.ADDITIONAL: + return additionals; + default: + return null; + } + } + + public void AddRecord(DnsSection section, IDnsRecord record) + { + CheckQuestion(section, record); + + object records = SectionAt(section); + if (records == null) + { + SetSection(section, record); + return; + } + + List recordList; + if (records is IDnsRecord) + { + recordList = new List(2); + recordList.Add((IDnsRecord)records); + recordList.Add(record); + SetSection(section, recordList); + return; + } + + recordList = (List)records; + recordList.Add(record); + } + + public void AddRecord(DnsSection section, int index, IDnsRecord record) + { + CheckQuestion(section, record); + + object records = SectionAt(section); + if (records == null) + { + if (index != 0) + throw new IndexOutOfRangeException($"index: {index} (expected: 0)"); + + SetSection(section, record); + return; + } + + List recordList; + if (records is IDnsRecord) + { + if (index == 0) + { + recordList = new List(); + recordList.Add(record); + recordList.Add((IDnsRecord)records); + } + else if (index == 1) + { + recordList = new List(); + recordList.Add((IDnsRecord)records); + recordList.Add(record); + } + else + { + throw new IndexOutOfRangeException($"index: {index} (expected: 0 or 1)"); + } + SetSection(section, recordList); + return; + } + + recordList = (List)records; + recordList[index] = record; + } + + public void Clear(DnsSection section) + { + object recordOrList = SectionAt(section); + SetSection(section, null); + + if (recordOrList is IReferenceCounted) + { + ((IReferenceCounted)recordOrList).Release(); + } + else if (recordOrList is IList) + { + List list = (List)recordOrList; + if (list.Count == 0) + { + foreach (var r in list) + { + ReferenceCountUtil.Release(r); + } + } + } + } + + public void Clear() + { + for (int i = 0; i < SECTION_COUNT; i++) + { + Clear((DnsSection)i); + } + } + + public TRecord GetRecord(DnsSection section) where TRecord : IDnsRecord + { + object records = SectionAt(section); + if (records == null) + return default(TRecord); + + if (records is IDnsRecord) + return (TRecord)records; + + List recordList = (List)records; + if (recordList.Count == 0) + return default(TRecord); + + return (TRecord)recordList[0]; + } + + public TRecord GetRecord(DnsSection section, int index) where TRecord : IDnsRecord + { + object records = SectionAt(section); + if (records == null) + throw new IndexOutOfRangeException($"index: {index} (expected: none)"); + + if (records is IDnsRecord) + { + if (index == 0) + return (TRecord)records; + + throw new IndexOutOfRangeException($"index: {index} (expected: 0)"); + } + + List recordList = (List)records; + return (TRecord)recordList[index]; + } + + public void RemoveRecord(DnsSection section, int index) + { + object records = SectionAt(section); + if (records == null) + throw new IndexOutOfRangeException($"index: {index} (expected: none)"); + + if (records is IDnsRecord) + { + if (index != 0) + throw new IndexOutOfRangeException($"index: {index} (expected: 0)"); + + SetSection(section, null); + } + + List recordList = (List)records; + recordList.RemoveAt(index); + } + + public void SetRecord(DnsSection section, IDnsRecord record) + { + Clear(section); + SetSection(section, record); + } + + public void SetRecord(DnsSection section, int index, IDnsRecord record) + { + CheckQuestion(section, record); + + object records = SectionAt(section); + if (records == null) + throw new IndexOutOfRangeException($"index: {index} (expected: none)"); + + if (records is IDnsRecord) + { + if (index == 0) + { + SetSection(section, record); + } + else + { + throw new IndexOutOfRangeException($"index: {index} (expected: 0)"); + } + } + + List recordList = (List)records; + recordList[index] = record; + } + + private void SetSection(DnsSection section, object value) + { + switch (section) + { + case DnsSection.QUESTION: + questions = value; + break; + case DnsSection.ANSWER: + answers = value; + break; + case DnsSection.AUTHORITY: + authorities = value; + break; + case DnsSection.ADDITIONAL: + additionals = value; + break; + } + } + + private static void CheckQuestion(DnsSection section, IDnsRecord record) + { + if (section == SECTION_QUESTION && + record != null && + !(record is IDnsQuestion)) + throw new ArgumentException($"record: {record} (expected: DnsQuestion)"); + } + + public override IReferenceCounted Touch(object hint) + { + if (leak != null) + leak.Record(hint); + + return this; + } + + protected override void Deallocate() + { + Clear(); + if (leak != null) + leak.Close(this); + } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + if (!(obj is IDnsMessage)) return false; + + IDnsMessage that = (IDnsMessage)obj; + if (Id != that.Id) + return false; + + if (this is IDnsQuestion) + { + if (!(that is IDnsQuestion)) + return false; + } + else if (that is IDnsQuestion) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + return Id * 31 + (this is IDnsQuestion ? 0 : 1); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DatagramDnsQuery.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DatagramDnsQuery.cs new file mode 100644 index 000000000..ad5c3d9c8 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DatagramDnsQuery.cs @@ -0,0 +1,73 @@ +using DotNetty.Transport.Channels; +using System; +using System.Net; + +namespace DotNetty.Codecs.DNS.Messages +{ + public class DatagramDnsQuery : DefaultDnsQuery, IAddressedEnvelope + { + public DatagramDnsQuery Content => this; + + public EndPoint Sender { get; } + + public EndPoint Recipient { get; } + + public DatagramDnsQuery(EndPoint sender, EndPoint recipient, int id) : this(sender, recipient, id, DnsOpCode.QUERY) { } + + public DatagramDnsQuery(EndPoint sender, EndPoint recipient, int id, DnsOpCode opCode) : base(id, opCode) + { + if (recipient == null && sender == null) + throw new ArgumentNullException("recipient and sender"); + + Sender = sender; + Recipient = recipient; + } + + public override bool Equals(object obj) + { + if (this == obj) + return false; + + if (!base.Equals(obj)) + return false; + + if (!(obj is IAddressedEnvelope)) + return false; + + IAddressedEnvelope that = (IAddressedEnvelope)obj; + if (Sender == null) + { + if (that.Sender != null) + return false; + } + else if (!Sender.Equals(that.Sender)) + { + return false; + } + + if (Recipient == null) + { + if (that.Recipient != null) + return false; + } + else if (!Recipient.Equals(that.Recipient)) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + int hashCode = base.GetHashCode(); + if (Sender != null) + hashCode = hashCode * 31 + Sender.GetHashCode(); + + if (Recipient != null) + hashCode = hashCode * 31 + Recipient.GetHashCode(); + + return hashCode; + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DatagramDnsResponse.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DatagramDnsResponse.cs new file mode 100644 index 000000000..874dc7008 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DatagramDnsResponse.cs @@ -0,0 +1,77 @@ +using DotNetty.Transport.Channels; +using System; +using System.Net; + +namespace DotNetty.Codecs.DNS.Messages +{ + public class DatagramDnsResponse : DefaultDnsResponse, IAddressedEnvelope + { + public EndPoint Sender { get; } + + public EndPoint Recipient { get; } + + public DatagramDnsResponse Content=>this ; + + public DatagramDnsResponse(EndPoint sender, EndPoint recipient, int id) + : this(sender, recipient, id, DnsOpCode.QUERY, DnsResponseCode.NOERROR) { } + + public DatagramDnsResponse(EndPoint sender, EndPoint recipient, int id, DnsOpCode opCode) + : this(sender, recipient, id, opCode, DnsResponseCode.NOERROR) { } + + public DatagramDnsResponse(EndPoint sender, EndPoint recipient, int id, DnsOpCode opCode, DnsResponseCode responseCode) + : base(id, opCode, responseCode) + { + Sender = sender ?? throw new ArgumentNullException(nameof(sender)); + Recipient = recipient ?? throw new ArgumentNullException(nameof(recipient)); + } + + public override bool Equals(object obj) + { + if (this == obj) return true; + + if (!base.Equals(obj)) return false; + + if (!(obj is IAddressedEnvelope)) return false; + + var that = (IAddressedEnvelope)obj; + + if (Sender == null) + { + if (that.Sender != null) + return true; + } + else if (!Sender.Equals(that.Sender)) + { + return false; + } + + if (Recipient == null) + { + if (that.Recipient != null) + return false; + } + else if (!Recipient.Equals(that.Recipient)) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + int hashCode = base.GetHashCode(); + if (Sender != null) + { + hashCode = hashCode * 31 + Sender.GetHashCode(); + } + + if (Recipient != null) + { + hashCode = hashCode * 31 + Recipient.GetHashCode(); + } + + return hashCode; + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DefaultDnsQuery.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DefaultDnsQuery.cs new file mode 100644 index 000000000..b30ceec38 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DefaultDnsQuery.cs @@ -0,0 +1,9 @@ +namespace DotNetty.Codecs.DNS.Messages +{ + public class DefaultDnsQuery : AbstractDnsMessage, IDnsQuery + { + public DefaultDnsQuery(int id) : base(id) { } + + public DefaultDnsQuery(int id, DnsOpCode opCode) : base(id, opCode) { } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DefaultDnsResponse.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DefaultDnsResponse.cs new file mode 100644 index 000000000..419bf9271 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DefaultDnsResponse.cs @@ -0,0 +1,30 @@ +using System; +using System.Text; + +namespace DotNetty.Codecs.DNS.Messages +{ + public class DefaultDnsResponse : AbstractDnsMessage, IDnsResponse + { + public bool IsAuthoritativeAnswer { get; set; } + public bool IsTruncated { get; set; } + public bool IsRecursionAvailable { get; set; } + public DnsResponseCode Code { get; set; } + + public DefaultDnsResponse(int id) + : this(id, DnsOpCode.QUERY, DnsResponseCode.NOERROR) { } + + public DefaultDnsResponse(int id, DnsOpCode opCode) + : this(id, opCode, DnsResponseCode.NOERROR) { } + + public DefaultDnsResponse(int id, DnsOpCode opCode, DnsResponseCode code) + : base(id, opCode) + { + Code = code ?? throw new ArgumentNullException(nameof(code)); + } + + public override string ToString() + { + return new StringBuilder(128).AppendResponse(this).ToString(); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DnsResponseCode.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DnsResponseCode.cs new file mode 100644 index 000000000..9f6b40086 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/DnsResponseCode.cs @@ -0,0 +1,105 @@ +using System; + +namespace DotNetty.Codecs.DNS.Messages +{ + public class DnsResponseCode + { + public static DnsResponseCode NOERROR = new DnsResponseCode(0, "NoError"); + public static DnsResponseCode FORMERR = new DnsResponseCode(1, "FormErr"); + public static DnsResponseCode SERVFAIL = new DnsResponseCode(2, "ServFail"); + public static DnsResponseCode NXDOMAIN = new DnsResponseCode(3, "NXDomain"); + public static DnsResponseCode NOTIMP = new DnsResponseCode(4, "NotImp"); + public static DnsResponseCode REFUSED = new DnsResponseCode(5, "Refused"); + public static DnsResponseCode YXDOMAIN = new DnsResponseCode(6, "YXDomain"); + public static DnsResponseCode YXRRSET = new DnsResponseCode(7, "YXRRSet"); + public static DnsResponseCode NXRRSET = new DnsResponseCode(8, "NXRRSet"); + public static DnsResponseCode NOTAUTH = new DnsResponseCode(9, "NotAuth"); + public static DnsResponseCode NOTZONE = new DnsResponseCode(10, "NotZone"); + public static DnsResponseCode BADVERS_OR_BADSIG = new DnsResponseCode(16, "BADVERS_OR_BADSIG"); + public static DnsResponseCode BADKEY = new DnsResponseCode(17, "BADKEY"); + public static DnsResponseCode BADTIME = new DnsResponseCode(18, "BADTIME"); + public static DnsResponseCode BADMODE = new DnsResponseCode(19, "BADMODE"); + public static DnsResponseCode BADNAME = new DnsResponseCode(20, "BADNAME"); + public static DnsResponseCode BADALG = new DnsResponseCode(21, "BADALG"); + + private string text; + + public int IntValue { get; } + public string Name { get; } + + private DnsResponseCode(int code) : this(code, "UNKNOWN") { } + + public DnsResponseCode(int code, string name) + { + if (code < 0 || code > 65535) + throw new ArgumentException($"code: {code} (expected: 0 ~ 65535)"); + + IntValue = code; + Name = name ?? throw new ArgumentNullException(nameof(name)); + } + + public static DnsResponseCode From(int responseCode) + { + switch (responseCode) + { + case 0: + return NOERROR; + case 1: + return FORMERR; + case 2: + return SERVFAIL; + case 3: + return NXDOMAIN; + case 4: + return NOTIMP; + case 5: + return REFUSED; + case 6: + return YXDOMAIN; + case 7: + return YXRRSET; + case 8: + return NXRRSET; + case 9: + return NOTAUTH; + case 10: + return NOTZONE; + case 16: + return BADVERS_OR_BADSIG; + case 17: + return BADKEY; + case 18: + return BADTIME; + case 19: + return BADMODE; + case 20: + return BADNAME; + case 21: + return BADALG; + default: + return new DnsResponseCode(responseCode); + } + } + + public override int GetHashCode() + { + return IntValue; + } + + public override bool Equals(object obj) + { + if (!(obj is DnsResponseCode)) + return false; + + return IntValue == ((DnsResponseCode)obj).IntValue; + } + + public override string ToString() + { + string text = this.text; + if (text == null) + this.text = text = $"{Name} ({IntValue})"; + return text; + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsMessage.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsMessage.cs new file mode 100644 index 000000000..bbd8c4c7f --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsMessage.cs @@ -0,0 +1,24 @@ +using DotNetty.Common; +using DotNetty.Codecs.DNS.Records; + +namespace DotNetty.Codecs.DNS.Messages +{ + public interface IDnsMessage : IReferenceCounted + { + int Id { get; set; } + DnsOpCode OpCode { get; set; } + bool IsRecursionDesired { get; set; } + int Z { get; set; } + int Count(DnsSection section); + int Count(); + TRecord GetRecord(DnsSection section) where TRecord : IDnsRecord; + TRecord GetRecord(DnsSection section, int index) where TRecord : IDnsRecord; + void SetRecord(DnsSection section, IDnsRecord record); + void SetRecord(DnsSection section, int index, IDnsRecord record); + void AddRecord(DnsSection section, IDnsRecord record); + void AddRecord(DnsSection section, int index, IDnsRecord record); + void RemoveRecord(DnsSection section, int index); + void Clear(DnsSection section); + void Clear(); + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsQuery.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsQuery.cs new file mode 100644 index 000000000..806417d9d --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsQuery.cs @@ -0,0 +1,8 @@ + +namespace DotNetty.Codecs.DNS.Messages +{ + public interface IDnsQuery : IDnsMessage + { + + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsResponse.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsResponse.cs new file mode 100644 index 000000000..71335b010 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Messages/IDnsResponse.cs @@ -0,0 +1,10 @@ +namespace DotNetty.Codecs.DNS.Messages +{ + public interface IDnsResponse : IDnsMessage + { + bool IsAuthoritativeAnswer { get; set; } + bool IsTruncated { get; set; } + bool IsRecursionAvailable { get; set; } + DnsResponseCode Code { get; set; } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/AbstractDnsOptPseudoRrRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/AbstractDnsOptPseudoRrRecord.cs new file mode 100644 index 000000000..07297a90f --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/AbstractDnsOptPseudoRrRecord.cs @@ -0,0 +1,48 @@ +using System.Reflection; +using System.Text; + +namespace DotNetty.Codecs.DNS.Records +{ + public abstract class AbstractDnsOptPseudoRrRecord : AbstractDnsRecord, IDnsOptPseudoRecord + { + private const string EMPTY_STRING = ""; + + protected AbstractDnsOptPseudoRrRecord(int maxPayloadSize, int extendedRcode, int version) + : base(EMPTY_STRING, DnsRecordType.OPT, PackIntoLong(extendedRcode, version), (DnsRecordClass)maxPayloadSize ) { } + + protected AbstractDnsOptPseudoRrRecord(int maxPayloadSize) + : base(EMPTY_STRING, DnsRecordType.OPT, 0, (DnsRecordClass)maxPayloadSize) { } + + private static long PackIntoLong(int val, int val2) + { + return ((val & 0xff) << 24 | (val2 & 0xff) << 16 | (0 & 0xff) << 8 | 0 & 0xff) & 0xFFFFFFFFL; + } + + public int ExtendedRcode => (short) (((int) TimeToLive >> 16) & 0xff); + + public int Version => (short)(((int)TimeToLive >> 16) & 0xff); + + public int Flags => (short)((short)TimeToLive & 0xff); + + public override string ToString() + { + return GetBuilder().ToString(); + } + + protected StringBuilder GetBuilder() + { + return new StringBuilder(64) + .Append(GetType().GetTypeInfo().Name) + .Append('(') + .Append("OPT flags:") + .Append(Flags) + .Append(" version:") + .Append(Version) + .Append(" extendedRecode:") + .Append(ExtendedRcode) + .Append(" udp:") + .Append(DnsClass) + .Append(')'); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/AbstractDnsRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/AbstractDnsRecord.cs new file mode 100644 index 000000000..bd8003321 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/AbstractDnsRecord.cs @@ -0,0 +1,100 @@ +using System; +using System.Globalization; +using System.Reflection; +using System.Text; + +namespace DotNetty.Codecs.DNS.Records +{ + public abstract class AbstractDnsRecord : IDnsRecord + { + private readonly IdnMapping idn = new IdnMapping(); + private int hashCode; + + public DnsRecordType Type { get; } + public string Name { get; } + public DnsRecordClass DnsClass { get; } + public long TimeToLive { get; set; } + + protected AbstractDnsRecord(string name, DnsRecordType type, + long timeToLive, DnsRecordClass dnsClass = DnsRecordClass.IN) + { + if (TimeToLive < 0) + throw new ArgumentException($"timeToLive: {timeToLive} (expected: >= 0)"); + + TimeToLive = timeToLive; + + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentNullException(nameof(name)); + + Name = AppendTrailingDot(idn.GetAscii(name)); + Type = type ?? throw new ArgumentNullException(nameof(type)); + DnsClass = dnsClass; + } + + private static string AppendTrailingDot(string name) + { + if (name.Length > 0 && !name.EndsWith(".")) + return name + "."; + + return name; + } + + public override bool Equals(object obj) + { + if (this == obj) + return true; + + if (!(obj is AbstractDnsRecord)) + return false; + + var that = (AbstractDnsRecord)obj; + int hashCode = GetHashCode(); + if (hashCode != 0 && hashCode != that.GetHashCode()) + return false; + + return Type.IntValue == that.Type.IntValue && + DnsClass == that.DnsClass && + Name.Equals(that.Name); + } + + public override int GetHashCode() + { + int hashCode = this.hashCode; + if (hashCode != 0) + return hashCode; + + return this.hashCode = Name.GetHashCode() * 31 + + Type.IntValue * 31 + (int)DnsClass; + + } + + public override string ToString() + { + var builder = new StringBuilder(64); + builder.Append(GetType().GetTypeInfo().Name) + .Append('(') + .Append(Name) + .Append(' ') + .Append(TimeToLive) + .Append(' ') + .AppendRecordClass(DnsClass) + .Append(' ') + .Append(Type.Name) + .Append(')'); + + return builder.ToString(); + } + + } + + public enum DnsRecordClass : int + { + IN = 0x0001, + CSNET = 0x0002, + CHAOS = 0x0003, + HESIOD = 0x0004, + NONE = 0x00fe, + ANY = 0x00ff + } + +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsOptEcsRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsOptEcsRecord.cs new file mode 100644 index 000000000..43e62bd04 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsOptEcsRecord.cs @@ -0,0 +1,52 @@ +using System; +using System.Net; +using System.Text; + +namespace DotNetty.Codecs.DNS.Records +{ + public class DefaultDnsOptEcsRecord : AbstractDnsOptPseudoRrRecord, IDnsOptEcsRecord + { + private readonly int srcPrefixLength; + private readonly byte[] address; + + public int SourcePrefixLength { get; } + + public int ScopePrefixLength => 0; + + public byte[] Address => (byte[])address.Clone(); + + public DefaultDnsOptEcsRecord(int maxPayloadSize, int extendedRcode, int version, + int srcPrefixLength, byte[] address) : base(maxPayloadSize, extendedRcode, version) + { + SourcePrefixLength = srcPrefixLength; + address = VerifyAddress(address); + } + + public DefaultDnsOptEcsRecord(int maxPayloadSize, int srcPrefixLength, byte[] address) + : this(maxPayloadSize, 0, 0, srcPrefixLength, address) { } + + public DefaultDnsOptEcsRecord(int maxPayloadSize, IPAddress address) + : this(maxPayloadSize, 0, 0, 0, address.GetAddressBytes()) { } + + private static byte[] VerifyAddress(byte[] bytes) + { + if (bytes.Length == 4 || bytes.Length == 16) + return bytes; + + throw new ArgumentException("bytes.length must either 4 or 16"); + } + + public override string ToString() + { + StringBuilder builder = GetBuilder(); + builder.Length = builder.Length - 1; + return builder.Append(" address:") + .Append(string.Join(".", address, 0, address.Length)) + .Append(" sourcePrefixLength:") + .Append(SourcePrefixLength) + .Append(" scopePrefixLength:") + .Append(ScopePrefixLength) + .Append(')').ToString(); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsPtrRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsPtrRecord.cs new file mode 100644 index 000000000..fea8f293e --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsPtrRecord.cs @@ -0,0 +1,39 @@ +using System; +using System.Reflection; +using System.Text; + +namespace DotNetty.Codecs.DNS.Records +{ + public class DefaultDnsPtrRecord : AbstractDnsRecord, IDnsPtrRecord + { + public string HostName { get; } + + public DefaultDnsPtrRecord(string name, DnsRecordClass dnsClass, long timeToLive, string hostname) + : base(name, DnsRecordType.PTR, timeToLive, dnsClass) + { + if (string.IsNullOrWhiteSpace(hostname)) + throw new ArgumentNullException(hostname); + + HostName = hostname; + } + + public override string ToString() + { + var builder = new StringBuilder(64); + + builder.Append(GetType().GetTypeInfo().Name) + .Append('(') + .Append(string.IsNullOrWhiteSpace(Name) ? "" : Name) + .Append(' ') + .Append(TimeToLive) + .Append(' ') + .AppendRecordClass(DnsClass) + .Append(' ') + .Append(Type.Name) + .Append(' ') + .Append(HostName); + + return builder.ToString(); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsQuestion.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsQuestion.cs new file mode 100644 index 000000000..d05c079a8 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsQuestion.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using System.Text; + +namespace DotNetty.Codecs.DNS.Records +{ + public class DefaultDnsQuestion : AbstractDnsRecord, IDnsQuestion + { + public DefaultDnsQuestion(string name, + DnsRecordType type, long timeToLive, + DnsRecordClass dnsClass = DnsRecordClass.IN) + : base(name, type, timeToLive, dnsClass) { } + + public DefaultDnsQuestion(string name, DnsRecordType type) : base(name, type, 0) { } + + public DefaultDnsQuestion(string name, DnsRecordType type, DnsRecordClass dnsClass) : + base(name, type, 0, dnsClass){ } + + public override string ToString() + { + var builder = new StringBuilder(64); + + builder.Append(GetType().GetTypeInfo().Name) + .Append('(') + .Append(Name) + .Append(' ') + .AppendRecordClass(DnsClass) + .Append(' ') + .Append(Type.Name) + .Append(')'); + + return builder.ToString(); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsRawRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsRawRecord.cs new file mode 100644 index 000000000..f2c4c352e --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DefaultDnsRawRecord.cs @@ -0,0 +1,105 @@ +using System; +using System.Text; +using DotNetty.Buffers; +using DotNetty.Common; +using System.Reflection; + +namespace DotNetty.Codecs.DNS.Records +{ + public class DefaultDnsRawRecord : AbstractDnsRecord, IDnsRawRecord + { + public IByteBuffer Content { get; } + + public int ReferenceCount { get; } + + public DefaultDnsRawRecord(string name, DnsRecordType type, long timeToLive, + IByteBuffer content) : this(name, type, DnsRecordClass.IN, timeToLive, content) + { + } + + public DefaultDnsRawRecord(string name, DnsRecordType type, DnsRecordClass dnsClass, + long timeToLive, IByteBuffer content) : base(name, type, timeToLive, dnsClass) + { + Content = content ?? throw new ArgumentNullException(nameof(content)); + } + + public IByteBufferHolder Copy() + { + return Replace(Content.Copy()); + } + + public IByteBufferHolder Duplicate() + { + return Replace(Content.Duplicate()); + } + + public bool Release() + { + return Content.Release(); + } + + public bool Release(int decrement) + { + return Content.Release(decrement); + } + + public IReferenceCounted Retain() + { + Content.Retain(); + return this; + } + + public IReferenceCounted Retain(int increment) + { + Content.Retain(increment); + return this; + } + + public IReferenceCounted Touch() + { + Content.Touch(); + return this; + } + + public IReferenceCounted Touch(object hint) + { + Content.Touch(hint); + return this; + } + + + public override string ToString() + { + var builder = new StringBuilder(64); + builder.Append(GetType().GetTypeInfo().Name).Append('('); + + if (Type != DnsRecordType.OPT) + { + builder.Append(string.IsNullOrWhiteSpace(Name) ? "" : Name) + .Append(' ') + .Append(TimeToLive) + .Append(' ') + .AppendRecordClass(DnsClass) + .Append(' ') + .Append(Type.Name); + } + else + { + builder.Append("OPT flags:") + .Append(TimeToLive) + .Append(" udp:") + .Append(DnsClass); + } + + builder.Append(' ') + .Append(Content.ReadableBytes) + .Append("B)"); + + return builder.ToString(); + } + + public IByteBufferHolder RetainedDuplicate() => this.Replace(this.Content.RetainedDuplicate()); + + public virtual IByteBufferHolder Replace(IByteBuffer content) => new DefaultByteBufferHolder(content); + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DnsRecordType.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DnsRecordType.cs new file mode 100644 index 000000000..46f22cd1a --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/DnsRecordType.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DotNetty.Codecs.DNS.Records +{ + /// + /// Represents a DNS record type. + /// + public class DnsRecordType + { + #region Types + public static readonly DnsRecordType A = new DnsRecordType(0x0001, "A"); + + public static readonly DnsRecordType NS = new DnsRecordType(0x0002, "NS"); + + public static readonly DnsRecordType CNAME = new DnsRecordType(0x0005, "CNAME"); + + public static readonly DnsRecordType SOA = new DnsRecordType(0x0006, "SOA"); + + public static readonly DnsRecordType PTR = new DnsRecordType(0x000c, "PTR"); + + public static readonly DnsRecordType MX = new DnsRecordType(0x000f, "MX"); + + public static readonly DnsRecordType TXT = new DnsRecordType(0x0010, "TXT"); + + public static readonly DnsRecordType RP = new DnsRecordType(0x0011, "RP"); + + public static readonly DnsRecordType AFSDB = new DnsRecordType(0x0012, "AFSDB"); + + public static readonly DnsRecordType SIG = new DnsRecordType(0x0018, "SIG"); + + public static readonly DnsRecordType KEY = new DnsRecordType(0x0019, "KEY"); + + public static readonly DnsRecordType AAAA = new DnsRecordType(0x001c, "AAAA"); + + public static readonly DnsRecordType LOC = new DnsRecordType(0x001d, "LOC"); + + public static readonly DnsRecordType SRV = new DnsRecordType(0x0021, "SRV"); + + public static readonly DnsRecordType NAPTR = new DnsRecordType(0x0023, "NAPTR"); + + public static readonly DnsRecordType KX = new DnsRecordType(0x0024, "KX"); + + public static readonly DnsRecordType CERT = new DnsRecordType(0x0025, "CERT"); + + public static readonly DnsRecordType DNAME = new DnsRecordType(0x0027, "DNAME"); + + public static readonly DnsRecordType OPT = new DnsRecordType(0x0029, "OPT"); + + public static readonly DnsRecordType APL = new DnsRecordType(0x002a, "APL"); + + public static readonly DnsRecordType DS = new DnsRecordType(0x002b, "DS"); + + public static readonly DnsRecordType SSHFP = new DnsRecordType(0x002c, "SSHFP"); + + public static readonly DnsRecordType IPSECKEY = new DnsRecordType(0x002d, "IPSECKEY"); + + public static readonly DnsRecordType RRSIG = new DnsRecordType(0x002e, "RRSIG"); + + public static readonly DnsRecordType NSEC = new DnsRecordType(0x002f, "NSEC"); + + public static readonly DnsRecordType DNSKEY = new DnsRecordType(0x0030, "DNSKEY"); + + public static readonly DnsRecordType DHCID = new DnsRecordType(0x0031, "DHCID"); + + public static readonly DnsRecordType NSEC3 = new DnsRecordType(0x0032, "NSEC3"); + + public static readonly DnsRecordType NSEC3PARAM = new DnsRecordType(0x0033, "NSEC3PARAM"); + + public static readonly DnsRecordType TLSA = new DnsRecordType(0x0034, "TLSA"); + + public static readonly DnsRecordType HIP = new DnsRecordType(0x0037, "HIP"); + + public static readonly DnsRecordType SPF = new DnsRecordType(0x0063, "SPF"); + + public static readonly DnsRecordType TKEY = new DnsRecordType(0x00f9, "TKEY"); + + public static readonly DnsRecordType TSIG = new DnsRecordType(0x00fa, "TSIG"); + + public static readonly DnsRecordType IXFR = new DnsRecordType(0x00fb, "IXFR"); + + public static readonly DnsRecordType AXFR = new DnsRecordType(0x00fc, "AXFR"); + + public static readonly DnsRecordType ANY = new DnsRecordType(0x00ff, "ANY"); + + public static readonly DnsRecordType CAA = new DnsRecordType(0x0101, "CAA"); + + public static readonly DnsRecordType TA = new DnsRecordType(0x8000, "TA"); + + public static readonly DnsRecordType DLV = new DnsRecordType(0x8001, "DLV"); + #endregion + + private static readonly Dictionary byName = new Dictionary(); + private static readonly Dictionary byType = new Dictionary(); + private static readonly string EXPECTED; + private string text = string.Empty; + + public int IntValue { get; } + public string Name { get; } + + private DnsRecordType(int intValue) : this(intValue, "UNKNOWN") { } + + public DnsRecordType(int intValue, string name) + { + if ((intValue & 0xffff) != intValue) + { + throw new ArgumentException("intValue: " + intValue + " (expected: 0 ~ 65535)"); + } + IntValue = intValue; + Name = name; + } + + static DnsRecordType() + { + DnsRecordType[] all = { + A, NS, CNAME, SOA, PTR, MX, TXT, RP, AFSDB, SIG, KEY, AAAA, LOC, SRV, NAPTR, KX, CERT, DNAME, OPT, APL, + DS, SSHFP, IPSECKEY, RRSIG, NSEC, DNSKEY, DHCID, NSEC3, NSEC3PARAM, TLSA, HIP, SPF, TKEY, TSIG, IXFR, + AXFR, ANY, CAA, TA, DLV + }; + + var expected = new StringBuilder(512); + + expected.Append(" (expected: "); + + foreach (var type in all) + { + byName.Add(type.Name, type); + byType.Add(type.IntValue, type); + + expected.Append(type.Name) + .Append('(') + .Append(type.IntValue) + .Append("), "); + } + + expected.Length = expected.Length - 2; + expected.Append(')'); + EXPECTED = expected.ToString(); + } + + public static DnsRecordType From(int intValue) + { + if (byType.ContainsKey(intValue)) + return byType[intValue]; + + return new DnsRecordType(intValue); + } + + public static DnsRecordType From(string name) + { + if (byName.ContainsKey(name)) + return byName[name]; + + throw new ArgumentException($"name: {name} {EXPECTED}"); + } + + public override int GetHashCode() + { + return IntValue; + } + + public override bool Equals(object obj) + { + return obj is DnsRecordType && ((DnsRecordType)obj).IntValue == IntValue; + } + + public override string ToString() + { + string text = this.text; + if (text == null) + this.text = text = Name + '(' + IntValue + ')'; + + return text; + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsOptEcsRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsOptEcsRecord.cs new file mode 100644 index 000000000..9dca7a61b --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsOptEcsRecord.cs @@ -0,0 +1,9 @@ +namespace DotNetty.Codecs.DNS.Records +{ + public interface IDnsOptEcsRecord : IDnsOptPseudoRecord + { + int SourcePrefixLength { get; } + int ScopePrefixLength { get; } + byte[] Address { get; } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsOptPseudoRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsOptPseudoRecord.cs new file mode 100644 index 000000000..82ad7e57f --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsOptPseudoRecord.cs @@ -0,0 +1,9 @@ +namespace DotNetty.Codecs.DNS.Records +{ + public interface IDnsOptPseudoRecord : IDnsRecord + { + int ExtendedRcode { get; } + int Version { get; } + int Flags { get; } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsPtrRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsPtrRecord.cs new file mode 100644 index 000000000..2d3cc1950 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsPtrRecord.cs @@ -0,0 +1,8 @@ + +namespace DotNetty.Codecs.DNS.Records +{ + public interface IDnsPtrRecord : IDnsRecord + { + string HostName { get; } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsQuestion.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsQuestion.cs new file mode 100644 index 000000000..8abab5ba9 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsQuestion.cs @@ -0,0 +1,6 @@ +namespace DotNetty.Codecs.DNS.Records +{ + public interface IDnsQuestion : IDnsRecord + { + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsRawRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsRawRecord.cs new file mode 100644 index 000000000..c85d9984e --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsRawRecord.cs @@ -0,0 +1,8 @@ +using DotNetty.Buffers; + +namespace DotNetty.Codecs.DNS.Records +{ + public interface IDnsRawRecord : IDnsRecord, IByteBufferHolder + { + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsRecord.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsRecord.cs new file mode 100644 index 000000000..5cd8f703e --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Records/IDnsRecord.cs @@ -0,0 +1,10 @@ +namespace DotNetty.Codecs.DNS.Records +{ + public interface IDnsRecord + { + DnsRecordClass DnsClass { get; } + string Name { get; } + long TimeToLive { get; set; } + DnsRecordType Type { get; } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/TcpDnsQueryEncoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/TcpDnsQueryEncoder.cs new file mode 100644 index 000000000..504793926 --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/TcpDnsQueryEncoder.cs @@ -0,0 +1,35 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Transport.Channels; +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; + +namespace DotNetty.Codecs.DNS +{ + public sealed class TcpDnsQueryEncoder:MessageToByteEncoder + { + private readonly DnsQueryEncoder encoder; + + public TcpDnsQueryEncoder():this(new DefaultDnsRecordEncoder()) + { + } + + public TcpDnsQueryEncoder(IDnsRecordEncoder recordEncoder) + { + this.encoder = new DnsQueryEncoder(recordEncoder); + } + + protected override void Encode(IChannelHandlerContext context, IDnsQuery message, IByteBuffer output) + { + output.SetWriterIndex(output.WriterIndex + 2); + encoder.Encode(message, output); + output.SetShort(0, output.ReadableBytes- 2); + } + + protected override IByteBuffer AllocateBuffer(IChannelHandlerContext ctx) { + return ctx.Allocator.Buffer(1024); + } + } +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/TcpDnsResponseDecoder.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/TcpDnsResponseDecoder.cs new file mode 100644 index 000000000..a8d24f37d --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/TcpDnsResponseDecoder.cs @@ -0,0 +1,47 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Transport.Channels; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace DotNetty.Codecs.DNS +{ + public class TcpDnsResponseDecoder : LengthFieldBasedFrameDecoder + { + private readonly DnsResponseDecoder responseDecoder; + + public TcpDnsResponseDecoder():this(new DefaultDnsRecordDecoder(), 64 * 1024) + { + + } + + public TcpDnsResponseDecoder(IDnsRecordDecoder recordDecoder, int maxFrameLength) : base(maxFrameLength, 0, 2, 0, 2) + { + + this.responseDecoder = new DnsResponseDecoder(recordDecoder); + } + + protected override Object Decode(IChannelHandlerContext ctx, IByteBuffer buffer) + { + var frame = (IByteBuffer)base.Decode(ctx, buffer); + if (frame == null) { + return null; + } + + try { + return responseDecoder.Decode(ctx.Channel.RemoteAddress, ctx.Channel.LocalAddress, frame.Slice()); + } finally { + frame.Release(); + } + } + + + protected override IByteBuffer ExtractFrame(IChannelHandlerContext ctx, IByteBuffer buffer, int index, int length) + { + return buffer.Copy(index, length); + } + } + +} diff --git a/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Utils.cs b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Utils.cs new file mode 100644 index 000000000..12769999c --- /dev/null +++ b/src/DotNetty.Codecs/DotNetty.Codecs.DNS/Utils.cs @@ -0,0 +1,154 @@ +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Codecs.DNS.Records; +using DotNetty.Transport.Channels; +using System; +using System.Reflection; +using System.Text; + +namespace DotNetty.Codecs.DNS +{ + internal static class Utils + { + internal static StringBuilder AppendRecordClass(this StringBuilder builder, DnsRecordClass dnsClass) + { + string name; + switch (dnsClass) + { + case DnsRecordClass.IN: + name = "IN"; + break; + case DnsRecordClass.CSNET: + name = "CSNET"; + break; + case DnsRecordClass.CHAOS: + name = "CHAOS"; + break; + case DnsRecordClass.HESIOD: + name = "HESIOD"; + break; + case DnsRecordClass.NONE: + name = "NONE"; + break; + case DnsRecordClass.ANY: + name = "ANY"; + break; + default: + name = $"UNKNOWN({dnsClass})"; + break; + } + + builder.Append(name); + return builder; + } + + internal static StringBuilder AppendResponse(this StringBuilder builder, IDnsResponse response) + { + builder.AppendResponseHeader(response) + .AppendAllRecords(response); + return builder; + } + + private static StringBuilder AppendAddresses(this StringBuilder builder, IDnsMessage response) + { + + if (!(response is IAddressedEnvelope)) + return builder; + + IAddressedEnvelope envelope = (IAddressedEnvelope) response; + + var addr = envelope.Sender; + if (addr != null) + { + builder.Append("from: ") + .Append(addr) + .Append(", "); + } + + addr = envelope.Recipient; + if (addr != null) + { + builder.Append("to: ") + .Append(addr) + .Append(", "); + } + + return builder; + } + + internal static StringBuilder AppendResponseHeader(this StringBuilder builder, IDnsResponse response) + { + builder.Append(response.GetType().GetTypeInfo().Name) + .Append('(') + .AppendAddresses(response) + .Append(response.Id) + .Append(", ") + .Append(response.OpCode) + .Append(", ") + .Append(response.Code) + .Append(','); + + bool hasComma = true; + if (response.IsRecursionDesired) + { + hasComma = false; + builder.Append(" RD"); + } + if (response.IsAuthoritativeAnswer) + { + hasComma = false; + builder.Append(" AA"); + } + if (response.IsTruncated) + { + hasComma = false; + builder.Append(" TC"); + } + if (response.IsRecursionAvailable) + { + hasComma = false; + builder.Append(" RA"); + } + if (response.Z != 0) + { + if (!hasComma) + { + builder.Append(','); + } + builder.Append(" Z: ") + .Append(response.Z); + } + + if (hasComma) + { + builder[builder.Length - 1] = ')'; + } + else + { + builder.Append(')'); + } + + return builder; + } + + private static StringBuilder AppendAllRecords(this StringBuilder builder, IDnsMessage msg) + { + return builder.AppendRecords(msg, DnsSection.QUESTION) + .AppendRecords(msg, DnsSection.ANSWER) + .AppendRecords(msg, DnsSection.AUTHORITY) + .AppendRecords(msg, DnsSection.ADDITIONAL); + } + + private static StringBuilder AppendRecords(this StringBuilder builder, IDnsMessage message, DnsSection section) + { + int count = message.Count(section); + for (int i = 0; i < count; i++) + { + builder.Append(Environment.NewLine) + .Append('\t') + .Append(message.GetRecord(section, i)); + } + + return builder; + } + } +} diff --git a/src/Surging.ApiGateway/.bowerrc b/src/Surging.ApiGateway/.bowerrc deleted file mode 100644 index 038f7dfef..000000000 --- a/src/Surging.ApiGateway/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "wwwroot/assets/lib" -} - diff --git a/src/Surging.ApiGateway/Configs/gatewaySettings.json b/src/Surging.ApiGateway/Configs/gatewaySettings.json index 76f08a2f1..54a385d2d 100644 --- a/src/Surging.ApiGateway/Configs/gatewaySettings.json +++ b/src/Surging.ApiGateway/Configs/gatewaySettings.json @@ -3,15 +3,14 @@ "AuthorizationRoutePath": "api/user/authentication", "AuthorizationServiceKey": "User", "TokenEndpointPath": "api/oauth2/token", - "CacheMode": "ddlCache.Redis", //MemoryCache or gateway.Redis save token + "CacheMode": "MemoryCache", //MemoryCache or gateway.Redis save token "AccessPolicy": { - "Origins": [ "http://127.0.0.1:1927", "http://localhost:927" ], "AllowAnyHeader": true, "AllowAnyMethod": true }, "Register": { "Provider": "Consul", - "Address": "${Register_Conn}|127.0.0.1:8500" + "Address": "${Register_Conn}|127.0.0.1:8500" //127.0.0.1:8500,127.0.0.1:9500 }, "ServicePart": { "MainPath": "part/service/aggregation", diff --git a/src/Surging.ApiGateway/Controllers/HomeController.cs b/src/Surging.ApiGateway/Controllers/HomeController.cs index 744d5d9e0..e81047ba8 100644 --- a/src/Surging.ApiGateway/Controllers/HomeController.cs +++ b/src/Surging.ApiGateway/Controllers/HomeController.cs @@ -10,7 +10,7 @@ public IActionResult Index() { return View(); } - + public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); diff --git a/src/Surging.ApiGateway/Controllers/ServiceManageController.cs b/src/Surging.ApiGateway/Controllers/ServiceManageController.cs index 6d718818a..18ea86811 100644 --- a/src/Surging.ApiGateway/Controllers/ServiceManageController.cs +++ b/src/Surging.ApiGateway/Controllers/ServiceManageController.cs @@ -24,6 +24,20 @@ public IActionResult Index() return View(); } + public IActionResult ServiceManage() + { + return View(); + } + + + [HttpPost] + public async Task GetRegisterAddress([FromServices]IServiceRegisterProvider serviceRegisterProvide, string queryParam) + { + var list = await serviceRegisterProvide.GetAddressAsync(queryParam); + var result = ServiceResult>.Create(true, list); + return Json(result); + } + [HttpPost] public async Task GetAddress([FromServices]IServiceDiscoveryProvider serviceDiscoveryProvider, string queryParam) { diff --git a/src/Surging.ApiGateway/Controllers/ServicesController.cs b/src/Surging.ApiGateway/Controllers/ServicesController.cs index 2428d16fb..ffc05f122 100644 --- a/src/Surging.ApiGateway/Controllers/ServicesController.cs +++ b/src/Surging.ApiGateway/Controllers/ServicesController.cs @@ -15,8 +15,8 @@ using GateWayAppConfig = Surging.Core.ApiGateWay.AppConfig; using System.Reflection; using Surging.Core.CPlatform.Utilities; -using Newtonsoft.Json.Linq; using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.CPlatform.Routing.Template; namespace Surging.ApiGateway.Controllers { @@ -35,10 +35,11 @@ public ServicesController(IServiceProxyProvider serviceProxyProvider, _serviceRouteProvider = serviceRouteProvider; _authorizationServerProvider = authorizationServerProvider; } - + public async Task> Path([FromServices]IServicePartProvider servicePartProvider, string path, [FromBody]Dictionary model) { string serviceKey = this.Request.Query["servicekey"]; + path = path.IndexOf("/") < 0 ? $"/{path}" : path; if (model == null) { model = new Dictionary(); @@ -47,95 +48,119 @@ public async Task> Path([FromServices]IServicePartProvider { model[n] = this.Request.Query[n].ToString(); } - ServiceResult result = ServiceResult.Create(false,null); - path = path.ToLower() == GateWayAppConfig.TokenEndpointPath.ToLower() ? - GateWayAppConfig.AuthorizationRoutePath : path.ToLower(); - if( await GetAllowRequest(path)==false) return new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; + ServiceResult result = ServiceResult.Create(false, null); + path = String.Compare(path.ToLower(), GateWayAppConfig.TokenEndpointPath, true) == 0 ? + GateWayAppConfig.AuthorizationRoutePath : path.ToLower(); + var route = await _serviceRouteProvider.GetRouteByPathRegex(path); + var httpMethods = route.ServiceDescriptor.HttpMethod(); + if (!string.IsNullOrEmpty(httpMethods) && + !httpMethods.Contains(Request.Method)) + return new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.Http405Endpoint, Message = "405 HTTP Method Not Supported" }; + if (!GetAllowRequest(route)) return new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; if (servicePartProvider.IsPart(path)) { result = ServiceResult.Create(true, await servicePartProvider.Merge(path, model)); result.StatusCode = (int)ServiceStatusCode.Success; } else - if ( OnAuthorization(path, model,ref result)) { - if (path == GateWayAppConfig.AuthorizationRoutePath) + var auth = await OnAuthorization(route, model); + result = auth.Item2; + if (auth.Item1) { - var token = await _authorizationServerProvider.GenerateTokenCredential(model); - if (token != null) + if (path == GateWayAppConfig.AuthorizationRoutePath) { - result = ServiceResult.Create(true, token); - result.StatusCode = (int)ServiceStatusCode.Success; + var token = await _authorizationServerProvider.GenerateTokenCredential(model); + if (token != null) + { + result = ServiceResult.Create(true, token); + result.StatusCode = (int)ServiceStatusCode.Success; + } + else + { + result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + } } else - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - } - } - else - { - if (!string.IsNullOrEmpty(serviceKey)) { - result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, path, serviceKey)); - result.StatusCode = (int)ServiceStatusCode.Success; - } - else - { - result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, path)); - result.StatusCode = (int)ServiceStatusCode.Success; + if (String.Compare(route.ServiceDescriptor.RoutePath, path, true) != 0) + { + var pamars = RouteTemplateSegmenter.Segment(route.ServiceDescriptor.RoutePath, path); + foreach (KeyValuePair item in pamars) + { + model.Add(item.Key, item.Value); + } + } + if (!string.IsNullOrEmpty(serviceKey)) + { + + result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, route.ServiceDescriptor.RoutePath, serviceKey)); + result.StatusCode = (int)ServiceStatusCode.Success; + } + else + { + result = ServiceResult.Create(true, await _serviceProxyProvider.Invoke(model, route.ServiceDescriptor.RoutePath)); + result.StatusCode = (int)ServiceStatusCode.Success; + } } } } return result; } - private async Task GetAllowRequest(string path) - { - var route = await _serviceRouteProvider.GetRouteByPath(path); + private bool GetAllowRequest(ServiceRoute route) + { return !route.ServiceDescriptor.DisableNetwork(); } - private bool OnAuthorization(string path, Dictionary model, ref ServiceResult result) + private async Task<(bool, ServiceResult)> OnAuthorization(ServiceRoute route, Dictionary model) { bool isSuccess = true; - var route = _serviceRouteProvider.GetRouteByPath(path).Result; + var serviceResult = ServiceResult.Create(false, null); + var result = (isSuccess, serviceResult); if (route.ServiceDescriptor.EnableAuthorization()) { if(route.ServiceDescriptor.AuthType()== AuthorizationType.JWT.ToString()) { - isSuccess= ValidateJwtAuthentication(route,model, ref result); + result =await ValidateJwtAuthentication(route,model); } else { - isSuccess = ValidateAppSecretAuthentication(route, path, model, ref result); + isSuccess = ValidateAppSecretAuthentication(route, model, ref serviceResult); + result= (isSuccess,serviceResult); } } - return isSuccess; + return result; } - public bool ValidateJwtAuthentication(ServiceRoute route, Dictionary model, ref ServiceResult result) + public async Task<(bool, ServiceResult)> ValidateJwtAuthentication(ServiceRoute route, Dictionary model) { + var result = ServiceResult.Create(false, null); bool isSuccess = true; var author = HttpContext.Request.Headers["Authorization"]; if (author.Count > 0) { - isSuccess = _authorizationServerProvider.ValidateClientAuthentication(author).Result; + isSuccess =await _authorizationServerProvider.ValidateClientAuthentication(author); if (!isSuccess) { result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; } else { - var keyValue = model.FirstOrDefault(); - if (!(keyValue.Value is IConvertible) || !typeof(IConvertible).GetTypeInfo().IsAssignableFrom(keyValue.Value.GetType())) + var payload = _authorizationServerProvider.GetPayloadString(author); + RpcContext.GetContext().SetAttachment("payload", payload); + if (model.Count>0) { - dynamic instance = keyValue.Value; - instance.Payload = _authorizationServerProvider.GetPayloadString(author); - RpcContext.GetContext().SetAttachment("payload", instance.Payload); - model.Remove(keyValue.Key); - model.Add(keyValue.Key, instance); + var keyValue = model.FirstOrDefault(); + if (!(keyValue.Value is IConvertible) || !typeof(IConvertible).GetTypeInfo().IsAssignableFrom(keyValue.Value.GetType())) + { + dynamic instance = keyValue.Value; + instance.Payload = payload; + model.Remove(keyValue.Key); + model.Add(keyValue.Key, instance); + } } } } @@ -144,30 +169,26 @@ public bool ValidateJwtAuthentication(ServiceRoute route, Dictionary { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; isSuccess = false; } - return isSuccess; + return (isSuccess,result); } - private bool ValidateAppSecretAuthentication(ServiceRoute route, string path, + + private bool ValidateAppSecretAuthentication(ServiceRoute route, Dictionary model, ref ServiceResult result) { bool isSuccess = true; DateTime time; var author = HttpContext.Request.Headers["Authorization"]; - - if (!string.IsNullOrEmpty(path) && model.ContainsKey("timeStamp") && author.Count>0) + + if (model.ContainsKey("timeStamp") && author.Count > 0) + { + if (long.TryParse(model["timeStamp"].ToString(), out long timeStamp)) { - if (DateTime.TryParse(model["timeStamp"].ToString(), out time)) + time = DateTimeConverter.UnixTimestampToDateTime(timeStamp); + var seconds = (DateTime.Now - time).TotalSeconds; + if (seconds <= 3560 && seconds >= 0) { - var seconds = (DateTime.Now - time).TotalSeconds; - if (seconds <= 3560 && seconds >= 0) - { - if (GetMD5($"{route.ServiceDescriptor.Token}{time.ToString("yyyy-MM-dd hh:mm:ss") }") != author.ToString()) - { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; - isSuccess = false; - } - } - else + if (GetMD5($"{route.ServiceDescriptor.Token}{time.ToString("yyyy-MM-dd hh:mm:ss") }") != author.ToString()) { result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; isSuccess = false; @@ -181,9 +202,15 @@ private bool ValidateAppSecretAuthentication(ServiceRoute route, string path, } else { - result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; + result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; isSuccess = false; - } + } + } + else + { + result = new ServiceResult { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; + isSuccess = false; + } return isSuccess; } diff --git a/src/Surging.ApiGateway/Dockerfile b/src/Surging.ApiGateway/Dockerfile deleted file mode 100644 index 677f91242..000000000 --- a/src/Surging.ApiGateway/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM microsoft/dotnet:2.1-runtime -WORKDIR /app -COPY . . -ENTRYPOINT ["dotnet", "Surging.ApiGateway.dll"] diff --git a/src/Surging.ApiGateway/Program.cs b/src/Surging.ApiGateway/Program.cs index 134669977..749a23653 100644 --- a/src/Surging.ApiGateway/Program.cs +++ b/src/Surging.ApiGateway/Program.cs @@ -2,6 +2,7 @@ using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Surging.Core.ApiGateWay; using Surging.Core.Codec.MessagePack; @@ -12,7 +13,6 @@ using Surging.Core.DotNetty; using Surging.Core.ProxyGenerator; using Surging.Core.ServiceHosting; -using Surging.Core.System.Intercept; using System; using System.IO; @@ -24,24 +24,13 @@ public class Program public static void Main(string[] args) { var host = new WebHostBuilder() - .UseUrls("http://*:729") - .UseKestrel(options => - { - options.Limits.MaxRequestBodySize = null; - options.Limits.MaxConcurrentConnections =100; - options.Limits.MaxConcurrentUpgradedConnections = 100; - options.Limits.MinRequestBodyDataRate = - new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10)); - options.Limits.MinResponseDataRate = - new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10)); - }) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseStartup() - .UseApplicationInsights() - .Build(); + .UseUrls("http://*:729") + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); host.Run(); - } } } diff --git a/src/Surging.ApiGateway/Startup.cs b/src/Surging.ApiGateway/Startup.cs index 5bef0a625..3e6c576d0 100644 --- a/src/Surging.ApiGateway/Startup.cs +++ b/src/Surging.ApiGateway/Startup.cs @@ -1,32 +1,37 @@ -using Autofac; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Autofac; using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Serialization; +using Surging.ApiGateway; +using Surging.Apm.Skywalking; +using Surging.Apm.Skywalking.Abstractions; using Surging.Core.ApiGateWay; using Surging.Core.ApiGateWay.Configurations; using Surging.Core.ApiGateWay.OAuth.Implementation.Configurations; +using Surging.Core.Caching; using Surging.Core.Caching.Configurations; using Surging.Core.Codec.MessagePack; using Surging.Core.Consul; using Surging.Core.Consul.Configurations; using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Cache; +using Surging.Core.CPlatform.Serialization.JsonConverters; using Surging.Core.CPlatform.Utilities; using Surging.Core.DotNetty; using Surging.Core.ProxyGenerator; -using Surging.Core.System.Intercept; using Surging.Core.Zookeeper; -//using Surging.Core.Zookeeper; -using ZookeeperConfigInfo = Surging.Core.Zookeeper.Configurations.ConfigInfo; -using System; using ApiGateWayConfig = Surging.Core.ApiGateWay.AppConfig; -using Surging.Core.Caching; -using Surging.Core.CPlatform.Cache; -using System.Linq; +using ZookeeperConfigInfo = Surging.Core.Zookeeper.Configurations.ConfigInfo; namespace Surging.ApiGateway { @@ -36,7 +41,7 @@ public class Startup public IContainer ApplicationContainer { get; private set; } - public Startup(IHostingEnvironment env) + public Startup(IWebHostEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) @@ -47,8 +52,11 @@ public Startup(IHostingEnvironment env) Configuration = builder.Build(); } + + // This method gets called by the runtime. Use this method to add services to the container. public IServiceProvider ConfigureServices(IServiceCollection services) { + services.AddControllersWithViews(); return RegisterAutofac(services); } @@ -57,26 +65,32 @@ private IServiceProvider RegisterAutofac(IServiceCollection services) var registerConfig = ApiGateWayConfig.Register; services.AddMvc(options => { options.Filters.Add(typeof(CustomExceptionFilterAttribute)); + options.EnableEndpointRouting = false; }).AddJsonOptions(options => { - options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; - options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + options.JsonSerializerOptions.PropertyNamingPolicy = null; + options.JsonSerializerOptions.DictionaryKeyPolicy = null; + }); + services.AddLogging(opt => + { + opt.AddConsole(); }); - services.AddLogging(); services.AddCors(); var builder = new ContainerBuilder(); - builder.Populate(services); + builder.Populate(services); builder.AddMicroService(option => { option.AddClient(); option.AddCache(); - option.AddClientIntercepted(typeof(CacheProviderInterceptor)); //option.UseZooKeeperManager(new ConfigInfo("127.0.0.1:2181")); - if(registerConfig.Provider== RegisterProvider.Consul) - option.UseConsulManager(new ConfigInfo(registerConfig.Address,enableChildrenMonitor:true)); - else if(registerConfig.Provider == RegisterProvider.Zookeeper) + if (registerConfig.Provider == RegisterProvider.Consul) + option.UseConsulManager(new ConfigInfo(registerConfig.Address, enableChildrenMonitor: false)); + else if (registerConfig.Provider == RegisterProvider.Zookeeper) option.UseZooKeeperManager(new ZookeeperConfigInfo(registerConfig.Address, enableChildrenMonitor: true)); option.UseDotNettyTransport(); option.AddApiGateWay(); + option.AddRpcTransportDiagnostic(); + option.UseSkywalking(); option.AddFilter(new ServiceExceptionFilter()); //option.UseProtoBufferCodec(); option.UseMessagePackCodec(); @@ -86,15 +100,26 @@ private IServiceProvider RegisterAutofac(IServiceCollection services) return new AutofacServiceProvider(ServiceLocator.Current); } - - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - loggerFactory.AddConsole(); + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } var serviceCacheProvider = ServiceLocator.Current.Resolve(); var addressDescriptors = serviceCacheProvider.GetServiceCaches().ToList(); + ServiceLocator.Current.Resolve(); ServiceLocator.Current.Resolve().SetCachesAsync(addressDescriptors); ServiceLocator.Current.Resolve(); - + ServiceLocator.Current.Resolve().StartAsync(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); @@ -105,8 +130,9 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF } app.UseCors(builder => { - var policy = Core.ApiGateWay.AppConfig.Policy; - builder.WithOrigins(policy.Origins); + var policy = Surging.Core.ApiGateWay.AppConfig.Policy; + if (policy.Origins != null) + builder.WithOrigins(policy.Origins); if (policy.AllowAnyHeader) builder.AllowAnyHeader(); if (policy.AllowAnyMethod) @@ -131,6 +157,19 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF "{*path}", new { controller = "Services", action = "Path" }); }); + app.UseHttpsRedirection(); + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); } } -} \ No newline at end of file +} diff --git a/src/Surging.ApiGateway/Surging.ApiGateway.csproj b/src/Surging.ApiGateway/Surging.ApiGateway.csproj index 1ddd427d4..527d3b1b9 100644 --- a/src/Surging.ApiGateway/Surging.ApiGateway.csproj +++ b/src/Surging.ApiGateway/Surging.ApiGateway.csproj @@ -1,46 +1,13 @@ - + - netcoreapp2.1 - true - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - aspnet-Surging.ApiGateway-147A234E-A922-4E6A-89B8-DCC64AEA96EE - false - 0.4.8 - fanly - surging Micro Service Framework - - surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec - Copyright © fanly All Rights Reserved. - https://github.com/dotnetcore/surging/blob/master/LICENSE - https://github.com/dotnetcore/surging - MicroService surging - ..\docker-compose.dcproj + net6.0 + - - - - - - - - - - - - - - - - - - - - - - + + @@ -50,20 +17,13 @@ - + - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - + + diff --git a/src/Surging.ApiGateway/Views/AuthenticationManage/EditServiceToken.cshtml b/src/Surging.ApiGateway/Views/AuthenticationManage/EditServiceToken.cshtml index 96c2c89ce..2f290af02 100644 --- a/src/Surging.ApiGateway/Views/AuthenticationManage/EditServiceToken.cshtml +++ b/src/Surging.ApiGateway/Views/AuthenticationManage/EditServiceToken.cshtml @@ -14,7 +14,7 @@
- @Html.TextBoxFor(p => ((IpAddressModel)p.Address).Token, new {autocomplete = "off", placeholder = "令牌", @class = "form-control" }) + @Html.TextBoxFor(p => ((IpAddressModel)p.Address), new {autocomplete = "off", placeholder = "令牌", @class = "form-control" })
diff --git a/src/Surging.ApiGateway/Views/ServiceManage/EditFaultTolerant.cshtml b/src/Surging.ApiGateway/Views/ServiceManage/EditFaultTolerant.cshtml index 769e535fa..e8e5395c2 100644 --- a/src/Surging.ApiGateway/Views/ServiceManage/EditFaultTolerant.cshtml +++ b/src/Surging.ApiGateway/Views/ServiceManage/EditFaultTolerant.cshtml @@ -35,13 +35,6 @@ @Html.TextBoxFor(p => p.ExecutionTimeoutInMilliseconds, new { autocomplete = "off", placeholder = "超时时间", @class = "form-control" }) -
- -
- @Html.RadioButtonFor(p => p.RequestCacheEnabled, true, new { name = "RequestCacheEnabled" }) - @Html.RadioButtonFor(p => p.RequestCacheEnabled, false, new { name = "RequestCacheEnabled" }) -
-
diff --git a/src/Surging.ApiGateway/Views/ServiceManage/FaultTolerant.cshtml b/src/Surging.ApiGateway/Views/ServiceManage/FaultTolerant.cshtml index 415b5d49c..070dd4fe5 100644 --- a/src/Surging.ApiGateway/Views/ServiceManage/FaultTolerant.cshtml +++ b/src/Surging.ApiGateway/Views/ServiceManage/FaultTolerant.cshtml @@ -43,7 +43,6 @@ 强制熔断 容错策略 超时时间 - 开启缓存 回退实例名 注入脚本 命名空间 diff --git a/src/Surging.ApiGateway/Views/ServiceManage/Index.cshtml b/src/Surging.ApiGateway/Views/ServiceManage/Index.cshtml index 8ff1ac96f..17cdedd8f 100644 --- a/src/Surging.ApiGateway/Views/ServiceManage/Index.cshtml +++ b/src/Surging.ApiGateway/Views/ServiceManage/Index.cshtml @@ -1,6 +1,6 @@  @{ - ViewBag.Title = "服务管理"; + ViewBag.Title = "注册中心"; var isPjax = (!string.IsNullOrEmpty(Context.Request.Query["XPJAX"]) && bool.Parse(Context.Request.Query["XPJAX"])) && (!string.IsNullOrEmpty(Context.Request.Headers["X-PJAX"]) && bool.Parse(Context.Request.Headers["X-PJAX"])) ; Layout = isPjax ? null : "_ServiceManageLayout.cshtml"; @@ -53,7 +53,7 @@ @section SubFootJS { + } +} +else +{ + +} diff --git a/src/Surging.ApiGateway/appsettings.Development.json b/src/Surging.ApiGateway/appsettings.Development.json new file mode 100644 index 000000000..8983e0fc1 --- /dev/null +++ b/src/Surging.ApiGateway/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/Surging.ApiGateway/appsettings.json b/src/Surging.ApiGateway/appsettings.json new file mode 100644 index 000000000..d9d9a9bff --- /dev/null +++ b/src/Surging.ApiGateway/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/src/Surging.ApiGateway/skyapm.json b/src/Surging.ApiGateway/skyapm.json new file mode 100644 index 000000000..cf0547ac2 --- /dev/null +++ b/src/Surging.ApiGateway/skyapm.json @@ -0,0 +1,29 @@ +{ + "SkyWalking": { + "ServiceName": "Surging.ApiGateway", + "Namespace": "", + "HeaderVersions": [ + "sw6" + ], + "Sampling": { + "SamplePer3Secs": -1, + "Percentage": -1.0 + }, + "Logging": { + "Level": "Information", + "FilePath": "logs/skyapm-{Date}.log" + }, + "Transport": { + "Interval": 3000, + "ProtocolVersion": "v6", + "QueueSize": 30000, + "BatchSize": 3000, + "gRPC": { + "Servers": "localhost:11800", + "Timeout": 100000, + "ConnectTimeout": 100000, + "ReportTimeout": 600000 + } + } + } +} \ No newline at end of file diff --git a/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/url.config.js b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/url.config.js index 9c0b3c655..8df6e9c25 100644 --- a/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/url.config.js +++ b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/url.config.js @@ -10,6 +10,7 @@ EDIT_FAULTTOLERANT: "/ServiceManage/EditFaultTolerant", GET_CACHEENDPOINT: "/ServiceManage/GetCacheEndpoint", EDIT_CACHEENDPOINT: "/ServiceManage/EditCacheEndpoint", - DEL_CACHEENDPOINT:"/ServiceManage/DelCacheEndpoint" + DEL_CACHEENDPOINT: "/ServiceManage/DelCacheEndpoint", + GET_REGISTERADDRESS: "/ServiceManage/GetRegisterAddress" } }); diff --git a/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/view/register.guide.js b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/view/register.guide.js new file mode 100644 index 000000000..d910bc99e --- /dev/null +++ b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/js/view/register.guide.js @@ -0,0 +1,47 @@ +define(function (require, exports, module) { + var $ = jQuery = require('jquery'); + require('jquerytmpl'); + var def = { + wrap: "#dataService tbody", + btnSearch: "#btnSearch", + queryParam: "#queryParam" + }; + var config = require('../url.config.js'); + var serviceaddress = function (options) { + var defaults = { + servicemanage_tpl: require("../../templates/registermanage_template.tpl") + }; + var self = this; + this.opts = $.extend(defaults, options || {}); + }; + serviceaddress.prototype = { + init: function () { + var self = this; + self.initEvent(); + self.loadData(); + + }, + initEvent: function () { + var self = this; + $(def.btnSearch).off("click").bind("click", function () { + self.loadData($(def.queryParam).val()); + }); + }, + loadData: function (condition) { + var self = this; + $.when( + $.post(config.GET_REGISTERADDRESS, { QueryParam: condition })) + .then(function (data) { + if (data.IsSucceed) { + var tpl = $.tmpl(self.opts.servicemanage_tpl, data); + $(def.wrap).html(tpl); + } + }); + } + }; + exports.init = function (options) { + var obj = new serviceaddress(options); + obj.init(); + }; + +}); \ No newline at end of file diff --git a/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/faulttolerant_template.tpl b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/faulttolerant_template.tpl index 291401ec8..b3cfaade2 100644 --- a/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/faulttolerant_template.tpl +++ b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/faulttolerant_template.tpl @@ -18,14 +18,7 @@ ${Strategy} - ${ExecutionTimeoutInMilliseconds} - - {{if RequestCacheEnabled==true }} - - {{else}} - - {{/if}} - + ${ExecutionTimeoutInMilliseconds} ${FallBackName} ${Injection} ${InjectionNamespaces} diff --git a/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/registermanage_template.tpl b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/registermanage_template.tpl new file mode 100644 index 000000000..e2a205bcb --- /dev/null +++ b/src/Surging.ApiGateway/wwwroot/apps/servicemange/assets/templates/registermanage_template.tpl @@ -0,0 +1,27 @@ + {{each Entity}} + + + {{if ($index+1)%2==1 }} + ${$index+1} + {{else}} + ${$index+1} + {{/if}} + + {{= [Address.Ip,Address.Port].join(":")}} + 已启动 + + {{if IsHealth==true }} + 正常 + {{else}} + 异常 + {{/if}} + + + + + {{/each}} \ No newline at end of file diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj new file mode 100644 index 000000000..9f073f38a --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/SkyApm.Transport.Grpc.Protocol.csproj @@ -0,0 +1,30 @@ + + + + + $(Product) gRPC data transmitter. + $(PackagePrefix).Transport.Grpc.Protocol + SkyApm.Transport.Grpc.Protocol + $(PackagePrefix).Transport.Grpc.Protocol + SkyWalking;Grpc + + + netstandard2.0 + SkyApm.Transport.Grpc.Protocol + + + + + + + + + + + + + + true + true + + diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ApplicationRegisterService.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ApplicationRegisterService.cs new file mode 100644 index 000000000..fa74e2c9a --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ApplicationRegisterService.cs @@ -0,0 +1,315 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/ApplicationRegisterService.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/ApplicationRegisterService.proto + public static partial class ApplicationRegisterServiceReflection { + + #region Descriptor + /// File descriptor for language-agent/ApplicationRegisterService.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static ApplicationRegisterServiceReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Ci9sYW5ndWFnZS1hZ2VudC9BcHBsaWNhdGlvblJlZ2lzdGVyU2VydmljZS5w", + "cm90bxoobGFuZ3VhZ2UtYWdlbnQvS2V5V2l0aEludGVnZXJWYWx1ZS5wcm90", + "byImCgtBcHBsaWNhdGlvbhIXCg9hcHBsaWNhdGlvbkNvZGUYASABKAkiPwoS", + "QXBwbGljYXRpb25NYXBwaW5nEikKC2FwcGxpY2F0aW9uGAEgASgLMhQuS2V5", + "V2l0aEludGVnZXJWYWx1ZTJcChpBcHBsaWNhdGlvblJlZ2lzdGVyU2Vydmlj", + "ZRI+ChdhcHBsaWNhdGlvbkNvZGVSZWdpc3RlchIMLkFwcGxpY2F0aW9uGhMu", + "QXBwbGljYXRpb25NYXBwaW5nIgBCUQowb3JnLmFwYWNoZS5za3l3YWxraW5n", + "LmFwbS5uZXR3b3JrLmxhbmd1YWdlLmFnZW50UAGqAhpTa3lXYWxraW5nLk5l", + "dHdvcmtQcm90b2NvbGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.KeyWithIntegerValueReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Application), global::SkyWalking.NetworkProtocol.Application.Parser, new[]{ "ApplicationCode" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ApplicationMapping), global::SkyWalking.NetworkProtocol.ApplicationMapping.Parser, new[]{ "Application" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class Application : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Application()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.ApplicationRegisterServiceReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Application() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Application(Application other) : this() { + applicationCode_ = other.applicationCode_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Application Clone() { + return new Application(this); + } + + /// Field number for the "applicationCode" field. + public const int ApplicationCodeFieldNumber = 1; + private string applicationCode_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ApplicationCode { + get { return applicationCode_; } + set { + applicationCode_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Application); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Application other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ApplicationCode != other.ApplicationCode) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ApplicationCode.Length != 0) hash ^= ApplicationCode.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ApplicationCode.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ApplicationCode); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ApplicationCode.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ApplicationCode); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Application other) { + if (other == null) { + return; + } + if (other.ApplicationCode.Length != 0) { + ApplicationCode = other.ApplicationCode; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + ApplicationCode = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class ApplicationMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ApplicationMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.ApplicationRegisterServiceReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationMapping(ApplicationMapping other) : this() { + application_ = other.application_ != null ? other.application_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationMapping Clone() { + return new ApplicationMapping(this); + } + + /// Field number for the "application" field. + public const int ApplicationFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.KeyWithIntegerValue application_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.KeyWithIntegerValue Application { + get { return application_; } + set { + application_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ApplicationMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ApplicationMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Application, other.Application)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (application_ != null) hash ^= Application.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (application_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Application); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (application_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Application); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ApplicationMapping other) { + if (other == null) { + return; + } + if (other.application_ != null) { + if (application_ == null) { + Application = new global::SkyWalking.NetworkProtocol.KeyWithIntegerValue(); + } + Application.MergeFrom(other.Application); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (application_ == null) { + Application = new global::SkyWalking.NetworkProtocol.KeyWithIntegerValue(); + } + input.ReadMessage(Application); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ApplicationRegisterServiceGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ApplicationRegisterServiceGrpc.cs new file mode 100644 index 000000000..4ab50cd94 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ApplicationRegisterServiceGrpc.cs @@ -0,0 +1,128 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/ApplicationRegisterService.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + /// + ///register service for ApplicationCode, this service is called when service starts. + /// + public static partial class ApplicationRegisterService + { + static readonly string __ServiceName = "ApplicationRegisterService"; + + static readonly grpc::Marshaller __Marshaller_Application = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Application.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ApplicationMapping = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ApplicationMapping.Parser.ParseFrom); + + static readonly grpc::Method __Method_applicationCodeRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "applicationCodeRegister", + __Marshaller_Application, + __Marshaller_ApplicationMapping); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.ApplicationRegisterServiceReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of ApplicationRegisterService + [grpc::BindServiceMethod(typeof(ApplicationRegisterService), "BindService")] + public abstract partial class ApplicationRegisterServiceBase + { + public virtual global::System.Threading.Tasks.Task applicationCodeRegister(global::SkyWalking.NetworkProtocol.Application request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for ApplicationRegisterService + public partial class ApplicationRegisterServiceClient : grpc::ClientBase + { + /// Creates a new client for ApplicationRegisterService + /// The channel to use to make remote calls. + public ApplicationRegisterServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for ApplicationRegisterService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public ApplicationRegisterServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected ApplicationRegisterServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected ApplicationRegisterServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.ApplicationMapping applicationCodeRegister(global::SkyWalking.NetworkProtocol.Application request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return applicationCodeRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.ApplicationMapping applicationCodeRegister(global::SkyWalking.NetworkProtocol.Application request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_applicationCodeRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall applicationCodeRegisterAsync(global::SkyWalking.NetworkProtocol.Application request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return applicationCodeRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall applicationCodeRegisterAsync(global::SkyWalking.NetworkProtocol.Application request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_applicationCodeRegister, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override ApplicationRegisterServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new ApplicationRegisterServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(ApplicationRegisterServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_applicationCodeRegister, serviceImpl.applicationCodeRegister).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, ApplicationRegisterServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_applicationCodeRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.applicationCodeRegister)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLR.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLR.cs new file mode 100644 index 000000000..3fd962a6d --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLR.cs @@ -0,0 +1,711 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: common/CLR.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from common/CLR.proto + public static partial class CLRReflection { + + #region Descriptor + /// File descriptor for common/CLR.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static CLRReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChBjb21tb24vQ0xSLnByb3RvGhNjb21tb24vY29tbW9uLnByb3RvIlwKCUNM", + "Uk1ldHJpYxIMCgR0aW1lGAEgASgDEhEKA2NwdRgCIAEoCzIELkNQVRISCgJn", + "YxgDIAEoCzIGLkNsckdDEhoKBnRocmVhZBgEIAEoCzIKLkNsclRocmVhZCJp", + "CgVDbHJHQxIYChBHZW4wQ29sbGVjdENvdW50GAEgASgDEhgKEEdlbjFDb2xs", + "ZWN0Q291bnQYAiABKAMSGAoQR2VuMkNvbGxlY3RDb3VudBgDIAEoAxISCgpI", + "ZWFwTWVtb3J5GAQgASgDIo8BCglDbHJUaHJlYWQSJgoeQXZhaWxhYmxlQ29t", + "cGxldGlvblBvcnRUaHJlYWRzGAEgASgFEh4KFkF2YWlsYWJsZVdvcmtlclRo", + "cmVhZHMYAiABKAUSIAoYTWF4Q29tcGxldGlvblBvcnRUaHJlYWRzGAMgASgF", + "EhgKEE1heFdvcmtlclRocmVhZHMYBCABKAVCUQowb3JnLmFwYWNoZS5za3l3", + "YWxraW5nLmFwbS5uZXR3b3JrLmxhbmd1YWdlLmFnZW50UAGqAhpTa3lXYWxr", + "aW5nLk5ldHdvcmtQcm90b2NvbGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.CLRMetric), global::SkyWalking.NetworkProtocol.CLRMetric.Parser, new[]{ "Time", "Cpu", "Gc", "Thread" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ClrGC), global::SkyWalking.NetworkProtocol.ClrGC.Parser, new[]{ "Gen0CollectCount", "Gen1CollectCount", "Gen2CollectCount", "HeapMemory" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ClrThread), global::SkyWalking.NetworkProtocol.ClrThread.Parser, new[]{ "AvailableCompletionPortThreads", "AvailableWorkerThreads", "MaxCompletionPortThreads", "MaxWorkerThreads" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class CLRMetric : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CLRMetric()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CLRReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CLRMetric() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CLRMetric(CLRMetric other) : this() { + time_ = other.time_; + cpu_ = other.cpu_ != null ? other.cpu_.Clone() : null; + gc_ = other.gc_ != null ? other.gc_.Clone() : null; + thread_ = other.thread_ != null ? other.thread_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CLRMetric Clone() { + return new CLRMetric(this); + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 1; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "cpu" field. + public const int CpuFieldNumber = 2; + private global::SkyWalking.NetworkProtocol.CPU cpu_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.CPU Cpu { + get { return cpu_; } + set { + cpu_ = value; + } + } + + /// Field number for the "gc" field. + public const int GcFieldNumber = 3; + private global::SkyWalking.NetworkProtocol.ClrGC gc_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.ClrGC Gc { + get { return gc_; } + set { + gc_ = value; + } + } + + /// Field number for the "thread" field. + public const int ThreadFieldNumber = 4; + private global::SkyWalking.NetworkProtocol.ClrThread thread_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.ClrThread Thread { + get { return thread_; } + set { + thread_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CLRMetric); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CLRMetric other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Time != other.Time) return false; + if (!object.Equals(Cpu, other.Cpu)) return false; + if (!object.Equals(Gc, other.Gc)) return false; + if (!object.Equals(Thread, other.Thread)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Time != 0L) hash ^= Time.GetHashCode(); + if (cpu_ != null) hash ^= Cpu.GetHashCode(); + if (gc_ != null) hash ^= Gc.GetHashCode(); + if (thread_ != null) hash ^= Thread.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Time != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Time); + } + if (cpu_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Cpu); + } + if (gc_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Gc); + } + if (thread_ != null) { + output.WriteRawTag(34); + output.WriteMessage(Thread); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + if (cpu_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Cpu); + } + if (gc_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Gc); + } + if (thread_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Thread); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CLRMetric other) { + if (other == null) { + return; + } + if (other.Time != 0L) { + Time = other.Time; + } + if (other.cpu_ != null) { + if (cpu_ == null) { + Cpu = new global::SkyWalking.NetworkProtocol.CPU(); + } + Cpu.MergeFrom(other.Cpu); + } + if (other.gc_ != null) { + if (gc_ == null) { + Gc = new global::SkyWalking.NetworkProtocol.ClrGC(); + } + Gc.MergeFrom(other.Gc); + } + if (other.thread_ != null) { + if (thread_ == null) { + Thread = new global::SkyWalking.NetworkProtocol.ClrThread(); + } + Thread.MergeFrom(other.Thread); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Time = input.ReadInt64(); + break; + } + case 18: { + if (cpu_ == null) { + Cpu = new global::SkyWalking.NetworkProtocol.CPU(); + } + input.ReadMessage(Cpu); + break; + } + case 26: { + if (gc_ == null) { + Gc = new global::SkyWalking.NetworkProtocol.ClrGC(); + } + input.ReadMessage(Gc); + break; + } + case 34: { + if (thread_ == null) { + Thread = new global::SkyWalking.NetworkProtocol.ClrThread(); + } + input.ReadMessage(Thread); + break; + } + } + } + } + + } + + public sealed partial class ClrGC : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ClrGC()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CLRReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ClrGC() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ClrGC(ClrGC other) : this() { + gen0CollectCount_ = other.gen0CollectCount_; + gen1CollectCount_ = other.gen1CollectCount_; + gen2CollectCount_ = other.gen2CollectCount_; + heapMemory_ = other.heapMemory_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ClrGC Clone() { + return new ClrGC(this); + } + + /// Field number for the "Gen0CollectCount" field. + public const int Gen0CollectCountFieldNumber = 1; + private long gen0CollectCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Gen0CollectCount { + get { return gen0CollectCount_; } + set { + gen0CollectCount_ = value; + } + } + + /// Field number for the "Gen1CollectCount" field. + public const int Gen1CollectCountFieldNumber = 2; + private long gen1CollectCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Gen1CollectCount { + get { return gen1CollectCount_; } + set { + gen1CollectCount_ = value; + } + } + + /// Field number for the "Gen2CollectCount" field. + public const int Gen2CollectCountFieldNumber = 3; + private long gen2CollectCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Gen2CollectCount { + get { return gen2CollectCount_; } + set { + gen2CollectCount_ = value; + } + } + + /// Field number for the "HeapMemory" field. + public const int HeapMemoryFieldNumber = 4; + private long heapMemory_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long HeapMemory { + get { return heapMemory_; } + set { + heapMemory_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ClrGC); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ClrGC other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Gen0CollectCount != other.Gen0CollectCount) return false; + if (Gen1CollectCount != other.Gen1CollectCount) return false; + if (Gen2CollectCount != other.Gen2CollectCount) return false; + if (HeapMemory != other.HeapMemory) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Gen0CollectCount != 0L) hash ^= Gen0CollectCount.GetHashCode(); + if (Gen1CollectCount != 0L) hash ^= Gen1CollectCount.GetHashCode(); + if (Gen2CollectCount != 0L) hash ^= Gen2CollectCount.GetHashCode(); + if (HeapMemory != 0L) hash ^= HeapMemory.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Gen0CollectCount != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Gen0CollectCount); + } + if (Gen1CollectCount != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Gen1CollectCount); + } + if (Gen2CollectCount != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Gen2CollectCount); + } + if (HeapMemory != 0L) { + output.WriteRawTag(32); + output.WriteInt64(HeapMemory); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Gen0CollectCount != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Gen0CollectCount); + } + if (Gen1CollectCount != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Gen1CollectCount); + } + if (Gen2CollectCount != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Gen2CollectCount); + } + if (HeapMemory != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(HeapMemory); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ClrGC other) { + if (other == null) { + return; + } + if (other.Gen0CollectCount != 0L) { + Gen0CollectCount = other.Gen0CollectCount; + } + if (other.Gen1CollectCount != 0L) { + Gen1CollectCount = other.Gen1CollectCount; + } + if (other.Gen2CollectCount != 0L) { + Gen2CollectCount = other.Gen2CollectCount; + } + if (other.HeapMemory != 0L) { + HeapMemory = other.HeapMemory; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Gen0CollectCount = input.ReadInt64(); + break; + } + case 16: { + Gen1CollectCount = input.ReadInt64(); + break; + } + case 24: { + Gen2CollectCount = input.ReadInt64(); + break; + } + case 32: { + HeapMemory = input.ReadInt64(); + break; + } + } + } + } + + } + + public sealed partial class ClrThread : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ClrThread()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CLRReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ClrThread() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ClrThread(ClrThread other) : this() { + availableCompletionPortThreads_ = other.availableCompletionPortThreads_; + availableWorkerThreads_ = other.availableWorkerThreads_; + maxCompletionPortThreads_ = other.maxCompletionPortThreads_; + maxWorkerThreads_ = other.maxWorkerThreads_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ClrThread Clone() { + return new ClrThread(this); + } + + /// Field number for the "AvailableCompletionPortThreads" field. + public const int AvailableCompletionPortThreadsFieldNumber = 1; + private int availableCompletionPortThreads_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int AvailableCompletionPortThreads { + get { return availableCompletionPortThreads_; } + set { + availableCompletionPortThreads_ = value; + } + } + + /// Field number for the "AvailableWorkerThreads" field. + public const int AvailableWorkerThreadsFieldNumber = 2; + private int availableWorkerThreads_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int AvailableWorkerThreads { + get { return availableWorkerThreads_; } + set { + availableWorkerThreads_ = value; + } + } + + /// Field number for the "MaxCompletionPortThreads" field. + public const int MaxCompletionPortThreadsFieldNumber = 3; + private int maxCompletionPortThreads_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int MaxCompletionPortThreads { + get { return maxCompletionPortThreads_; } + set { + maxCompletionPortThreads_ = value; + } + } + + /// Field number for the "MaxWorkerThreads" field. + public const int MaxWorkerThreadsFieldNumber = 4; + private int maxWorkerThreads_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int MaxWorkerThreads { + get { return maxWorkerThreads_; } + set { + maxWorkerThreads_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ClrThread); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ClrThread other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (AvailableCompletionPortThreads != other.AvailableCompletionPortThreads) return false; + if (AvailableWorkerThreads != other.AvailableWorkerThreads) return false; + if (MaxCompletionPortThreads != other.MaxCompletionPortThreads) return false; + if (MaxWorkerThreads != other.MaxWorkerThreads) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (AvailableCompletionPortThreads != 0) hash ^= AvailableCompletionPortThreads.GetHashCode(); + if (AvailableWorkerThreads != 0) hash ^= AvailableWorkerThreads.GetHashCode(); + if (MaxCompletionPortThreads != 0) hash ^= MaxCompletionPortThreads.GetHashCode(); + if (MaxWorkerThreads != 0) hash ^= MaxWorkerThreads.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (AvailableCompletionPortThreads != 0) { + output.WriteRawTag(8); + output.WriteInt32(AvailableCompletionPortThreads); + } + if (AvailableWorkerThreads != 0) { + output.WriteRawTag(16); + output.WriteInt32(AvailableWorkerThreads); + } + if (MaxCompletionPortThreads != 0) { + output.WriteRawTag(24); + output.WriteInt32(MaxCompletionPortThreads); + } + if (MaxWorkerThreads != 0) { + output.WriteRawTag(32); + output.WriteInt32(MaxWorkerThreads); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (AvailableCompletionPortThreads != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(AvailableCompletionPortThreads); + } + if (AvailableWorkerThreads != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(AvailableWorkerThreads); + } + if (MaxCompletionPortThreads != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(MaxCompletionPortThreads); + } + if (MaxWorkerThreads != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(MaxWorkerThreads); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ClrThread other) { + if (other == null) { + return; + } + if (other.AvailableCompletionPortThreads != 0) { + AvailableCompletionPortThreads = other.AvailableCompletionPortThreads; + } + if (other.AvailableWorkerThreads != 0) { + AvailableWorkerThreads = other.AvailableWorkerThreads; + } + if (other.MaxCompletionPortThreads != 0) { + MaxCompletionPortThreads = other.MaxCompletionPortThreads; + } + if (other.MaxWorkerThreads != 0) { + MaxWorkerThreads = other.MaxWorkerThreads; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + AvailableCompletionPortThreads = input.ReadInt32(); + break; + } + case 16: { + AvailableWorkerThreads = input.ReadInt32(); + break; + } + case 24: { + MaxCompletionPortThreads = input.ReadInt32(); + break; + } + case 32: { + MaxWorkerThreads = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRMetric.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRMetric.cs new file mode 100644 index 000000000..b66cd9f6d --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRMetric.cs @@ -0,0 +1,198 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent-v2/CLRMetric.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent-v2/CLRMetric.proto + public static partial class CLRMetricReflection { + + #region Descriptor + /// File descriptor for language-agent-v2/CLRMetric.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static CLRMetricReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiFsYW5ndWFnZS1hZ2VudC12Mi9DTFJNZXRyaWMucHJvdG8aE2NvbW1vbi9j", + "b21tb24ucHJvdG8aEGNvbW1vbi9DTFIucHJvdG8iTQoTQ0xSTWV0cmljQ29s", + "bGVjdGlvbhIbCgdtZXRyaWNzGAEgAygLMgouQ0xSTWV0cmljEhkKEXNlcnZp", + "Y2VJbnN0YW5jZUlkGAIgASgFMkYKFkNMUk1ldHJpY1JlcG9ydFNlcnZpY2US", + "LAoHY29sbGVjdBIULkNMUk1ldHJpY0NvbGxlY3Rpb24aCS5Db21tYW5kcyIA", + "QlQKM29yZy5hcGFjaGUuc2t5d2Fsa2luZy5hcG0ubmV0d29yay5sYW5ndWFn", + "ZS5hZ2VudC52MlABqgIaU2t5V2Fsa2luZy5OZXR3b3JrUHJvdG9jb2xiBnBy", + "b3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, global::SkyWalking.NetworkProtocol.CLRReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.CLRMetricCollection), global::SkyWalking.NetworkProtocol.CLRMetricCollection.Parser, new[]{ "Metrics", "ServiceInstanceId" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class CLRMetricCollection : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CLRMetricCollection()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CLRMetricReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CLRMetricCollection() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CLRMetricCollection(CLRMetricCollection other) : this() { + metrics_ = other.metrics_.Clone(); + serviceInstanceId_ = other.serviceInstanceId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CLRMetricCollection Clone() { + return new CLRMetricCollection(this); + } + + /// Field number for the "metrics" field. + public const int MetricsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_metrics_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.CLRMetric.Parser); + private readonly pbc::RepeatedField metrics_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Metrics { + get { return metrics_; } + } + + /// Field number for the "serviceInstanceId" field. + public const int ServiceInstanceIdFieldNumber = 2; + private int serviceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceInstanceId { + get { return serviceInstanceId_; } + set { + serviceInstanceId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CLRMetricCollection); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CLRMetricCollection other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!metrics_.Equals(other.metrics_)) return false; + if (ServiceInstanceId != other.ServiceInstanceId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= metrics_.GetHashCode(); + if (ServiceInstanceId != 0) hash ^= ServiceInstanceId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + metrics_.WriteTo(output, _repeated_metrics_codec); + if (ServiceInstanceId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ServiceInstanceId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += metrics_.CalculateSize(_repeated_metrics_codec); + if (ServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceInstanceId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CLRMetricCollection other) { + if (other == null) { + return; + } + metrics_.Add(other.metrics_); + if (other.ServiceInstanceId != 0) { + ServiceInstanceId = other.ServiceInstanceId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + metrics_.AddEntriesFrom(input, _repeated_metrics_codec); + break; + } + case 16: { + ServiceInstanceId = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRMetricGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRMetricGrpc.cs new file mode 100644 index 000000000..3bc459309 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CLRMetricGrpc.cs @@ -0,0 +1,125 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent-v2/CLRMetric.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class CLRMetricReportService + { + static readonly string __ServiceName = "CLRMetricReportService"; + + static readonly grpc::Marshaller __Marshaller_CLRMetricCollection = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.CLRMetricCollection.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Commands = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Commands.Parser.ParseFrom); + + static readonly grpc::Method __Method_collect = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "collect", + __Marshaller_CLRMetricCollection, + __Marshaller_Commands); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.CLRMetricReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of CLRMetricReportService + [grpc::BindServiceMethod(typeof(CLRMetricReportService), "BindService")] + public abstract partial class CLRMetricReportServiceBase + { + public virtual global::System.Threading.Tasks.Task collect(global::SkyWalking.NetworkProtocol.CLRMetricCollection request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for CLRMetricReportService + public partial class CLRMetricReportServiceClient : grpc::ClientBase + { + /// Creates a new client for CLRMetricReportService + /// The channel to use to make remote calls. + public CLRMetricReportServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for CLRMetricReportService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public CLRMetricReportServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected CLRMetricReportServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected CLRMetricReportServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.Commands collect(global::SkyWalking.NetworkProtocol.CLRMetricCollection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collect(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.Commands collect(global::SkyWalking.NetworkProtocol.CLRMetricCollection request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_collect, null, options, request); + } + public virtual grpc::AsyncUnaryCall collectAsync(global::SkyWalking.NetworkProtocol.CLRMetricCollection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collectAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall collectAsync(global::SkyWalking.NetworkProtocol.CLRMetricCollection request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_collect, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override CLRMetricReportServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new CLRMetricReportServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(CLRMetricReportServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_collect, serviceImpl.collect).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, CLRMetricReportServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_collect, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.collect)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Common.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Common.cs new file mode 100644 index 000000000..7d77fdd4e --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Common.cs @@ -0,0 +1,781 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: common/common.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from common/common.proto + public static partial class CommonReflection { + + #region Descriptor + /// File descriptor for common/common.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static CommonReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChNjb21tb24vY29tbW9uLnByb3RvIjAKEktleVN0cmluZ1ZhbHVlUGFpchIL", + "CgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAkiLQoPS2V5SW50VmFsdWVQYWly", + "EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoBSIbCgNDUFUSFAoMdXNhZ2VQ", + "ZXJjZW50GAIgASgBIiYKCENvbW1hbmRzEhoKCGNvbW1hbmRzGAEgAygLMggu", + "Q29tbWFuZCI9CgdDb21tYW5kEg8KB2NvbW1hbmQYASABKAkSIQoEYXJncxgC", + "IAMoCzITLktleVN0cmluZ1ZhbHVlUGFpciowCgtEZXRlY3RQb2ludBIKCgZj", + "bGllbnQQABIKCgZzZXJ2ZXIQARIJCgVwcm94eRACQkkKKG9yZy5hcGFjaGUu", + "c2t5d2Fsa2luZy5hcG0ubmV0d29yay5jb21tb25QAaoCGlNreVdhbGtpbmcu", + "TmV0d29ya1Byb3RvY29sYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::SkyWalking.NetworkProtocol.DetectPoint), }, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.KeyStringValuePair), global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser, new[]{ "Key", "Value" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.KeyIntValuePair), global::SkyWalking.NetworkProtocol.KeyIntValuePair.Parser, new[]{ "Key", "Value" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.CPU), global::SkyWalking.NetworkProtocol.CPU.Parser, new[]{ "UsagePercent" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Commands), global::SkyWalking.NetworkProtocol.Commands.Parser, new[]{ "Commands_" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Command), global::SkyWalking.NetworkProtocol.Command.Parser, new[]{ "Command_", "Args" }, null, null, null) + })); + } + #endregion + + } + #region Enums + /// + /// In most cases, detect point should be `server` or `client`. + /// Even in service mesh, this means `server`/`client` side sidecar + /// `proxy` is reserved only. + /// + public enum DetectPoint { + [pbr::OriginalName("client")] Client = 0, + [pbr::OriginalName("server")] Server = 1, + [pbr::OriginalName("proxy")] Proxy = 2, + } + + #endregion + + #region Messages + public sealed partial class KeyStringValuePair : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KeyStringValuePair()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyStringValuePair() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyStringValuePair(KeyStringValuePair other) : this() { + key_ = other.key_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyStringValuePair Clone() { + return new KeyStringValuePair(this); + } + + /// Field number for the "key" field. + public const int KeyFieldNumber = 1; + private string key_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Key { + get { return key_; } + set { + key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 2; + private string value_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Value { + get { return value_; } + set { + value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as KeyStringValuePair); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(KeyStringValuePair other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Key != other.Key) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Key.Length != 0) hash ^= Key.GetHashCode(); + if (Value.Length != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Key.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Key); + } + if (Value.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Key.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); + } + if (Value.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(KeyStringValuePair other) { + if (other == null) { + return; + } + if (other.Key.Length != 0) { + Key = other.Key; + } + if (other.Value.Length != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Key = input.ReadString(); + break; + } + case 18: { + Value = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class KeyIntValuePair : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KeyIntValuePair()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyIntValuePair() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyIntValuePair(KeyIntValuePair other) : this() { + key_ = other.key_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyIntValuePair Clone() { + return new KeyIntValuePair(this); + } + + /// Field number for the "key" field. + public const int KeyFieldNumber = 1; + private string key_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Key { + get { return key_; } + set { + key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 2; + private int value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as KeyIntValuePair); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(KeyIntValuePair other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Key != other.Key) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Key.Length != 0) hash ^= Key.GetHashCode(); + if (Value != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Key.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Key); + } + if (Value != 0) { + output.WriteRawTag(16); + output.WriteInt32(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Key.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); + } + if (Value != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(KeyIntValuePair other) { + if (other == null) { + return; + } + if (other.Key.Length != 0) { + Key = other.Key; + } + if (other.Value != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Key = input.ReadString(); + break; + } + case 16: { + Value = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class CPU : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CPU()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CPU() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CPU(CPU other) : this() { + usagePercent_ = other.usagePercent_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CPU Clone() { + return new CPU(this); + } + + /// Field number for the "usagePercent" field. + public const int UsagePercentFieldNumber = 2; + private double usagePercent_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double UsagePercent { + get { return usagePercent_; } + set { + usagePercent_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CPU); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CPU other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(UsagePercent, other.UsagePercent)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (UsagePercent != 0D) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(UsagePercent); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (UsagePercent != 0D) { + output.WriteRawTag(17); + output.WriteDouble(UsagePercent); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (UsagePercent != 0D) { + size += 1 + 8; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CPU other) { + if (other == null) { + return; + } + if (other.UsagePercent != 0D) { + UsagePercent = other.UsagePercent; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 17: { + UsagePercent = input.ReadDouble(); + break; + } + } + } + } + + } + + public sealed partial class Commands : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Commands()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Commands() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Commands(Commands other) : this() { + commands_ = other.commands_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Commands Clone() { + return new Commands(this); + } + + /// Field number for the "commands" field. + public const int Commands_FieldNumber = 1; + private static readonly pb::FieldCodec _repeated_commands_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.Command.Parser); + private readonly pbc::RepeatedField commands_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Commands_ { + get { return commands_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Commands); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Commands other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!commands_.Equals(other.commands_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= commands_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + commands_.WriteTo(output, _repeated_commands_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += commands_.CalculateSize(_repeated_commands_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Commands other) { + if (other == null) { + return; + } + commands_.Add(other.commands_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + commands_.AddEntriesFrom(input, _repeated_commands_codec); + break; + } + } + } + } + + } + + public sealed partial class Command : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Command()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Command() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Command(Command other) : this() { + command_ = other.command_; + args_ = other.args_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Command Clone() { + return new Command(this); + } + + /// Field number for the "command" field. + public const int Command_FieldNumber = 1; + private string command_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Command_ { + get { return command_; } + set { + command_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "args" field. + public const int ArgsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_args_codec + = pb::FieldCodec.ForMessage(18, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField args_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Args { + get { return args_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Command); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Command other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Command_ != other.Command_) return false; + if(!args_.Equals(other.args_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Command_.Length != 0) hash ^= Command_.GetHashCode(); + hash ^= args_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Command_.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Command_); + } + args_.WriteTo(output, _repeated_args_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Command_.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Command_); + } + size += args_.CalculateSize(_repeated_args_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Command other) { + if (other == null) { + return; + } + if (other.Command_.Length != 0) { + Command_ = other.Command_; + } + args_.Add(other.args_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Command_ = input.ReadString(); + break; + } + case 18: { + args_.AddEntriesFrom(input, _repeated_args_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CommonGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/CommonGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DiscoveryService.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DiscoveryService.cs new file mode 100644 index 000000000..086bc9978 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DiscoveryService.cs @@ -0,0 +1,1625 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/DiscoveryService.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/DiscoveryService.proto + public static partial class DiscoveryServiceReflection { + + #region Descriptor + /// File descriptor for language-agent/DiscoveryService.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static DiscoveryServiceReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiVsYW5ndWFnZS1hZ2VudC9EaXNjb3ZlcnlTZXJ2aWNlLnByb3RvGh9sYW5n", + "dWFnZS1hZ2VudC9Eb3duc3RyZWFtLnByb3RvGhljb21tb24vdHJhY2UtY29t", + "bW9uLnByb3RvIm4KE0FwcGxpY2F0aW9uSW5zdGFuY2USFQoNYXBwbGljYXRp", + "b25JZBgBIAEoBRIRCglhZ2VudFVVSUQYAiABKAkSFAoMcmVnaXN0ZXJUaW1l", + "GAMgASgDEhcKBm9zaW5mbxgEIAEoCzIHLk9TSW5mbyJSChpBcHBsaWNhdGlv", + "bkluc3RhbmNlTWFwcGluZxIVCg1hcHBsaWNhdGlvbklkGAEgASgFEh0KFWFw", + "cGxpY2F0aW9uSW5zdGFuY2VJZBgCIAEoBSKBAQoaQXBwbGljYXRpb25JbnN0", + "YW5jZVJlY292ZXISFQoNYXBwbGljYXRpb25JZBgBIAEoBRIdChVhcHBsaWNh", + "dGlvbkluc3RhbmNlSWQYAiABKAUSFAoMcmVnaXN0ZXJUaW1lGAMgASgDEhcK", + "Bm9zaW5mbxgEIAEoCzIHLk9TSW5mbyJUChxBcHBsaWNhdGlvbkluc3RhbmNl", + "SGVhcnRiZWF0Eh0KFWFwcGxpY2F0aW9uSW5zdGFuY2VJZBgBIAEoBRIVCg1o", + "ZWFydGJlYXRUaW1lGAIgASgDIkwKBk9TSW5mbxIOCgZvc05hbWUYASABKAkS", + "EAoIaG9zdG5hbWUYAiABKAkSEQoJcHJvY2Vzc05vGAMgASgFEg0KBWlwdjRz", + "GAQgAygJIj4KFVNlcnZpY2VOYW1lQ29sbGVjdGlvbhIlCghlbGVtZW50cxgB", + "IAMoCzITLlNlcnZpY2VOYW1lRWxlbWVudCJMChxTZXJ2aWNlTmFtZU1hcHBp", + "bmdDb2xsZWN0aW9uEiwKCGVsZW1lbnRzGAEgAygLMhouU2VydmljZU5hbWVN", + "YXBwaW5nRWxlbWVudCJUChlTZXJ2aWNlTmFtZU1hcHBpbmdFbGVtZW50EhEK", + "CXNlcnZpY2VJZBgBIAEoBRIkCgdlbGVtZW50GAIgASgLMhMuU2VydmljZU5h", + "bWVFbGVtZW50ImAKElNlcnZpY2VOYW1lRWxlbWVudBITCgtzZXJ2aWNlTmFt", + "ZRgBIAEoCRIVCg1hcHBsaWNhdGlvbklkGAIgASgFEh4KC3NyY1NwYW5UeXBl", + "GAMgASgOMgkuU3BhblR5cGUyngEKGEluc3RhbmNlRGlzY292ZXJ5U2Vydmlj", + "ZRJHChByZWdpc3Rlckluc3RhbmNlEhQuQXBwbGljYXRpb25JbnN0YW5jZRob", + "LkFwcGxpY2F0aW9uSW5zdGFuY2VNYXBwaW5nIgASOQoJaGVhcnRiZWF0Eh0u", + "QXBwbGljYXRpb25JbnN0YW5jZUhlYXJ0YmVhdBoLLkRvd25zdHJlYW0iADJj", + "ChtTZXJ2aWNlTmFtZURpc2NvdmVyeVNlcnZpY2USRAoJZGlzY292ZXJ5EhYu", + "U2VydmljZU5hbWVDb2xsZWN0aW9uGh0uU2VydmljZU5hbWVNYXBwaW5nQ29s", + "bGVjdGlvbiIAQlEKMG9yZy5hcGFjaGUuc2t5d2Fsa2luZy5hcG0ubmV0d29y", + "ay5sYW5ndWFnZS5hZ2VudFABqgIaU2t5V2Fsa2luZy5OZXR3b3JrUHJvdG9j", + "b2xiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.DownstreamReflection.Descriptor, global::SkyWalking.NetworkProtocol.TraceCommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ApplicationInstance), global::SkyWalking.NetworkProtocol.ApplicationInstance.Parser, new[]{ "ApplicationId", "AgentUUID", "RegisterTime", "Osinfo" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ApplicationInstanceMapping), global::SkyWalking.NetworkProtocol.ApplicationInstanceMapping.Parser, new[]{ "ApplicationId", "ApplicationInstanceId" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ApplicationInstanceRecover), global::SkyWalking.NetworkProtocol.ApplicationInstanceRecover.Parser, new[]{ "ApplicationId", "ApplicationInstanceId", "RegisterTime", "Osinfo" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat), global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat.Parser, new[]{ "ApplicationInstanceId", "HeartbeatTime" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.OSInfo), global::SkyWalking.NetworkProtocol.OSInfo.Parser, new[]{ "OsName", "Hostname", "ProcessNo", "Ipv4S" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceNameCollection), global::SkyWalking.NetworkProtocol.ServiceNameCollection.Parser, new[]{ "Elements" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceNameMappingCollection), global::SkyWalking.NetworkProtocol.ServiceNameMappingCollection.Parser, new[]{ "Elements" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceNameMappingElement), global::SkyWalking.NetworkProtocol.ServiceNameMappingElement.Parser, new[]{ "ServiceId", "Element" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceNameElement), global::SkyWalking.NetworkProtocol.ServiceNameElement.Parser, new[]{ "ServiceName", "ApplicationId", "SrcSpanType" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class ApplicationInstance : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ApplicationInstance()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstance() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstance(ApplicationInstance other) : this() { + applicationId_ = other.applicationId_; + agentUUID_ = other.agentUUID_; + registerTime_ = other.registerTime_; + osinfo_ = other.osinfo_ != null ? other.osinfo_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstance Clone() { + return new ApplicationInstance(this); + } + + /// Field number for the "applicationId" field. + public const int ApplicationIdFieldNumber = 1; + private int applicationId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationId { + get { return applicationId_; } + set { + applicationId_ = value; + } + } + + /// Field number for the "agentUUID" field. + public const int AgentUUIDFieldNumber = 2; + private string agentUUID_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AgentUUID { + get { return agentUUID_; } + set { + agentUUID_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "registerTime" field. + public const int RegisterTimeFieldNumber = 3; + private long registerTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long RegisterTime { + get { return registerTime_; } + set { + registerTime_ = value; + } + } + + /// Field number for the "osinfo" field. + public const int OsinfoFieldNumber = 4; + private global::SkyWalking.NetworkProtocol.OSInfo osinfo_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.OSInfo Osinfo { + get { return osinfo_; } + set { + osinfo_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ApplicationInstance); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ApplicationInstance other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ApplicationId != other.ApplicationId) return false; + if (AgentUUID != other.AgentUUID) return false; + if (RegisterTime != other.RegisterTime) return false; + if (!object.Equals(Osinfo, other.Osinfo)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ApplicationId != 0) hash ^= ApplicationId.GetHashCode(); + if (AgentUUID.Length != 0) hash ^= AgentUUID.GetHashCode(); + if (RegisterTime != 0L) hash ^= RegisterTime.GetHashCode(); + if (osinfo_ != null) hash ^= Osinfo.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ApplicationId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ApplicationId); + } + if (AgentUUID.Length != 0) { + output.WriteRawTag(18); + output.WriteString(AgentUUID); + } + if (RegisterTime != 0L) { + output.WriteRawTag(24); + output.WriteInt64(RegisterTime); + } + if (osinfo_ != null) { + output.WriteRawTag(34); + output.WriteMessage(Osinfo); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ApplicationId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationId); + } + if (AgentUUID.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AgentUUID); + } + if (RegisterTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(RegisterTime); + } + if (osinfo_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Osinfo); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ApplicationInstance other) { + if (other == null) { + return; + } + if (other.ApplicationId != 0) { + ApplicationId = other.ApplicationId; + } + if (other.AgentUUID.Length != 0) { + AgentUUID = other.AgentUUID; + } + if (other.RegisterTime != 0L) { + RegisterTime = other.RegisterTime; + } + if (other.osinfo_ != null) { + if (osinfo_ == null) { + Osinfo = new global::SkyWalking.NetworkProtocol.OSInfo(); + } + Osinfo.MergeFrom(other.Osinfo); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ApplicationId = input.ReadInt32(); + break; + } + case 18: { + AgentUUID = input.ReadString(); + break; + } + case 24: { + RegisterTime = input.ReadInt64(); + break; + } + case 34: { + if (osinfo_ == null) { + Osinfo = new global::SkyWalking.NetworkProtocol.OSInfo(); + } + input.ReadMessage(Osinfo); + break; + } + } + } + } + + } + + public sealed partial class ApplicationInstanceMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ApplicationInstanceMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceMapping(ApplicationInstanceMapping other) : this() { + applicationId_ = other.applicationId_; + applicationInstanceId_ = other.applicationInstanceId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceMapping Clone() { + return new ApplicationInstanceMapping(this); + } + + /// Field number for the "applicationId" field. + public const int ApplicationIdFieldNumber = 1; + private int applicationId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationId { + get { return applicationId_; } + set { + applicationId_ = value; + } + } + + /// Field number for the "applicationInstanceId" field. + public const int ApplicationInstanceIdFieldNumber = 2; + private int applicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationInstanceId { + get { return applicationInstanceId_; } + set { + applicationInstanceId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ApplicationInstanceMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ApplicationInstanceMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ApplicationId != other.ApplicationId) return false; + if (ApplicationInstanceId != other.ApplicationInstanceId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ApplicationId != 0) hash ^= ApplicationId.GetHashCode(); + if (ApplicationInstanceId != 0) hash ^= ApplicationInstanceId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ApplicationId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ApplicationId); + } + if (ApplicationInstanceId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ApplicationInstanceId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ApplicationId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationId); + } + if (ApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationInstanceId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ApplicationInstanceMapping other) { + if (other == null) { + return; + } + if (other.ApplicationId != 0) { + ApplicationId = other.ApplicationId; + } + if (other.ApplicationInstanceId != 0) { + ApplicationInstanceId = other.ApplicationInstanceId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ApplicationId = input.ReadInt32(); + break; + } + case 16: { + ApplicationInstanceId = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class ApplicationInstanceRecover : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ApplicationInstanceRecover()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceRecover() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceRecover(ApplicationInstanceRecover other) : this() { + applicationId_ = other.applicationId_; + applicationInstanceId_ = other.applicationInstanceId_; + registerTime_ = other.registerTime_; + osinfo_ = other.osinfo_ != null ? other.osinfo_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceRecover Clone() { + return new ApplicationInstanceRecover(this); + } + + /// Field number for the "applicationId" field. + public const int ApplicationIdFieldNumber = 1; + private int applicationId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationId { + get { return applicationId_; } + set { + applicationId_ = value; + } + } + + /// Field number for the "applicationInstanceId" field. + public const int ApplicationInstanceIdFieldNumber = 2; + private int applicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationInstanceId { + get { return applicationInstanceId_; } + set { + applicationInstanceId_ = value; + } + } + + /// Field number for the "registerTime" field. + public const int RegisterTimeFieldNumber = 3; + private long registerTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long RegisterTime { + get { return registerTime_; } + set { + registerTime_ = value; + } + } + + /// Field number for the "osinfo" field. + public const int OsinfoFieldNumber = 4; + private global::SkyWalking.NetworkProtocol.OSInfo osinfo_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.OSInfo Osinfo { + get { return osinfo_; } + set { + osinfo_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ApplicationInstanceRecover); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ApplicationInstanceRecover other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ApplicationId != other.ApplicationId) return false; + if (ApplicationInstanceId != other.ApplicationInstanceId) return false; + if (RegisterTime != other.RegisterTime) return false; + if (!object.Equals(Osinfo, other.Osinfo)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ApplicationId != 0) hash ^= ApplicationId.GetHashCode(); + if (ApplicationInstanceId != 0) hash ^= ApplicationInstanceId.GetHashCode(); + if (RegisterTime != 0L) hash ^= RegisterTime.GetHashCode(); + if (osinfo_ != null) hash ^= Osinfo.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ApplicationId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ApplicationId); + } + if (ApplicationInstanceId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ApplicationInstanceId); + } + if (RegisterTime != 0L) { + output.WriteRawTag(24); + output.WriteInt64(RegisterTime); + } + if (osinfo_ != null) { + output.WriteRawTag(34); + output.WriteMessage(Osinfo); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ApplicationId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationId); + } + if (ApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationInstanceId); + } + if (RegisterTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(RegisterTime); + } + if (osinfo_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Osinfo); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ApplicationInstanceRecover other) { + if (other == null) { + return; + } + if (other.ApplicationId != 0) { + ApplicationId = other.ApplicationId; + } + if (other.ApplicationInstanceId != 0) { + ApplicationInstanceId = other.ApplicationInstanceId; + } + if (other.RegisterTime != 0L) { + RegisterTime = other.RegisterTime; + } + if (other.osinfo_ != null) { + if (osinfo_ == null) { + Osinfo = new global::SkyWalking.NetworkProtocol.OSInfo(); + } + Osinfo.MergeFrom(other.Osinfo); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ApplicationId = input.ReadInt32(); + break; + } + case 16: { + ApplicationInstanceId = input.ReadInt32(); + break; + } + case 24: { + RegisterTime = input.ReadInt64(); + break; + } + case 34: { + if (osinfo_ == null) { + Osinfo = new global::SkyWalking.NetworkProtocol.OSInfo(); + } + input.ReadMessage(Osinfo); + break; + } + } + } + } + + } + + public sealed partial class ApplicationInstanceHeartbeat : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ApplicationInstanceHeartbeat()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceHeartbeat() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceHeartbeat(ApplicationInstanceHeartbeat other) : this() { + applicationInstanceId_ = other.applicationInstanceId_; + heartbeatTime_ = other.heartbeatTime_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ApplicationInstanceHeartbeat Clone() { + return new ApplicationInstanceHeartbeat(this); + } + + /// Field number for the "applicationInstanceId" field. + public const int ApplicationInstanceIdFieldNumber = 1; + private int applicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationInstanceId { + get { return applicationInstanceId_; } + set { + applicationInstanceId_ = value; + } + } + + /// Field number for the "heartbeatTime" field. + public const int HeartbeatTimeFieldNumber = 2; + private long heartbeatTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long HeartbeatTime { + get { return heartbeatTime_; } + set { + heartbeatTime_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ApplicationInstanceHeartbeat); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ApplicationInstanceHeartbeat other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ApplicationInstanceId != other.ApplicationInstanceId) return false; + if (HeartbeatTime != other.HeartbeatTime) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ApplicationInstanceId != 0) hash ^= ApplicationInstanceId.GetHashCode(); + if (HeartbeatTime != 0L) hash ^= HeartbeatTime.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ApplicationInstanceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ApplicationInstanceId); + } + if (HeartbeatTime != 0L) { + output.WriteRawTag(16); + output.WriteInt64(HeartbeatTime); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationInstanceId); + } + if (HeartbeatTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(HeartbeatTime); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ApplicationInstanceHeartbeat other) { + if (other == null) { + return; + } + if (other.ApplicationInstanceId != 0) { + ApplicationInstanceId = other.ApplicationInstanceId; + } + if (other.HeartbeatTime != 0L) { + HeartbeatTime = other.HeartbeatTime; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ApplicationInstanceId = input.ReadInt32(); + break; + } + case 16: { + HeartbeatTime = input.ReadInt64(); + break; + } + } + } + } + + } + + public sealed partial class OSInfo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OSInfo()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OSInfo() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OSInfo(OSInfo other) : this() { + osName_ = other.osName_; + hostname_ = other.hostname_; + processNo_ = other.processNo_; + ipv4S_ = other.ipv4S_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OSInfo Clone() { + return new OSInfo(this); + } + + /// Field number for the "osName" field. + public const int OsNameFieldNumber = 1; + private string osName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OsName { + get { return osName_; } + set { + osName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "hostname" field. + public const int HostnameFieldNumber = 2; + private string hostname_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Hostname { + get { return hostname_; } + set { + hostname_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "processNo" field. + public const int ProcessNoFieldNumber = 3; + private int processNo_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ProcessNo { + get { return processNo_; } + set { + processNo_ = value; + } + } + + /// Field number for the "ipv4s" field. + public const int Ipv4SFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_ipv4S_codec + = pb::FieldCodec.ForString(34); + private readonly pbc::RepeatedField ipv4S_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ipv4S { + get { return ipv4S_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as OSInfo); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(OSInfo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (OsName != other.OsName) return false; + if (Hostname != other.Hostname) return false; + if (ProcessNo != other.ProcessNo) return false; + if(!ipv4S_.Equals(other.ipv4S_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (OsName.Length != 0) hash ^= OsName.GetHashCode(); + if (Hostname.Length != 0) hash ^= Hostname.GetHashCode(); + if (ProcessNo != 0) hash ^= ProcessNo.GetHashCode(); + hash ^= ipv4S_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (OsName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(OsName); + } + if (Hostname.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Hostname); + } + if (ProcessNo != 0) { + output.WriteRawTag(24); + output.WriteInt32(ProcessNo); + } + ipv4S_.WriteTo(output, _repeated_ipv4S_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (OsName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OsName); + } + if (Hostname.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Hostname); + } + if (ProcessNo != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ProcessNo); + } + size += ipv4S_.CalculateSize(_repeated_ipv4S_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(OSInfo other) { + if (other == null) { + return; + } + if (other.OsName.Length != 0) { + OsName = other.OsName; + } + if (other.Hostname.Length != 0) { + Hostname = other.Hostname; + } + if (other.ProcessNo != 0) { + ProcessNo = other.ProcessNo; + } + ipv4S_.Add(other.ipv4S_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + OsName = input.ReadString(); + break; + } + case 18: { + Hostname = input.ReadString(); + break; + } + case 24: { + ProcessNo = input.ReadInt32(); + break; + } + case 34: { + ipv4S_.AddEntriesFrom(input, _repeated_ipv4S_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceNameCollection : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceNameCollection()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameCollection() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameCollection(ServiceNameCollection other) : this() { + elements_ = other.elements_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameCollection Clone() { + return new ServiceNameCollection(this); + } + + /// Field number for the "elements" field. + public const int ElementsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_elements_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.ServiceNameElement.Parser); + private readonly pbc::RepeatedField elements_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Elements { + get { return elements_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceNameCollection); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceNameCollection other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!elements_.Equals(other.elements_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= elements_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + elements_.WriteTo(output, _repeated_elements_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += elements_.CalculateSize(_repeated_elements_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceNameCollection other) { + if (other == null) { + return; + } + elements_.Add(other.elements_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + elements_.AddEntriesFrom(input, _repeated_elements_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceNameMappingCollection : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceNameMappingCollection()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameMappingCollection() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameMappingCollection(ServiceNameMappingCollection other) : this() { + elements_ = other.elements_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameMappingCollection Clone() { + return new ServiceNameMappingCollection(this); + } + + /// Field number for the "elements" field. + public const int ElementsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_elements_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.ServiceNameMappingElement.Parser); + private readonly pbc::RepeatedField elements_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Elements { + get { return elements_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceNameMappingCollection); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceNameMappingCollection other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!elements_.Equals(other.elements_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= elements_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + elements_.WriteTo(output, _repeated_elements_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += elements_.CalculateSize(_repeated_elements_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceNameMappingCollection other) { + if (other == null) { + return; + } + elements_.Add(other.elements_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + elements_.AddEntriesFrom(input, _repeated_elements_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceNameMappingElement : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceNameMappingElement()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameMappingElement() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameMappingElement(ServiceNameMappingElement other) : this() { + serviceId_ = other.serviceId_; + element_ = other.element_ != null ? other.element_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameMappingElement Clone() { + return new ServiceNameMappingElement(this); + } + + /// Field number for the "serviceId" field. + public const int ServiceIdFieldNumber = 1; + private int serviceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceId { + get { return serviceId_; } + set { + serviceId_ = value; + } + } + + /// Field number for the "element" field. + public const int ElementFieldNumber = 2; + private global::SkyWalking.NetworkProtocol.ServiceNameElement element_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.ServiceNameElement Element { + get { return element_; } + set { + element_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceNameMappingElement); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceNameMappingElement other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceId != other.ServiceId) return false; + if (!object.Equals(Element, other.Element)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceId != 0) hash ^= ServiceId.GetHashCode(); + if (element_ != null) hash ^= Element.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ServiceId); + } + if (element_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Element); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceId); + } + if (element_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Element); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceNameMappingElement other) { + if (other == null) { + return; + } + if (other.ServiceId != 0) { + ServiceId = other.ServiceId; + } + if (other.element_ != null) { + if (element_ == null) { + Element = new global::SkyWalking.NetworkProtocol.ServiceNameElement(); + } + Element.MergeFrom(other.Element); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ServiceId = input.ReadInt32(); + break; + } + case 18: { + if (element_ == null) { + Element = new global::SkyWalking.NetworkProtocol.ServiceNameElement(); + } + input.ReadMessage(Element); + break; + } + } + } + } + + } + + public sealed partial class ServiceNameElement : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceNameElement()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameElement() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameElement(ServiceNameElement other) : this() { + serviceName_ = other.serviceName_; + applicationId_ = other.applicationId_; + srcSpanType_ = other.srcSpanType_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceNameElement Clone() { + return new ServiceNameElement(this); + } + + /// Field number for the "serviceName" field. + public const int ServiceNameFieldNumber = 1; + private string serviceName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ServiceName { + get { return serviceName_; } + set { + serviceName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "applicationId" field. + public const int ApplicationIdFieldNumber = 2; + private int applicationId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationId { + get { return applicationId_; } + set { + applicationId_ = value; + } + } + + /// Field number for the "srcSpanType" field. + public const int SrcSpanTypeFieldNumber = 3; + private global::SkyWalking.NetworkProtocol.SpanType srcSpanType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.SpanType SrcSpanType { + get { return srcSpanType_; } + set { + srcSpanType_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceNameElement); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceNameElement other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceName != other.ServiceName) return false; + if (ApplicationId != other.ApplicationId) return false; + if (SrcSpanType != other.SrcSpanType) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceName.Length != 0) hash ^= ServiceName.GetHashCode(); + if (ApplicationId != 0) hash ^= ApplicationId.GetHashCode(); + if (SrcSpanType != 0) hash ^= SrcSpanType.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ServiceName); + } + if (ApplicationId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ApplicationId); + } + if (SrcSpanType != 0) { + output.WriteRawTag(24); + output.WriteEnum((int) SrcSpanType); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ServiceName); + } + if (ApplicationId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationId); + } + if (SrcSpanType != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SrcSpanType); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceNameElement other) { + if (other == null) { + return; + } + if (other.ServiceName.Length != 0) { + ServiceName = other.ServiceName; + } + if (other.ApplicationId != 0) { + ApplicationId = other.ApplicationId; + } + if (other.SrcSpanType != 0) { + SrcSpanType = other.SrcSpanType; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + ServiceName = input.ReadString(); + break; + } + case 16: { + ApplicationId = input.ReadInt32(); + break; + } + case 24: { + SrcSpanType = (global::SkyWalking.NetworkProtocol.SpanType) input.ReadEnum(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DiscoveryServiceGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DiscoveryServiceGrpc.cs new file mode 100644 index 000000000..270932194 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DiscoveryServiceGrpc.cs @@ -0,0 +1,255 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/DiscoveryService.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class InstanceDiscoveryService + { + static readonly string __ServiceName = "InstanceDiscoveryService"; + + static readonly grpc::Marshaller __Marshaller_ApplicationInstance = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ApplicationInstance.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ApplicationInstanceMapping = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ApplicationInstanceMapping.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ApplicationInstanceHeartbeat = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Downstream = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Downstream.Parser.ParseFrom); + + static readonly grpc::Method __Method_registerInstance = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "registerInstance", + __Marshaller_ApplicationInstance, + __Marshaller_ApplicationInstanceMapping); + + static readonly grpc::Method __Method_heartbeat = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "heartbeat", + __Marshaller_ApplicationInstanceHeartbeat, + __Marshaller_Downstream); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of InstanceDiscoveryService + [grpc::BindServiceMethod(typeof(InstanceDiscoveryService), "BindService")] + public abstract partial class InstanceDiscoveryServiceBase + { + public virtual global::System.Threading.Tasks.Task registerInstance(global::SkyWalking.NetworkProtocol.ApplicationInstance request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task heartbeat(global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for InstanceDiscoveryService + public partial class InstanceDiscoveryServiceClient : grpc::ClientBase + { + /// Creates a new client for InstanceDiscoveryService + /// The channel to use to make remote calls. + public InstanceDiscoveryServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for InstanceDiscoveryService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public InstanceDiscoveryServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected InstanceDiscoveryServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected InstanceDiscoveryServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.ApplicationInstanceMapping registerInstance(global::SkyWalking.NetworkProtocol.ApplicationInstance request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return registerInstance(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.ApplicationInstanceMapping registerInstance(global::SkyWalking.NetworkProtocol.ApplicationInstance request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_registerInstance, null, options, request); + } + public virtual grpc::AsyncUnaryCall registerInstanceAsync(global::SkyWalking.NetworkProtocol.ApplicationInstance request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return registerInstanceAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall registerInstanceAsync(global::SkyWalking.NetworkProtocol.ApplicationInstance request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_registerInstance, null, options, request); + } + public virtual global::SkyWalking.NetworkProtocol.Downstream heartbeat(global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return heartbeat(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.Downstream heartbeat(global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_heartbeat, null, options, request); + } + public virtual grpc::AsyncUnaryCall heartbeatAsync(global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return heartbeatAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall heartbeatAsync(global::SkyWalking.NetworkProtocol.ApplicationInstanceHeartbeat request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_heartbeat, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override InstanceDiscoveryServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new InstanceDiscoveryServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(InstanceDiscoveryServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_registerInstance, serviceImpl.registerInstance) + .AddMethod(__Method_heartbeat, serviceImpl.heartbeat).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, InstanceDiscoveryServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_registerInstance, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.registerInstance)); + serviceBinder.AddMethod(__Method_heartbeat, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.heartbeat)); + } + + } + /// + ///discovery service for ServiceName by Network address or application code + /// + public static partial class ServiceNameDiscoveryService + { + static readonly string __ServiceName = "ServiceNameDiscoveryService"; + + static readonly grpc::Marshaller __Marshaller_ServiceNameCollection = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceNameCollection.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ServiceNameMappingCollection = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceNameMappingCollection.Parser.ParseFrom); + + static readonly grpc::Method __Method_discovery = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "discovery", + __Marshaller_ServiceNameCollection, + __Marshaller_ServiceNameMappingCollection); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.DiscoveryServiceReflection.Descriptor.Services[1]; } + } + + /// Base class for server-side implementations of ServiceNameDiscoveryService + [grpc::BindServiceMethod(typeof(ServiceNameDiscoveryService), "BindService")] + public abstract partial class ServiceNameDiscoveryServiceBase + { + public virtual global::System.Threading.Tasks.Task discovery(global::SkyWalking.NetworkProtocol.ServiceNameCollection request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for ServiceNameDiscoveryService + public partial class ServiceNameDiscoveryServiceClient : grpc::ClientBase + { + /// Creates a new client for ServiceNameDiscoveryService + /// The channel to use to make remote calls. + public ServiceNameDiscoveryServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for ServiceNameDiscoveryService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public ServiceNameDiscoveryServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected ServiceNameDiscoveryServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected ServiceNameDiscoveryServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.ServiceNameMappingCollection discovery(global::SkyWalking.NetworkProtocol.ServiceNameCollection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return discovery(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.ServiceNameMappingCollection discovery(global::SkyWalking.NetworkProtocol.ServiceNameCollection request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_discovery, null, options, request); + } + public virtual grpc::AsyncUnaryCall discoveryAsync(global::SkyWalking.NetworkProtocol.ServiceNameCollection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return discoveryAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall discoveryAsync(global::SkyWalking.NetworkProtocol.ServiceNameCollection request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_discovery, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override ServiceNameDiscoveryServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new ServiceNameDiscoveryServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(ServiceNameDiscoveryServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_discovery, serviceImpl.discovery).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, ServiceNameDiscoveryServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_discovery, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.discovery)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Downstream.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Downstream.cs new file mode 100644 index 000000000..57491aebc --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Downstream.cs @@ -0,0 +1,149 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/Downstream.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/Downstream.proto + public static partial class DownstreamReflection { + + #region Descriptor + /// File descriptor for language-agent/Downstream.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static DownstreamReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Ch9sYW5ndWFnZS1hZ2VudC9Eb3duc3RyZWFtLnByb3RvIgwKCkRvd25zdHJl", + "YW1CUQowb3JnLmFwYWNoZS5za3l3YWxraW5nLmFwbS5uZXR3b3JrLmxhbmd1", + "YWdlLmFnZW50UAGqAhpTa3lXYWxraW5nLk5ldHdvcmtQcm90b2NvbGIGcHJv", + "dG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Downstream), global::SkyWalking.NetworkProtocol.Downstream.Parser, null, null, null, null) + })); + } + #endregion + + } + #region Messages + /// + /// nothing down stream from collector yet. + /// + public sealed partial class Downstream : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Downstream()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.DownstreamReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Downstream() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Downstream(Downstream other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Downstream Clone() { + return new Downstream(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Downstream); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Downstream other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Downstream other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DownstreamGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/DownstreamGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/InstancePing.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/InstancePing.cs new file mode 100644 index 000000000..d65f814f4 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/InstancePing.cs @@ -0,0 +1,233 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: register/InstancePing.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from register/InstancePing.proto + public static partial class InstancePingReflection { + + #region Descriptor + /// File descriptor for register/InstancePing.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static InstancePingReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChtyZWdpc3Rlci9JbnN0YW5jZVBpbmcucHJvdG8aE2NvbW1vbi9jb21tb24u", + "cHJvdG8iXgoWU2VydmljZUluc3RhbmNlUGluZ1BrZxIZChFzZXJ2aWNlSW5z", + "dGFuY2VJZBgBIAEoBRIMCgR0aW1lGAIgASgDEhsKE3NlcnZpY2VJbnN0YW5j", + "ZVVVSUQYAyABKAkyRQoTU2VydmljZUluc3RhbmNlUGluZxIuCgZkb1BpbmcS", + "Fy5TZXJ2aWNlSW5zdGFuY2VQaW5nUGtnGgkuQ29tbWFuZHMiAEJOCi1vcmcu", + "YXBhY2hlLnNreXdhbGtpbmcuYXBtLm5ldHdvcmsucmVnaXN0ZXIudjJQAaoC", + "GlNreVdhbGtpbmcuTmV0d29ya1Byb3RvY29sYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg), global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg.Parser, new[]{ "ServiceInstanceId", "Time", "ServiceInstanceUUID" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class ServiceInstancePingPkg : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceInstancePingPkg()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.InstancePingReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstancePingPkg() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstancePingPkg(ServiceInstancePingPkg other) : this() { + serviceInstanceId_ = other.serviceInstanceId_; + time_ = other.time_; + serviceInstanceUUID_ = other.serviceInstanceUUID_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstancePingPkg Clone() { + return new ServiceInstancePingPkg(this); + } + + /// Field number for the "serviceInstanceId" field. + public const int ServiceInstanceIdFieldNumber = 1; + private int serviceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceInstanceId { + get { return serviceInstanceId_; } + set { + serviceInstanceId_ = value; + } + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 2; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "serviceInstanceUUID" field. + public const int ServiceInstanceUUIDFieldNumber = 3; + private string serviceInstanceUUID_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ServiceInstanceUUID { + get { return serviceInstanceUUID_; } + set { + serviceInstanceUUID_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceInstancePingPkg); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceInstancePingPkg other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceInstanceId != other.ServiceInstanceId) return false; + if (Time != other.Time) return false; + if (ServiceInstanceUUID != other.ServiceInstanceUUID) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceInstanceId != 0) hash ^= ServiceInstanceId.GetHashCode(); + if (Time != 0L) hash ^= Time.GetHashCode(); + if (ServiceInstanceUUID.Length != 0) hash ^= ServiceInstanceUUID.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceInstanceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ServiceInstanceId); + } + if (Time != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Time); + } + if (ServiceInstanceUUID.Length != 0) { + output.WriteRawTag(26); + output.WriteString(ServiceInstanceUUID); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceInstanceId); + } + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + if (ServiceInstanceUUID.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ServiceInstanceUUID); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceInstancePingPkg other) { + if (other == null) { + return; + } + if (other.ServiceInstanceId != 0) { + ServiceInstanceId = other.ServiceInstanceId; + } + if (other.Time != 0L) { + Time = other.Time; + } + if (other.ServiceInstanceUUID.Length != 0) { + ServiceInstanceUUID = other.ServiceInstanceUUID; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ServiceInstanceId = input.ReadInt32(); + break; + } + case 16: { + Time = input.ReadInt64(); + break; + } + case 26: { + ServiceInstanceUUID = input.ReadString(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/InstancePingGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/InstancePingGrpc.cs new file mode 100644 index 000000000..66a36b00e --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/InstancePingGrpc.cs @@ -0,0 +1,125 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: register/InstancePing.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class ServiceInstancePing + { + static readonly string __ServiceName = "ServiceInstancePing"; + + static readonly grpc::Marshaller __Marshaller_ServiceInstancePingPkg = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Commands = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Commands.Parser.ParseFrom); + + static readonly grpc::Method __Method_doPing = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "doPing", + __Marshaller_ServiceInstancePingPkg, + __Marshaller_Commands); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.InstancePingReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of ServiceInstancePing + [grpc::BindServiceMethod(typeof(ServiceInstancePing), "BindService")] + public abstract partial class ServiceInstancePingBase + { + public virtual global::System.Threading.Tasks.Task doPing(global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for ServiceInstancePing + public partial class ServiceInstancePingClient : grpc::ClientBase + { + /// Creates a new client for ServiceInstancePing + /// The channel to use to make remote calls. + public ServiceInstancePingClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for ServiceInstancePing that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public ServiceInstancePingClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected ServiceInstancePingClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected ServiceInstancePingClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.Commands doPing(global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doPing(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.Commands doPing(global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_doPing, null, options, request); + } + public virtual grpc::AsyncUnaryCall doPingAsync(global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doPingAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall doPingAsync(global::SkyWalking.NetworkProtocol.ServiceInstancePingPkg request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_doPing, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override ServiceInstancePingClient NewInstance(ClientBaseConfiguration configuration) + { + return new ServiceInstancePingClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(ServiceInstancePingBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_doPing, serviceImpl.doPing).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, ServiceInstancePingBase serviceImpl) + { + serviceBinder.AddMethod(__Method_doPing, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.doPing)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVM.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVM.cs new file mode 100644 index 000000000..fab3403fa --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVM.cs @@ -0,0 +1,966 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: common/JVM.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from common/JVM.proto + public static partial class JVMReflection { + + #region Descriptor + /// File descriptor for common/JVM.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static JVMReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChBjb21tb24vSlZNLnByb3RvGhNjb21tb24vY29tbW9uLnByb3RvIncKCUpW", + "TU1ldHJpYxIMCgR0aW1lGAEgASgDEhEKA2NwdRgCIAEoCzIELkNQVRIXCgZt", + "ZW1vcnkYAyADKAsyBy5NZW1vcnkSHwoKbWVtb3J5UG9vbBgEIAMoCzILLk1l", + "bW9yeVBvb2wSDwoCZ2MYBSADKAsyAy5HQyJUCgZNZW1vcnkSDgoGaXNIZWFw", + "GAEgASgIEgwKBGluaXQYAiABKAMSCwoDbWF4GAMgASgDEgwKBHVzZWQYBCAB", + "KAMSEQoJY29tbWl0dGVkGAUgASgDImAKCk1lbW9yeVBvb2wSFwoEdHlwZRgB", + "IAEoDjIJLlBvb2xUeXBlEgwKBGluaXQYAiABKAMSCwoDbWF4GAMgASgDEgwK", + "BHVzZWQYBCABKAMSEAoIY29tbWl0ZWQYBSABKAMiPAoCR0MSGQoGcGhyYXNl", + "GAEgASgOMgkuR0NQaHJhc2USDQoFY291bnQYAiABKAMSDAoEdGltZRgDIAEo", + "AyqAAQoIUG9vbFR5cGUSFAoQQ09ERV9DQUNIRV9VU0FHRRAAEhAKDE5FV0dF", + "Tl9VU0FHRRABEhAKDE9MREdFTl9VU0FHRRACEhIKDlNVUlZJVk9SX1VTQUdF", + "EAMSEQoNUEVSTUdFTl9VU0FHRRAEEhMKD01FVEFTUEFDRV9VU0FHRRAFKhwK", + "CEdDUGhyYXNlEgcKA05FVxAAEgcKA09MRBABQlEKMG9yZy5hcGFjaGUuc2t5", + "d2Fsa2luZy5hcG0ubmV0d29yay5sYW5ndWFnZS5hZ2VudFABqgIaU2t5V2Fs", + "a2luZy5OZXR3b3JrUHJvdG9jb2xiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::SkyWalking.NetworkProtocol.PoolType), typeof(global::SkyWalking.NetworkProtocol.GCPhrase), }, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.JVMMetric), global::SkyWalking.NetworkProtocol.JVMMetric.Parser, new[]{ "Time", "Cpu", "Memory", "MemoryPool", "Gc" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Memory), global::SkyWalking.NetworkProtocol.Memory.Parser, new[]{ "IsHeap", "Init", "Max", "Used", "Committed" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.MemoryPool), global::SkyWalking.NetworkProtocol.MemoryPool.Parser, new[]{ "Type", "Init", "Max", "Used", "Commited" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.GC), global::SkyWalking.NetworkProtocol.GC.Parser, new[]{ "Phrase", "Count", "Time" }, null, null, null) + })); + } + #endregion + + } + #region Enums + public enum PoolType { + [pbr::OriginalName("CODE_CACHE_USAGE")] CodeCacheUsage = 0, + [pbr::OriginalName("NEWGEN_USAGE")] NewgenUsage = 1, + [pbr::OriginalName("OLDGEN_USAGE")] OldgenUsage = 2, + [pbr::OriginalName("SURVIVOR_USAGE")] SurvivorUsage = 3, + [pbr::OriginalName("PERMGEN_USAGE")] PermgenUsage = 4, + [pbr::OriginalName("METASPACE_USAGE")] MetaspaceUsage = 5, + } + + public enum GCPhrase { + [pbr::OriginalName("NEW")] New = 0, + [pbr::OriginalName("OLD")] Old = 1, + } + + #endregion + + #region Messages + public sealed partial class JVMMetric : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new JVMMetric()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.JVMReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetric() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetric(JVMMetric other) : this() { + time_ = other.time_; + cpu_ = other.cpu_ != null ? other.cpu_.Clone() : null; + memory_ = other.memory_.Clone(); + memoryPool_ = other.memoryPool_.Clone(); + gc_ = other.gc_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetric Clone() { + return new JVMMetric(this); + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 1; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "cpu" field. + public const int CpuFieldNumber = 2; + private global::SkyWalking.NetworkProtocol.CPU cpu_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.CPU Cpu { + get { return cpu_; } + set { + cpu_ = value; + } + } + + /// Field number for the "memory" field. + public const int MemoryFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_memory_codec + = pb::FieldCodec.ForMessage(26, global::SkyWalking.NetworkProtocol.Memory.Parser); + private readonly pbc::RepeatedField memory_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Memory { + get { return memory_; } + } + + /// Field number for the "memoryPool" field. + public const int MemoryPoolFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_memoryPool_codec + = pb::FieldCodec.ForMessage(34, global::SkyWalking.NetworkProtocol.MemoryPool.Parser); + private readonly pbc::RepeatedField memoryPool_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField MemoryPool { + get { return memoryPool_; } + } + + /// Field number for the "gc" field. + public const int GcFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_gc_codec + = pb::FieldCodec.ForMessage(42, global::SkyWalking.NetworkProtocol.GC.Parser); + private readonly pbc::RepeatedField gc_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Gc { + get { return gc_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as JVMMetric); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(JVMMetric other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Time != other.Time) return false; + if (!object.Equals(Cpu, other.Cpu)) return false; + if(!memory_.Equals(other.memory_)) return false; + if(!memoryPool_.Equals(other.memoryPool_)) return false; + if(!gc_.Equals(other.gc_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Time != 0L) hash ^= Time.GetHashCode(); + if (cpu_ != null) hash ^= Cpu.GetHashCode(); + hash ^= memory_.GetHashCode(); + hash ^= memoryPool_.GetHashCode(); + hash ^= gc_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Time != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Time); + } + if (cpu_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Cpu); + } + memory_.WriteTo(output, _repeated_memory_codec); + memoryPool_.WriteTo(output, _repeated_memoryPool_codec); + gc_.WriteTo(output, _repeated_gc_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + if (cpu_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Cpu); + } + size += memory_.CalculateSize(_repeated_memory_codec); + size += memoryPool_.CalculateSize(_repeated_memoryPool_codec); + size += gc_.CalculateSize(_repeated_gc_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(JVMMetric other) { + if (other == null) { + return; + } + if (other.Time != 0L) { + Time = other.Time; + } + if (other.cpu_ != null) { + if (cpu_ == null) { + Cpu = new global::SkyWalking.NetworkProtocol.CPU(); + } + Cpu.MergeFrom(other.Cpu); + } + memory_.Add(other.memory_); + memoryPool_.Add(other.memoryPool_); + gc_.Add(other.gc_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Time = input.ReadInt64(); + break; + } + case 18: { + if (cpu_ == null) { + Cpu = new global::SkyWalking.NetworkProtocol.CPU(); + } + input.ReadMessage(Cpu); + break; + } + case 26: { + memory_.AddEntriesFrom(input, _repeated_memory_codec); + break; + } + case 34: { + memoryPool_.AddEntriesFrom(input, _repeated_memoryPool_codec); + break; + } + case 42: { + gc_.AddEntriesFrom(input, _repeated_gc_codec); + break; + } + } + } + } + + } + + public sealed partial class Memory : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Memory()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.JVMReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Memory() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Memory(Memory other) : this() { + isHeap_ = other.isHeap_; + init_ = other.init_; + max_ = other.max_; + used_ = other.used_; + committed_ = other.committed_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Memory Clone() { + return new Memory(this); + } + + /// Field number for the "isHeap" field. + public const int IsHeapFieldNumber = 1; + private bool isHeap_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsHeap { + get { return isHeap_; } + set { + isHeap_ = value; + } + } + + /// Field number for the "init" field. + public const int InitFieldNumber = 2; + private long init_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Init { + get { return init_; } + set { + init_ = value; + } + } + + /// Field number for the "max" field. + public const int MaxFieldNumber = 3; + private long max_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Max { + get { return max_; } + set { + max_ = value; + } + } + + /// Field number for the "used" field. + public const int UsedFieldNumber = 4; + private long used_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Used { + get { return used_; } + set { + used_ = value; + } + } + + /// Field number for the "committed" field. + public const int CommittedFieldNumber = 5; + private long committed_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Committed { + get { return committed_; } + set { + committed_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Memory); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Memory other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (IsHeap != other.IsHeap) return false; + if (Init != other.Init) return false; + if (Max != other.Max) return false; + if (Used != other.Used) return false; + if (Committed != other.Committed) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (IsHeap != false) hash ^= IsHeap.GetHashCode(); + if (Init != 0L) hash ^= Init.GetHashCode(); + if (Max != 0L) hash ^= Max.GetHashCode(); + if (Used != 0L) hash ^= Used.GetHashCode(); + if (Committed != 0L) hash ^= Committed.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (IsHeap != false) { + output.WriteRawTag(8); + output.WriteBool(IsHeap); + } + if (Init != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Init); + } + if (Max != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Max); + } + if (Used != 0L) { + output.WriteRawTag(32); + output.WriteInt64(Used); + } + if (Committed != 0L) { + output.WriteRawTag(40); + output.WriteInt64(Committed); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (IsHeap != false) { + size += 1 + 1; + } + if (Init != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Init); + } + if (Max != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Max); + } + if (Used != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Used); + } + if (Committed != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Committed); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Memory other) { + if (other == null) { + return; + } + if (other.IsHeap != false) { + IsHeap = other.IsHeap; + } + if (other.Init != 0L) { + Init = other.Init; + } + if (other.Max != 0L) { + Max = other.Max; + } + if (other.Used != 0L) { + Used = other.Used; + } + if (other.Committed != 0L) { + Committed = other.Committed; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + IsHeap = input.ReadBool(); + break; + } + case 16: { + Init = input.ReadInt64(); + break; + } + case 24: { + Max = input.ReadInt64(); + break; + } + case 32: { + Used = input.ReadInt64(); + break; + } + case 40: { + Committed = input.ReadInt64(); + break; + } + } + } + } + + } + + public sealed partial class MemoryPool : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MemoryPool()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.JVMReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MemoryPool() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MemoryPool(MemoryPool other) : this() { + type_ = other.type_; + init_ = other.init_; + max_ = other.max_; + used_ = other.used_; + commited_ = other.commited_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MemoryPool Clone() { + return new MemoryPool(this); + } + + /// Field number for the "type" field. + public const int TypeFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.PoolType type_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.PoolType Type { + get { return type_; } + set { + type_ = value; + } + } + + /// Field number for the "init" field. + public const int InitFieldNumber = 2; + private long init_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Init { + get { return init_; } + set { + init_ = value; + } + } + + /// Field number for the "max" field. + public const int MaxFieldNumber = 3; + private long max_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Max { + get { return max_; } + set { + max_ = value; + } + } + + /// Field number for the "used" field. + public const int UsedFieldNumber = 4; + private long used_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Used { + get { return used_; } + set { + used_ = value; + } + } + + /// Field number for the "commited" field. + public const int CommitedFieldNumber = 5; + private long commited_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Commited { + get { return commited_; } + set { + commited_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as MemoryPool); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(MemoryPool other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Type != other.Type) return false; + if (Init != other.Init) return false; + if (Max != other.Max) return false; + if (Used != other.Used) return false; + if (Commited != other.Commited) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Type != 0) hash ^= Type.GetHashCode(); + if (Init != 0L) hash ^= Init.GetHashCode(); + if (Max != 0L) hash ^= Max.GetHashCode(); + if (Used != 0L) hash ^= Used.GetHashCode(); + if (Commited != 0L) hash ^= Commited.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Type != 0) { + output.WriteRawTag(8); + output.WriteEnum((int) Type); + } + if (Init != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Init); + } + if (Max != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Max); + } + if (Used != 0L) { + output.WriteRawTag(32); + output.WriteInt64(Used); + } + if (Commited != 0L) { + output.WriteRawTag(40); + output.WriteInt64(Commited); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Type != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); + } + if (Init != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Init); + } + if (Max != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Max); + } + if (Used != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Used); + } + if (Commited != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Commited); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(MemoryPool other) { + if (other == null) { + return; + } + if (other.Type != 0) { + Type = other.Type; + } + if (other.Init != 0L) { + Init = other.Init; + } + if (other.Max != 0L) { + Max = other.Max; + } + if (other.Used != 0L) { + Used = other.Used; + } + if (other.Commited != 0L) { + Commited = other.Commited; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Type = (global::SkyWalking.NetworkProtocol.PoolType) input.ReadEnum(); + break; + } + case 16: { + Init = input.ReadInt64(); + break; + } + case 24: { + Max = input.ReadInt64(); + break; + } + case 32: { + Used = input.ReadInt64(); + break; + } + case 40: { + Commited = input.ReadInt64(); + break; + } + } + } + } + + } + + public sealed partial class GC : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GC()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.JVMReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GC() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GC(GC other) : this() { + phrase_ = other.phrase_; + count_ = other.count_; + time_ = other.time_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GC Clone() { + return new GC(this); + } + + /// Field number for the "phrase" field. + public const int PhraseFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.GCPhrase phrase_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.GCPhrase Phrase { + get { return phrase_; } + set { + phrase_ = value; + } + } + + /// Field number for the "count" field. + public const int CountFieldNumber = 2; + private long count_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Count { + get { return count_; } + set { + count_ = value; + } + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 3; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GC); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GC other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Phrase != other.Phrase) return false; + if (Count != other.Count) return false; + if (Time != other.Time) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Phrase != 0) hash ^= Phrase.GetHashCode(); + if (Count != 0L) hash ^= Count.GetHashCode(); + if (Time != 0L) hash ^= Time.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Phrase != 0) { + output.WriteRawTag(8); + output.WriteEnum((int) Phrase); + } + if (Count != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Count); + } + if (Time != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Time); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Phrase != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Phrase); + } + if (Count != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count); + } + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GC other) { + if (other == null) { + return; + } + if (other.Phrase != 0) { + Phrase = other.Phrase; + } + if (other.Count != 0L) { + Count = other.Count; + } + if (other.Time != 0L) { + Time = other.Time; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Phrase = (global::SkyWalking.NetworkProtocol.GCPhrase) input.ReadEnum(); + break; + } + case 16: { + Count = input.ReadInt64(); + break; + } + case 24: { + Time = input.ReadInt64(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetric.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetric.cs new file mode 100644 index 000000000..9bed0b7cf --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetric.cs @@ -0,0 +1,198 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent-v2/JVMMetric.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent-v2/JVMMetric.proto + public static partial class JVMMetricReflection { + + #region Descriptor + /// File descriptor for language-agent-v2/JVMMetric.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static JVMMetricReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiFsYW5ndWFnZS1hZ2VudC12Mi9KVk1NZXRyaWMucHJvdG8aE2NvbW1vbi9j", + "b21tb24ucHJvdG8aEGNvbW1vbi9KVk0ucHJvdG8iTQoTSlZNTWV0cmljQ29s", + "bGVjdGlvbhIbCgdtZXRyaWNzGAEgAygLMgouSlZNTWV0cmljEhkKEXNlcnZp", + "Y2VJbnN0YW5jZUlkGAIgASgFMkYKFkpWTU1ldHJpY1JlcG9ydFNlcnZpY2US", + "LAoHY29sbGVjdBIULkpWTU1ldHJpY0NvbGxlY3Rpb24aCS5Db21tYW5kcyIA", + "QlQKM29yZy5hcGFjaGUuc2t5d2Fsa2luZy5hcG0ubmV0d29yay5sYW5ndWFn", + "ZS5hZ2VudC52MlABqgIaU2t5V2Fsa2luZy5OZXR3b3JrUHJvdG9jb2xiBnBy", + "b3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, global::SkyWalking.NetworkProtocol.JVMReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.JVMMetricCollection), global::SkyWalking.NetworkProtocol.JVMMetricCollection.Parser, new[]{ "Metrics", "ServiceInstanceId" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class JVMMetricCollection : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new JVMMetricCollection()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.JVMMetricReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetricCollection() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetricCollection(JVMMetricCollection other) : this() { + metrics_ = other.metrics_.Clone(); + serviceInstanceId_ = other.serviceInstanceId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetricCollection Clone() { + return new JVMMetricCollection(this); + } + + /// Field number for the "metrics" field. + public const int MetricsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_metrics_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.JVMMetric.Parser); + private readonly pbc::RepeatedField metrics_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Metrics { + get { return metrics_; } + } + + /// Field number for the "serviceInstanceId" field. + public const int ServiceInstanceIdFieldNumber = 2; + private int serviceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceInstanceId { + get { return serviceInstanceId_; } + set { + serviceInstanceId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as JVMMetricCollection); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(JVMMetricCollection other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!metrics_.Equals(other.metrics_)) return false; + if (ServiceInstanceId != other.ServiceInstanceId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= metrics_.GetHashCode(); + if (ServiceInstanceId != 0) hash ^= ServiceInstanceId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + metrics_.WriteTo(output, _repeated_metrics_codec); + if (ServiceInstanceId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ServiceInstanceId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += metrics_.CalculateSize(_repeated_metrics_codec); + if (ServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceInstanceId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(JVMMetricCollection other) { + if (other == null) { + return; + } + metrics_.Add(other.metrics_); + if (other.ServiceInstanceId != 0) { + ServiceInstanceId = other.ServiceInstanceId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + metrics_.AddEntriesFrom(input, _repeated_metrics_codec); + break; + } + case 16: { + ServiceInstanceId = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricGrpc.cs new file mode 100644 index 000000000..c4dedad7e --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricGrpc.cs @@ -0,0 +1,125 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent-v2/JVMMetric.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class JVMMetricReportService + { + static readonly string __ServiceName = "JVMMetricReportService"; + + static readonly grpc::Marshaller __Marshaller_JVMMetricCollection = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.JVMMetricCollection.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Commands = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Commands.Parser.ParseFrom); + + static readonly grpc::Method __Method_collect = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "collect", + __Marshaller_JVMMetricCollection, + __Marshaller_Commands); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.JVMMetricReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of JVMMetricReportService + [grpc::BindServiceMethod(typeof(JVMMetricReportService), "BindService")] + public abstract partial class JVMMetricReportServiceBase + { + public virtual global::System.Threading.Tasks.Task collect(global::SkyWalking.NetworkProtocol.JVMMetricCollection request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for JVMMetricReportService + public partial class JVMMetricReportServiceClient : grpc::ClientBase + { + /// Creates a new client for JVMMetricReportService + /// The channel to use to make remote calls. + public JVMMetricReportServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for JVMMetricReportService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public JVMMetricReportServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected JVMMetricReportServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected JVMMetricReportServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.Commands collect(global::SkyWalking.NetworkProtocol.JVMMetricCollection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collect(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.Commands collect(global::SkyWalking.NetworkProtocol.JVMMetricCollection request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_collect, null, options, request); + } + public virtual grpc::AsyncUnaryCall collectAsync(global::SkyWalking.NetworkProtocol.JVMMetricCollection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collectAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall collectAsync(global::SkyWalking.NetworkProtocol.JVMMetricCollection request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_collect, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override JVMMetricReportServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new JVMMetricReportServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(JVMMetricReportServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_collect, serviceImpl.collect).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, JVMMetricReportServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_collect, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.collect)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricsService.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricsService.cs new file mode 100644 index 000000000..eda33b5e5 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricsService.cs @@ -0,0 +1,198 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/JVMMetricsService.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/JVMMetricsService.proto + public static partial class JVMMetricsServiceReflection { + + #region Descriptor + /// File descriptor for language-agent/JVMMetricsService.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static JVMMetricsServiceReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiZsYW5ndWFnZS1hZ2VudC9KVk1NZXRyaWNzU2VydmljZS5wcm90bxofbGFu", + "Z3VhZ2UtYWdlbnQvRG93bnN0cmVhbS5wcm90bxoQY29tbW9uL0pWTS5wcm90", + "byJICgpKVk1NZXRyaWNzEhsKB21ldHJpY3MYASADKAsyCi5KVk1NZXRyaWMS", + "HQoVYXBwbGljYXRpb25JbnN0YW5jZUlkGAIgASgFMjoKEUpWTU1ldHJpY3NT", + "ZXJ2aWNlEiUKB2NvbGxlY3QSCy5KVk1NZXRyaWNzGgsuRG93bnN0cmVhbSIA", + "QlEKMG9yZy5hcGFjaGUuc2t5d2Fsa2luZy5hcG0ubmV0d29yay5sYW5ndWFn", + "ZS5hZ2VudFABqgIaU2t5V2Fsa2luZy5OZXR3b3JrUHJvdG9jb2xiBnByb3Rv", + "Mw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.DownstreamReflection.Descriptor, global::SkyWalking.NetworkProtocol.JVMReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.JVMMetrics), global::SkyWalking.NetworkProtocol.JVMMetrics.Parser, new[]{ "Metrics", "ApplicationInstanceId" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class JVMMetrics : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new JVMMetrics()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.JVMMetricsServiceReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetrics() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetrics(JVMMetrics other) : this() { + metrics_ = other.metrics_.Clone(); + applicationInstanceId_ = other.applicationInstanceId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public JVMMetrics Clone() { + return new JVMMetrics(this); + } + + /// Field number for the "metrics" field. + public const int MetricsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_metrics_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.JVMMetric.Parser); + private readonly pbc::RepeatedField metrics_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Metrics { + get { return metrics_; } + } + + /// Field number for the "applicationInstanceId" field. + public const int ApplicationInstanceIdFieldNumber = 2; + private int applicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationInstanceId { + get { return applicationInstanceId_; } + set { + applicationInstanceId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as JVMMetrics); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(JVMMetrics other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!metrics_.Equals(other.metrics_)) return false; + if (ApplicationInstanceId != other.ApplicationInstanceId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= metrics_.GetHashCode(); + if (ApplicationInstanceId != 0) hash ^= ApplicationInstanceId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + metrics_.WriteTo(output, _repeated_metrics_codec); + if (ApplicationInstanceId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ApplicationInstanceId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += metrics_.CalculateSize(_repeated_metrics_codec); + if (ApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationInstanceId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(JVMMetrics other) { + if (other == null) { + return; + } + metrics_.Add(other.metrics_); + if (other.ApplicationInstanceId != 0) { + ApplicationInstanceId = other.ApplicationInstanceId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + metrics_.AddEntriesFrom(input, _repeated_metrics_codec); + break; + } + case 16: { + ApplicationInstanceId = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricsServiceGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricsServiceGrpc.cs new file mode 100644 index 000000000..c20e9c53b --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/JVMMetricsServiceGrpc.cs @@ -0,0 +1,125 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/JVMMetricsService.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class JVMMetricsService + { + static readonly string __ServiceName = "JVMMetricsService"; + + static readonly grpc::Marshaller __Marshaller_JVMMetrics = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.JVMMetrics.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Downstream = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Downstream.Parser.ParseFrom); + + static readonly grpc::Method __Method_collect = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "collect", + __Marshaller_JVMMetrics, + __Marshaller_Downstream); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.JVMMetricsServiceReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of JVMMetricsService + [grpc::BindServiceMethod(typeof(JVMMetricsService), "BindService")] + public abstract partial class JVMMetricsServiceBase + { + public virtual global::System.Threading.Tasks.Task collect(global::SkyWalking.NetworkProtocol.JVMMetrics request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for JVMMetricsService + public partial class JVMMetricsServiceClient : grpc::ClientBase + { + /// Creates a new client for JVMMetricsService + /// The channel to use to make remote calls. + public JVMMetricsServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for JVMMetricsService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public JVMMetricsServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected JVMMetricsServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected JVMMetricsServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.Downstream collect(global::SkyWalking.NetworkProtocol.JVMMetrics request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collect(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.Downstream collect(global::SkyWalking.NetworkProtocol.JVMMetrics request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_collect, null, options, request); + } + public virtual grpc::AsyncUnaryCall collectAsync(global::SkyWalking.NetworkProtocol.JVMMetrics request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collectAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall collectAsync(global::SkyWalking.NetworkProtocol.JVMMetrics request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_collect, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override JVMMetricsServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new JVMMetricsServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(JVMMetricsServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_collect, serviceImpl.collect).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, JVMMetricsServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_collect, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.collect)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithIntegerValue.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithIntegerValue.cs new file mode 100644 index 000000000..6ea5a13a1 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithIntegerValue.cs @@ -0,0 +1,203 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/KeyWithIntegerValue.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/KeyWithIntegerValue.proto + public static partial class KeyWithIntegerValueReflection { + + #region Descriptor + /// File descriptor for language-agent/KeyWithIntegerValue.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static KeyWithIntegerValueReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CihsYW5ndWFnZS1hZ2VudC9LZXlXaXRoSW50ZWdlclZhbHVlLnByb3RvIjEK", + "E0tleVdpdGhJbnRlZ2VyVmFsdWUSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIg", + "ASgFQlEKMG9yZy5hcGFjaGUuc2t5d2Fsa2luZy5hcG0ubmV0d29yay5sYW5n", + "dWFnZS5hZ2VudFABqgIaU2t5V2Fsa2luZy5OZXR3b3JrUHJvdG9jb2xiBnBy", + "b3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.KeyWithIntegerValue), global::SkyWalking.NetworkProtocol.KeyWithIntegerValue.Parser, new[]{ "Key", "Value" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class KeyWithIntegerValue : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KeyWithIntegerValue()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.KeyWithIntegerValueReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyWithIntegerValue() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyWithIntegerValue(KeyWithIntegerValue other) : this() { + key_ = other.key_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyWithIntegerValue Clone() { + return new KeyWithIntegerValue(this); + } + + /// Field number for the "key" field. + public const int KeyFieldNumber = 1; + private string key_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Key { + get { return key_; } + set { + key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 2; + private int value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Value { + get { return value_; } + set { + value_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as KeyWithIntegerValue); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(KeyWithIntegerValue other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Key != other.Key) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Key.Length != 0) hash ^= Key.GetHashCode(); + if (Value != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Key.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Key); + } + if (Value != 0) { + output.WriteRawTag(16); + output.WriteInt32(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Key.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); + } + if (Value != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(KeyWithIntegerValue other) { + if (other == null) { + return; + } + if (other.Key.Length != 0) { + Key = other.Key; + } + if (other.Value != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Key = input.ReadString(); + break; + } + case 16: { + Value = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithIntegerValueGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithIntegerValueGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithStringValue.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithStringValue.cs new file mode 100644 index 000000000..7bf428db2 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithStringValue.cs @@ -0,0 +1,203 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/KeyWithStringValue.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/KeyWithStringValue.proto + public static partial class KeyWithStringValueReflection { + + #region Descriptor + /// File descriptor for language-agent/KeyWithStringValue.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static KeyWithStringValueReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CidsYW5ndWFnZS1hZ2VudC9LZXlXaXRoU3RyaW5nVmFsdWUucHJvdG8iMAoS", + "S2V5V2l0aFN0cmluZ1ZhbHVlEgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEo", + "CUJRCjBvcmcuYXBhY2hlLnNreXdhbGtpbmcuYXBtLm5ldHdvcmsubGFuZ3Vh", + "Z2UuYWdlbnRQAaoCGlNreVdhbGtpbmcuTmV0d29ya1Byb3RvY29sYgZwcm90", + "bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.KeyWithStringValue), global::SkyWalking.NetworkProtocol.KeyWithStringValue.Parser, new[]{ "Key", "Value" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class KeyWithStringValue : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KeyWithStringValue()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.KeyWithStringValueReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyWithStringValue() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyWithStringValue(KeyWithStringValue other) : this() { + key_ = other.key_; + value_ = other.value_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KeyWithStringValue Clone() { + return new KeyWithStringValue(this); + } + + /// Field number for the "key" field. + public const int KeyFieldNumber = 1; + private string key_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Key { + get { return key_; } + set { + key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 2; + private string value_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Value { + get { return value_; } + set { + value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as KeyWithStringValue); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(KeyWithStringValue other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Key != other.Key) return false; + if (Value != other.Value) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Key.Length != 0) hash ^= Key.GetHashCode(); + if (Value.Length != 0) hash ^= Value.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Key.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Key); + } + if (Value.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Value); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Key.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); + } + if (Value.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(KeyWithStringValue other) { + if (other == null) { + return; + } + if (other.Key.Length != 0) { + Key = other.Key; + } + if (other.Value.Length != 0) { + Value = other.Value; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Key = input.ReadString(); + break; + } + case 18: { + Value = input.ReadString(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithStringValueGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/KeyWithStringValueGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/NetworkAddressRegisterService.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/NetworkAddressRegisterService.cs new file mode 100644 index 000000000..dedd74958 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/NetworkAddressRegisterService.cs @@ -0,0 +1,293 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/NetworkAddressRegisterService.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/NetworkAddressRegisterService.proto + public static partial class NetworkAddressRegisterServiceReflection { + + #region Descriptor + /// File descriptor for language-agent/NetworkAddressRegisterService.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static NetworkAddressRegisterServiceReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CjJsYW5ndWFnZS1hZ2VudC9OZXR3b3JrQWRkcmVzc1JlZ2lzdGVyU2Vydmlj", + "ZS5wcm90bxoobGFuZ3VhZ2UtYWdlbnQvS2V5V2l0aEludGVnZXJWYWx1ZS5w", + "cm90byIlChBOZXR3b3JrQWRkcmVzc2VzEhEKCWFkZHJlc3NlcxgBIAMoCSJC", + "ChZOZXR3b3JrQWRkcmVzc01hcHBpbmdzEigKCmFkZHJlc3NJZHMYASADKAsy", + "FC5LZXlXaXRoSW50ZWdlclZhbHVlMl4KHU5ldHdvcmtBZGRyZXNzUmVnaXN0", + "ZXJTZXJ2aWNlEj0KDWJhdGNoUmVnaXN0ZXISES5OZXR3b3JrQWRkcmVzc2Vz", + "GhcuTmV0d29ya0FkZHJlc3NNYXBwaW5ncyIAQlEKMG9yZy5hcGFjaGUuc2t5", + "d2Fsa2luZy5hcG0ubmV0d29yay5sYW5ndWFnZS5hZ2VudFABqgIaU2t5V2Fs", + "a2luZy5OZXR3b3JrUHJvdG9jb2xiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.KeyWithIntegerValueReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.NetworkAddresses), global::SkyWalking.NetworkProtocol.NetworkAddresses.Parser, new[]{ "Addresses" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.NetworkAddressMappings), global::SkyWalking.NetworkProtocol.NetworkAddressMappings.Parser, new[]{ "AddressIds" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class NetworkAddresses : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NetworkAddresses()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.NetworkAddressRegisterServiceReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetworkAddresses() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetworkAddresses(NetworkAddresses other) : this() { + addresses_ = other.addresses_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetworkAddresses Clone() { + return new NetworkAddresses(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NetworkAddresses); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NetworkAddresses other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NetworkAddresses other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + } + } + } + + } + + public sealed partial class NetworkAddressMappings : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NetworkAddressMappings()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.NetworkAddressRegisterServiceReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetworkAddressMappings() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetworkAddressMappings(NetworkAddressMappings other) : this() { + addressIds_ = other.addressIds_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetworkAddressMappings Clone() { + return new NetworkAddressMappings(this); + } + + /// Field number for the "addressIds" field. + public const int AddressIdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addressIds_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.KeyWithIntegerValue.Parser); + private readonly pbc::RepeatedField addressIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AddressIds { + get { return addressIds_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NetworkAddressMappings); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NetworkAddressMappings other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addressIds_.Equals(other.addressIds_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addressIds_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + addressIds_.WriteTo(output, _repeated_addressIds_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addressIds_.CalculateSize(_repeated_addressIds_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NetworkAddressMappings other) { + if (other == null) { + return; + } + addressIds_.Add(other.addressIds_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + addressIds_.AddEntriesFrom(input, _repeated_addressIds_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/NetworkAddressRegisterServiceGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/NetworkAddressRegisterServiceGrpc.cs new file mode 100644 index 000000000..e9b914762 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/NetworkAddressRegisterServiceGrpc.cs @@ -0,0 +1,125 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/NetworkAddressRegisterService.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class NetworkAddressRegisterService + { + static readonly string __ServiceName = "NetworkAddressRegisterService"; + + static readonly grpc::Marshaller __Marshaller_NetworkAddresses = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.NetworkAddresses.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_NetworkAddressMappings = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.NetworkAddressMappings.Parser.ParseFrom); + + static readonly grpc::Method __Method_batchRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "batchRegister", + __Marshaller_NetworkAddresses, + __Marshaller_NetworkAddressMappings); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.NetworkAddressRegisterServiceReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of NetworkAddressRegisterService + [grpc::BindServiceMethod(typeof(NetworkAddressRegisterService), "BindService")] + public abstract partial class NetworkAddressRegisterServiceBase + { + public virtual global::System.Threading.Tasks.Task batchRegister(global::SkyWalking.NetworkProtocol.NetworkAddresses request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for NetworkAddressRegisterService + public partial class NetworkAddressRegisterServiceClient : grpc::ClientBase + { + /// Creates a new client for NetworkAddressRegisterService + /// The channel to use to make remote calls. + public NetworkAddressRegisterServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for NetworkAddressRegisterService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public NetworkAddressRegisterServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected NetworkAddressRegisterServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected NetworkAddressRegisterServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.NetworkAddressMappings batchRegister(global::SkyWalking.NetworkProtocol.NetworkAddresses request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return batchRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.NetworkAddressMappings batchRegister(global::SkyWalking.NetworkProtocol.NetworkAddresses request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_batchRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall batchRegisterAsync(global::SkyWalking.NetworkProtocol.NetworkAddresses request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return batchRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall batchRegisterAsync(global::SkyWalking.NetworkProtocol.NetworkAddresses request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_batchRegister, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override NetworkAddressRegisterServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new NetworkAddressRegisterServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(NetworkAddressRegisterServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_batchRegister, serviceImpl.batchRegister).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, NetworkAddressRegisterServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_batchRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.batchRegister)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Register.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Register.cs new file mode 100644 index 000000000..927d0d482 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Register.cs @@ -0,0 +1,2243 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: register/Register.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from register/Register.proto + public static partial class RegisterReflection { + + #region Descriptor + /// File descriptor for register/Register.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static RegisterReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChdyZWdpc3Rlci9SZWdpc3Rlci5wcm90bxoTY29tbW9uL2NvbW1vbi5wcm90", + "byImCghTZXJ2aWNlcxIaCghzZXJ2aWNlcxgBIAMoCzIILlNlcnZpY2UiagoH", + "U2VydmljZRITCgtzZXJ2aWNlTmFtZRgBIAEoCRIhCgR0YWdzGAMgAygLMhMu", + "S2V5U3RyaW5nVmFsdWVQYWlyEicKCnByb3BlcnRpZXMYBCADKAsyEy5LZXlT", + "dHJpbmdWYWx1ZVBhaXIiPAoWU2VydmljZVJlZ2lzdGVyTWFwcGluZxIiCghz", + "ZXJ2aWNlcxgBIAMoCzIQLktleUludFZhbHVlUGFpciI3ChBTZXJ2aWNlSW5z", + "dGFuY2VzEiMKCWluc3RhbmNlcxgBIAMoCzIQLlNlcnZpY2VJbnN0YW5jZSKU", + "AQoPU2VydmljZUluc3RhbmNlEhEKCXNlcnZpY2VJZBgBIAEoBRIUCgxpbnN0", + "YW5jZVVVSUQYAiABKAkSDAoEdGltZRgDIAEoAxIhCgR0YWdzGAQgAygLMhMu", + "S2V5U3RyaW5nVmFsdWVQYWlyEicKCnByb3BlcnRpZXMYBSADKAsyEy5LZXlT", + "dHJpbmdWYWx1ZVBhaXIiTAoeU2VydmljZUluc3RhbmNlUmVnaXN0ZXJNYXBw", + "aW5nEioKEHNlcnZpY2VJbnN0YW5jZXMYASADKAsyEC5LZXlJbnRWYWx1ZVBh", + "aXIiIQoMTmV0QWRkcmVzc2VzEhEKCWFkZHJlc3NlcxgBIAMoCSI5ChFOZXRB", + "ZGRyZXNzTWFwcGluZxIkCgphZGRyZXNzSWRzGAEgAygLMhAuS2V5SW50VmFs", + "dWVQYWlyIigKCEVucG9pbnRzEhwKCWVuZHBvaW50cxgBIAMoCzIJLkVuZHBv", + "aW50IpsBCghFbmRwb2ludBIRCglzZXJ2aWNlSWQYASABKAUSFAoMZW5kcG9p", + "bnROYW1lGAIgASgJEiEKBHRhZ3MYAyADKAsyEy5LZXlTdHJpbmdWYWx1ZVBh", + "aXISJwoKcHJvcGVydGllcxgEIAMoCzITLktleVN0cmluZ1ZhbHVlUGFpchIa", + "CgRmcm9tGAUgASgOMgwuRGV0ZWN0UG9pbnQiPAoPRW5kcG9pbnRNYXBwaW5n", + "EikKCGVsZW1lbnRzGAEgAygLMhcuRW5kcG9pbnRNYXBwaW5nRWxlbWVudCJx", + "ChZFbmRwb2ludE1hcHBpbmdFbGVtZW50EhEKCXNlcnZpY2VJZBgBIAEoBRIU", + "CgxlbmRwb2ludE5hbWUYAiABKAkSEgoKZW5kcG9pbnRJZBgDIAEoBRIaCgRm", + "cm9tGAQgASgOMgwuRGV0ZWN0UG9pbnQiVgogU2VydmljZUFuZE5ldHdvcmtB", + "ZGRyZXNzTWFwcGluZ3MSMgoIbWFwcGluZ3MYASADKAsyIC5TZXJ2aWNlQW5k", + "TmV0d29ya0FkZHJlc3NNYXBwaW5nIoEBCh9TZXJ2aWNlQW5kTmV0d29ya0Fk", + "ZHJlc3NNYXBwaW5nEhEKCXNlcnZpY2VJZBgBIAEoBRIZChFzZXJ2aWNlSW5z", + "dGFuY2VJZBgCIAEoBRIWCg5uZXR3b3JrQWRkcmVzcxgDIAEoCRIYChBuZXR3", + "b3JrQWRkcmVzc0lkGAQgASgFMusCCghSZWdpc3RlchI5ChFkb1NlcnZpY2VS", + "ZWdpc3RlchIJLlNlcnZpY2VzGhcuU2VydmljZVJlZ2lzdGVyTWFwcGluZyIA", + "ElEKGWRvU2VydmljZUluc3RhbmNlUmVnaXN0ZXISES5TZXJ2aWNlSW5zdGFu", + "Y2VzGh8uU2VydmljZUluc3RhbmNlUmVnaXN0ZXJNYXBwaW5nIgASMwoSZG9F", + "bmRwb2ludFJlZ2lzdGVyEgkuRW5wb2ludHMaEC5FbmRwb2ludE1hcHBpbmci", + "ABI/Chhkb05ldHdvcmtBZGRyZXNzUmVnaXN0ZXISDS5OZXRBZGRyZXNzZXMa", + "Ei5OZXRBZGRyZXNzTWFwcGluZyIAElsKKWRvU2VydmljZUFuZE5ldHdvcmtB", + "ZGRyZXNzTWFwcGluZ1JlZ2lzdGVyEiEuU2VydmljZUFuZE5ldHdvcmtBZGRy", + "ZXNzTWFwcGluZ3MaCS5Db21tYW5kcyIAQk4KLW9yZy5hcGFjaGUuc2t5d2Fs", + "a2luZy5hcG0ubmV0d29yay5yZWdpc3Rlci52MlABqgIaU2t5V2Fsa2luZy5O", + "ZXR3b3JrUHJvdG9jb2xiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Services), global::SkyWalking.NetworkProtocol.Services.Parser, new[]{ "Services_" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Service), global::SkyWalking.NetworkProtocol.Service.Parser, new[]{ "ServiceName", "Tags", "Properties" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceRegisterMapping), global::SkyWalking.NetworkProtocol.ServiceRegisterMapping.Parser, new[]{ "Services" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceInstances), global::SkyWalking.NetworkProtocol.ServiceInstances.Parser, new[]{ "Instances" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceInstance), global::SkyWalking.NetworkProtocol.ServiceInstance.Parser, new[]{ "ServiceId", "InstanceUUID", "Time", "Tags", "Properties" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceInstanceRegisterMapping), global::SkyWalking.NetworkProtocol.ServiceInstanceRegisterMapping.Parser, new[]{ "ServiceInstances" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.NetAddresses), global::SkyWalking.NetworkProtocol.NetAddresses.Parser, new[]{ "Addresses" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.NetAddressMapping), global::SkyWalking.NetworkProtocol.NetAddressMapping.Parser, new[]{ "AddressIds" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Enpoints), global::SkyWalking.NetworkProtocol.Enpoints.Parser, new[]{ "Endpoints" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Endpoint), global::SkyWalking.NetworkProtocol.Endpoint.Parser, new[]{ "ServiceId", "EndpointName", "Tags", "Properties", "From" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.EndpointMapping), global::SkyWalking.NetworkProtocol.EndpointMapping.Parser, new[]{ "Elements" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.EndpointMappingElement), global::SkyWalking.NetworkProtocol.EndpointMappingElement.Parser, new[]{ "ServiceId", "EndpointName", "EndpointId", "From" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings), global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings.Parser, new[]{ "Mappings" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMapping), global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMapping.Parser, new[]{ "ServiceId", "ServiceInstanceId", "NetworkAddress", "NetworkAddressId" }, null, null, null) + })); + } + #endregion + + } + #region Messages + /// + /// Service register + /// + public sealed partial class Services : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Services()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Services() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Services(Services other) : this() { + services_ = other.services_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Services Clone() { + return new Services(this); + } + + /// Field number for the "services" field. + public const int Services_FieldNumber = 1; + private static readonly pb::FieldCodec _repeated_services_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.Service.Parser); + private readonly pbc::RepeatedField services_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Services_ { + get { return services_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Services); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Services other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!services_.Equals(other.services_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= services_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + services_.WriteTo(output, _repeated_services_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += services_.CalculateSize(_repeated_services_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Services other) { + if (other == null) { + return; + } + services_.Add(other.services_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + services_.AddEntriesFrom(input, _repeated_services_codec); + break; + } + } + } + } + + } + + public sealed partial class Service : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Service()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Service() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Service(Service other) : this() { + serviceName_ = other.serviceName_; + tags_ = other.tags_.Clone(); + properties_ = other.properties_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Service Clone() { + return new Service(this); + } + + /// Field number for the "serviceName" field. + public const int ServiceNameFieldNumber = 1; + private string serviceName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ServiceName { + get { return serviceName_; } + set { + serviceName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "tags" field. + public const int TagsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_tags_codec + = pb::FieldCodec.ForMessage(26, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField tags_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Tags { + get { return tags_; } + } + + /// Field number for the "properties" field. + public const int PropertiesFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_properties_codec + = pb::FieldCodec.ForMessage(34, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField properties_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Properties { + get { return properties_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Service); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Service other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceName != other.ServiceName) return false; + if(!tags_.Equals(other.tags_)) return false; + if(!properties_.Equals(other.properties_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceName.Length != 0) hash ^= ServiceName.GetHashCode(); + hash ^= tags_.GetHashCode(); + hash ^= properties_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ServiceName); + } + tags_.WriteTo(output, _repeated_tags_codec); + properties_.WriteTo(output, _repeated_properties_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ServiceName); + } + size += tags_.CalculateSize(_repeated_tags_codec); + size += properties_.CalculateSize(_repeated_properties_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Service other) { + if (other == null) { + return; + } + if (other.ServiceName.Length != 0) { + ServiceName = other.ServiceName; + } + tags_.Add(other.tags_); + properties_.Add(other.properties_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + ServiceName = input.ReadString(); + break; + } + case 26: { + tags_.AddEntriesFrom(input, _repeated_tags_codec); + break; + } + case 34: { + properties_.AddEntriesFrom(input, _repeated_properties_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceRegisterMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceRegisterMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceRegisterMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceRegisterMapping(ServiceRegisterMapping other) : this() { + services_ = other.services_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceRegisterMapping Clone() { + return new ServiceRegisterMapping(this); + } + + /// Field number for the "services" field. + public const int ServicesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_services_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.KeyIntValuePair.Parser); + private readonly pbc::RepeatedField services_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Services { + get { return services_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceRegisterMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceRegisterMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!services_.Equals(other.services_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= services_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + services_.WriteTo(output, _repeated_services_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += services_.CalculateSize(_repeated_services_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceRegisterMapping other) { + if (other == null) { + return; + } + services_.Add(other.services_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + services_.AddEntriesFrom(input, _repeated_services_codec); + break; + } + } + } + } + + } + + /// + /// Service Instance register + /// + public sealed partial class ServiceInstances : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceInstances()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstances() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstances(ServiceInstances other) : this() { + instances_ = other.instances_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstances Clone() { + return new ServiceInstances(this); + } + + /// Field number for the "instances" field. + public const int InstancesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_instances_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.ServiceInstance.Parser); + private readonly pbc::RepeatedField instances_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Instances { + get { return instances_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceInstances); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceInstances other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!instances_.Equals(other.instances_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= instances_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + instances_.WriteTo(output, _repeated_instances_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += instances_.CalculateSize(_repeated_instances_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceInstances other) { + if (other == null) { + return; + } + instances_.Add(other.instances_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + instances_.AddEntriesFrom(input, _repeated_instances_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceInstance : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceInstance()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstance() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstance(ServiceInstance other) : this() { + serviceId_ = other.serviceId_; + instanceUUID_ = other.instanceUUID_; + time_ = other.time_; + tags_ = other.tags_.Clone(); + properties_ = other.properties_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstance Clone() { + return new ServiceInstance(this); + } + + /// Field number for the "serviceId" field. + public const int ServiceIdFieldNumber = 1; + private int serviceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceId { + get { return serviceId_; } + set { + serviceId_ = value; + } + } + + /// Field number for the "instanceUUID" field. + public const int InstanceUUIDFieldNumber = 2; + private string instanceUUID_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string InstanceUUID { + get { return instanceUUID_; } + set { + instanceUUID_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 3; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "tags" field. + public const int TagsFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_tags_codec + = pb::FieldCodec.ForMessage(34, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField tags_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Tags { + get { return tags_; } + } + + /// Field number for the "properties" field. + public const int PropertiesFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_properties_codec + = pb::FieldCodec.ForMessage(42, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField properties_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Properties { + get { return properties_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceInstance); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceInstance other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceId != other.ServiceId) return false; + if (InstanceUUID != other.InstanceUUID) return false; + if (Time != other.Time) return false; + if(!tags_.Equals(other.tags_)) return false; + if(!properties_.Equals(other.properties_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceId != 0) hash ^= ServiceId.GetHashCode(); + if (InstanceUUID.Length != 0) hash ^= InstanceUUID.GetHashCode(); + if (Time != 0L) hash ^= Time.GetHashCode(); + hash ^= tags_.GetHashCode(); + hash ^= properties_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ServiceId); + } + if (InstanceUUID.Length != 0) { + output.WriteRawTag(18); + output.WriteString(InstanceUUID); + } + if (Time != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Time); + } + tags_.WriteTo(output, _repeated_tags_codec); + properties_.WriteTo(output, _repeated_properties_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceId); + } + if (InstanceUUID.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(InstanceUUID); + } + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + size += tags_.CalculateSize(_repeated_tags_codec); + size += properties_.CalculateSize(_repeated_properties_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceInstance other) { + if (other == null) { + return; + } + if (other.ServiceId != 0) { + ServiceId = other.ServiceId; + } + if (other.InstanceUUID.Length != 0) { + InstanceUUID = other.InstanceUUID; + } + if (other.Time != 0L) { + Time = other.Time; + } + tags_.Add(other.tags_); + properties_.Add(other.properties_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ServiceId = input.ReadInt32(); + break; + } + case 18: { + InstanceUUID = input.ReadString(); + break; + } + case 24: { + Time = input.ReadInt64(); + break; + } + case 34: { + tags_.AddEntriesFrom(input, _repeated_tags_codec); + break; + } + case 42: { + properties_.AddEntriesFrom(input, _repeated_properties_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceInstanceRegisterMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceInstanceRegisterMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstanceRegisterMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstanceRegisterMapping(ServiceInstanceRegisterMapping other) : this() { + serviceInstances_ = other.serviceInstances_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceInstanceRegisterMapping Clone() { + return new ServiceInstanceRegisterMapping(this); + } + + /// Field number for the "serviceInstances" field. + public const int ServiceInstancesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_serviceInstances_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.KeyIntValuePair.Parser); + private readonly pbc::RepeatedField serviceInstances_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField ServiceInstances { + get { return serviceInstances_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceInstanceRegisterMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceInstanceRegisterMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!serviceInstances_.Equals(other.serviceInstances_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= serviceInstances_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + serviceInstances_.WriteTo(output, _repeated_serviceInstances_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += serviceInstances_.CalculateSize(_repeated_serviceInstances_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceInstanceRegisterMapping other) { + if (other == null) { + return; + } + serviceInstances_.Add(other.serviceInstances_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + serviceInstances_.AddEntriesFrom(input, _repeated_serviceInstances_codec); + break; + } + } + } + } + + } + + /// + /// Only known use case is the language agent. + /// Network address represents the ip/hostname:port, which is usually used at client side of RPC. + /// + public sealed partial class NetAddresses : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NetAddresses()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddresses() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddresses(NetAddresses other) : this() { + addresses_ = other.addresses_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddresses Clone() { + return new NetAddresses(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NetAddresses); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NetAddresses other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NetAddresses other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + } + } + } + + } + + public sealed partial class NetAddressMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NetAddressMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddressMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddressMapping(NetAddressMapping other) : this() { + addressIds_ = other.addressIds_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddressMapping Clone() { + return new NetAddressMapping(this); + } + + /// Field number for the "addressIds" field. + public const int AddressIdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addressIds_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.KeyIntValuePair.Parser); + private readonly pbc::RepeatedField addressIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AddressIds { + get { return addressIds_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NetAddressMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NetAddressMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addressIds_.Equals(other.addressIds_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addressIds_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + addressIds_.WriteTo(output, _repeated_addressIds_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addressIds_.CalculateSize(_repeated_addressIds_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NetAddressMapping other) { + if (other == null) { + return; + } + addressIds_.Add(other.addressIds_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + addressIds_.AddEntriesFrom(input, _repeated_addressIds_codec); + break; + } + } + } + } + + } + + /// + /// Endpint register + /// + public sealed partial class Enpoints : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Enpoints()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Enpoints() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Enpoints(Enpoints other) : this() { + endpoints_ = other.endpoints_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Enpoints Clone() { + return new Enpoints(this); + } + + /// Field number for the "endpoints" field. + public const int EndpointsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_endpoints_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.Endpoint.Parser); + private readonly pbc::RepeatedField endpoints_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Endpoints { + get { return endpoints_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Enpoints); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Enpoints other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!endpoints_.Equals(other.endpoints_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= endpoints_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + endpoints_.WriteTo(output, _repeated_endpoints_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += endpoints_.CalculateSize(_repeated_endpoints_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Enpoints other) { + if (other == null) { + return; + } + endpoints_.Add(other.endpoints_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + endpoints_.AddEntriesFrom(input, _repeated_endpoints_codec); + break; + } + } + } + } + + } + + public sealed partial class Endpoint : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Endpoint()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Endpoint() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Endpoint(Endpoint other) : this() { + serviceId_ = other.serviceId_; + endpointName_ = other.endpointName_; + tags_ = other.tags_.Clone(); + properties_ = other.properties_.Clone(); + from_ = other.from_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Endpoint Clone() { + return new Endpoint(this); + } + + /// Field number for the "serviceId" field. + public const int ServiceIdFieldNumber = 1; + private int serviceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceId { + get { return serviceId_; } + set { + serviceId_ = value; + } + } + + /// Field number for the "endpointName" field. + public const int EndpointNameFieldNumber = 2; + private string endpointName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string EndpointName { + get { return endpointName_; } + set { + endpointName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "tags" field. + public const int TagsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_tags_codec + = pb::FieldCodec.ForMessage(26, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField tags_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Tags { + get { return tags_; } + } + + /// Field number for the "properties" field. + public const int PropertiesFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_properties_codec + = pb::FieldCodec.ForMessage(34, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField properties_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Properties { + get { return properties_; } + } + + /// Field number for the "from" field. + public const int FromFieldNumber = 5; + private global::SkyWalking.NetworkProtocol.DetectPoint from_ = 0; + /// + /// For endpoint + /// from DetectPoint is either `client` or `server`. No chance to be `proxy`. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.DetectPoint From { + get { return from_; } + set { + from_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Endpoint); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Endpoint other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceId != other.ServiceId) return false; + if (EndpointName != other.EndpointName) return false; + if(!tags_.Equals(other.tags_)) return false; + if(!properties_.Equals(other.properties_)) return false; + if (From != other.From) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceId != 0) hash ^= ServiceId.GetHashCode(); + if (EndpointName.Length != 0) hash ^= EndpointName.GetHashCode(); + hash ^= tags_.GetHashCode(); + hash ^= properties_.GetHashCode(); + if (From != 0) hash ^= From.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ServiceId); + } + if (EndpointName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(EndpointName); + } + tags_.WriteTo(output, _repeated_tags_codec); + properties_.WriteTo(output, _repeated_properties_codec); + if (From != 0) { + output.WriteRawTag(40); + output.WriteEnum((int) From); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceId); + } + if (EndpointName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(EndpointName); + } + size += tags_.CalculateSize(_repeated_tags_codec); + size += properties_.CalculateSize(_repeated_properties_codec); + if (From != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) From); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Endpoint other) { + if (other == null) { + return; + } + if (other.ServiceId != 0) { + ServiceId = other.ServiceId; + } + if (other.EndpointName.Length != 0) { + EndpointName = other.EndpointName; + } + tags_.Add(other.tags_); + properties_.Add(other.properties_); + if (other.From != 0) { + From = other.From; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ServiceId = input.ReadInt32(); + break; + } + case 18: { + EndpointName = input.ReadString(); + break; + } + case 26: { + tags_.AddEntriesFrom(input, _repeated_tags_codec); + break; + } + case 34: { + properties_.AddEntriesFrom(input, _repeated_properties_codec); + break; + } + case 40: { + From = (global::SkyWalking.NetworkProtocol.DetectPoint) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class EndpointMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EndpointMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndpointMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndpointMapping(EndpointMapping other) : this() { + elements_ = other.elements_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndpointMapping Clone() { + return new EndpointMapping(this); + } + + /// Field number for the "elements" field. + public const int ElementsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_elements_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.EndpointMappingElement.Parser); + private readonly pbc::RepeatedField elements_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Elements { + get { return elements_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EndpointMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EndpointMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!elements_.Equals(other.elements_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= elements_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + elements_.WriteTo(output, _repeated_elements_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += elements_.CalculateSize(_repeated_elements_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EndpointMapping other) { + if (other == null) { + return; + } + elements_.Add(other.elements_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + elements_.AddEntriesFrom(input, _repeated_elements_codec); + break; + } + } + } + } + + } + + public sealed partial class EndpointMappingElement : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EndpointMappingElement()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndpointMappingElement() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndpointMappingElement(EndpointMappingElement other) : this() { + serviceId_ = other.serviceId_; + endpointName_ = other.endpointName_; + endpointId_ = other.endpointId_; + from_ = other.from_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EndpointMappingElement Clone() { + return new EndpointMappingElement(this); + } + + /// Field number for the "serviceId" field. + public const int ServiceIdFieldNumber = 1; + private int serviceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceId { + get { return serviceId_; } + set { + serviceId_ = value; + } + } + + /// Field number for the "endpointName" field. + public const int EndpointNameFieldNumber = 2; + private string endpointName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string EndpointName { + get { return endpointName_; } + set { + endpointName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "endpointId" field. + public const int EndpointIdFieldNumber = 3; + private int endpointId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int EndpointId { + get { return endpointId_; } + set { + endpointId_ = value; + } + } + + /// Field number for the "from" field. + public const int FromFieldNumber = 4; + private global::SkyWalking.NetworkProtocol.DetectPoint from_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.DetectPoint From { + get { return from_; } + set { + from_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EndpointMappingElement); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EndpointMappingElement other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceId != other.ServiceId) return false; + if (EndpointName != other.EndpointName) return false; + if (EndpointId != other.EndpointId) return false; + if (From != other.From) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceId != 0) hash ^= ServiceId.GetHashCode(); + if (EndpointName.Length != 0) hash ^= EndpointName.GetHashCode(); + if (EndpointId != 0) hash ^= EndpointId.GetHashCode(); + if (From != 0) hash ^= From.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ServiceId); + } + if (EndpointName.Length != 0) { + output.WriteRawTag(18); + output.WriteString(EndpointName); + } + if (EndpointId != 0) { + output.WriteRawTag(24); + output.WriteInt32(EndpointId); + } + if (From != 0) { + output.WriteRawTag(32); + output.WriteEnum((int) From); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceId); + } + if (EndpointName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(EndpointName); + } + if (EndpointId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(EndpointId); + } + if (From != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) From); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EndpointMappingElement other) { + if (other == null) { + return; + } + if (other.ServiceId != 0) { + ServiceId = other.ServiceId; + } + if (other.EndpointName.Length != 0) { + EndpointName = other.EndpointName; + } + if (other.EndpointId != 0) { + EndpointId = other.EndpointId; + } + if (other.From != 0) { + From = other.From; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ServiceId = input.ReadInt32(); + break; + } + case 18: { + EndpointName = input.ReadString(); + break; + } + case 24: { + EndpointId = input.ReadInt32(); + break; + } + case 32: { + From = (global::SkyWalking.NetworkProtocol.DetectPoint) input.ReadEnum(); + break; + } + } + } + } + + } + + public sealed partial class ServiceAndNetworkAddressMappings : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceAndNetworkAddressMappings()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceAndNetworkAddressMappings() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceAndNetworkAddressMappings(ServiceAndNetworkAddressMappings other) : this() { + mappings_ = other.mappings_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceAndNetworkAddressMappings Clone() { + return new ServiceAndNetworkAddressMappings(this); + } + + /// Field number for the "mappings" field. + public const int MappingsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_mappings_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMapping.Parser); + private readonly pbc::RepeatedField mappings_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Mappings { + get { return mappings_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceAndNetworkAddressMappings); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceAndNetworkAddressMappings other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!mappings_.Equals(other.mappings_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= mappings_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + mappings_.WriteTo(output, _repeated_mappings_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += mappings_.CalculateSize(_repeated_mappings_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceAndNetworkAddressMappings other) { + if (other == null) { + return; + } + mappings_.Add(other.mappings_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + mappings_.AddEntriesFrom(input, _repeated_mappings_codec); + break; + } + } + } + } + + } + + public sealed partial class ServiceAndNetworkAddressMapping : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceAndNetworkAddressMapping()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceAndNetworkAddressMapping() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceAndNetworkAddressMapping(ServiceAndNetworkAddressMapping other) : this() { + serviceId_ = other.serviceId_; + serviceInstanceId_ = other.serviceInstanceId_; + networkAddress_ = other.networkAddress_; + networkAddressId_ = other.networkAddressId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceAndNetworkAddressMapping Clone() { + return new ServiceAndNetworkAddressMapping(this); + } + + /// Field number for the "serviceId" field. + public const int ServiceIdFieldNumber = 1; + private int serviceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceId { + get { return serviceId_; } + set { + serviceId_ = value; + } + } + + /// Field number for the "serviceInstanceId" field. + public const int ServiceInstanceIdFieldNumber = 2; + private int serviceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceInstanceId { + get { return serviceInstanceId_; } + set { + serviceInstanceId_ = value; + } + } + + /// Field number for the "networkAddress" field. + public const int NetworkAddressFieldNumber = 3; + private string networkAddress_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NetworkAddress { + get { return networkAddress_; } + set { + networkAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "networkAddressId" field. + public const int NetworkAddressIdFieldNumber = 4; + private int networkAddressId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NetworkAddressId { + get { return networkAddressId_; } + set { + networkAddressId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceAndNetworkAddressMapping); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceAndNetworkAddressMapping other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ServiceId != other.ServiceId) return false; + if (ServiceInstanceId != other.ServiceInstanceId) return false; + if (NetworkAddress != other.NetworkAddress) return false; + if (NetworkAddressId != other.NetworkAddressId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ServiceId != 0) hash ^= ServiceId.GetHashCode(); + if (ServiceInstanceId != 0) hash ^= ServiceInstanceId.GetHashCode(); + if (NetworkAddress.Length != 0) hash ^= NetworkAddress.GetHashCode(); + if (NetworkAddressId != 0) hash ^= NetworkAddressId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (ServiceId != 0) { + output.WriteRawTag(8); + output.WriteInt32(ServiceId); + } + if (ServiceInstanceId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ServiceInstanceId); + } + if (NetworkAddress.Length != 0) { + output.WriteRawTag(26); + output.WriteString(NetworkAddress); + } + if (NetworkAddressId != 0) { + output.WriteRawTag(32); + output.WriteInt32(NetworkAddressId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceId); + } + if (ServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceInstanceId); + } + if (NetworkAddress.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NetworkAddress); + } + if (NetworkAddressId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NetworkAddressId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceAndNetworkAddressMapping other) { + if (other == null) { + return; + } + if (other.ServiceId != 0) { + ServiceId = other.ServiceId; + } + if (other.ServiceInstanceId != 0) { + ServiceInstanceId = other.ServiceInstanceId; + } + if (other.NetworkAddress.Length != 0) { + NetworkAddress = other.NetworkAddress; + } + if (other.NetworkAddressId != 0) { + NetworkAddressId = other.NetworkAddressId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ServiceId = input.ReadInt32(); + break; + } + case 16: { + ServiceInstanceId = input.ReadInt32(); + break; + } + case 26: { + NetworkAddress = input.ReadString(); + break; + } + case 32: { + NetworkAddressId = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/RegisterGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/RegisterGrpc.cs new file mode 100644 index 000000000..2f755a257 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/RegisterGrpc.cs @@ -0,0 +1,256 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: register/Register.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + /// + ///register service for ApplicationCode, this service is called when service starts. + /// + public static partial class Register + { + static readonly string __ServiceName = "Register"; + + static readonly grpc::Marshaller __Marshaller_Services = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Services.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ServiceRegisterMapping = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceRegisterMapping.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ServiceInstances = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceInstances.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ServiceInstanceRegisterMapping = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceInstanceRegisterMapping.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Enpoints = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Enpoints.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_EndpointMapping = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.EndpointMapping.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_NetAddresses = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.NetAddresses.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_NetAddressMapping = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.NetAddressMapping.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_ServiceAndNetworkAddressMappings = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Commands = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Commands.Parser.ParseFrom); + + static readonly grpc::Method __Method_doServiceRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "doServiceRegister", + __Marshaller_Services, + __Marshaller_ServiceRegisterMapping); + + static readonly grpc::Method __Method_doServiceInstanceRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "doServiceInstanceRegister", + __Marshaller_ServiceInstances, + __Marshaller_ServiceInstanceRegisterMapping); + + static readonly grpc::Method __Method_doEndpointRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "doEndpointRegister", + __Marshaller_Enpoints, + __Marshaller_EndpointMapping); + + static readonly grpc::Method __Method_doNetworkAddressRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "doNetworkAddressRegister", + __Marshaller_NetAddresses, + __Marshaller_NetAddressMapping); + + static readonly grpc::Method __Method_doServiceAndNetworkAddressMappingRegister = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "doServiceAndNetworkAddressMappingRegister", + __Marshaller_ServiceAndNetworkAddressMappings, + __Marshaller_Commands); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.RegisterReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of Register + [grpc::BindServiceMethod(typeof(Register), "BindService")] + public abstract partial class RegisterBase + { + public virtual global::System.Threading.Tasks.Task doServiceRegister(global::SkyWalking.NetworkProtocol.Services request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task doServiceInstanceRegister(global::SkyWalking.NetworkProtocol.ServiceInstances request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task doEndpointRegister(global::SkyWalking.NetworkProtocol.Enpoints request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task doNetworkAddressRegister(global::SkyWalking.NetworkProtocol.NetAddresses request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + public virtual global::System.Threading.Tasks.Task doServiceAndNetworkAddressMappingRegister(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings request, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for Register + public partial class RegisterClient : grpc::ClientBase + { + /// Creates a new client for Register + /// The channel to use to make remote calls. + public RegisterClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for Register that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public RegisterClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected RegisterClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected RegisterClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual global::SkyWalking.NetworkProtocol.ServiceRegisterMapping doServiceRegister(global::SkyWalking.NetworkProtocol.Services request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doServiceRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.ServiceRegisterMapping doServiceRegister(global::SkyWalking.NetworkProtocol.Services request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_doServiceRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall doServiceRegisterAsync(global::SkyWalking.NetworkProtocol.Services request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doServiceRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall doServiceRegisterAsync(global::SkyWalking.NetworkProtocol.Services request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_doServiceRegister, null, options, request); + } + public virtual global::SkyWalking.NetworkProtocol.ServiceInstanceRegisterMapping doServiceInstanceRegister(global::SkyWalking.NetworkProtocol.ServiceInstances request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doServiceInstanceRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.ServiceInstanceRegisterMapping doServiceInstanceRegister(global::SkyWalking.NetworkProtocol.ServiceInstances request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_doServiceInstanceRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall doServiceInstanceRegisterAsync(global::SkyWalking.NetworkProtocol.ServiceInstances request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doServiceInstanceRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall doServiceInstanceRegisterAsync(global::SkyWalking.NetworkProtocol.ServiceInstances request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_doServiceInstanceRegister, null, options, request); + } + public virtual global::SkyWalking.NetworkProtocol.EndpointMapping doEndpointRegister(global::SkyWalking.NetworkProtocol.Enpoints request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doEndpointRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.EndpointMapping doEndpointRegister(global::SkyWalking.NetworkProtocol.Enpoints request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_doEndpointRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall doEndpointRegisterAsync(global::SkyWalking.NetworkProtocol.Enpoints request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doEndpointRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall doEndpointRegisterAsync(global::SkyWalking.NetworkProtocol.Enpoints request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_doEndpointRegister, null, options, request); + } + public virtual global::SkyWalking.NetworkProtocol.NetAddressMapping doNetworkAddressRegister(global::SkyWalking.NetworkProtocol.NetAddresses request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doNetworkAddressRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.NetAddressMapping doNetworkAddressRegister(global::SkyWalking.NetworkProtocol.NetAddresses request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_doNetworkAddressRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall doNetworkAddressRegisterAsync(global::SkyWalking.NetworkProtocol.NetAddresses request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doNetworkAddressRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall doNetworkAddressRegisterAsync(global::SkyWalking.NetworkProtocol.NetAddresses request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_doNetworkAddressRegister, null, options, request); + } + public virtual global::SkyWalking.NetworkProtocol.Commands doServiceAndNetworkAddressMappingRegister(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doServiceAndNetworkAddressMappingRegister(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual global::SkyWalking.NetworkProtocol.Commands doServiceAndNetworkAddressMappingRegister(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_doServiceAndNetworkAddressMappingRegister, null, options, request); + } + public virtual grpc::AsyncUnaryCall doServiceAndNetworkAddressMappingRegisterAsync(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return doServiceAndNetworkAddressMappingRegisterAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncUnaryCall doServiceAndNetworkAddressMappingRegisterAsync(global::SkyWalking.NetworkProtocol.ServiceAndNetworkAddressMappings request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_doServiceAndNetworkAddressMappingRegister, null, options, request); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override RegisterClient NewInstance(ClientBaseConfiguration configuration) + { + return new RegisterClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(RegisterBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_doServiceRegister, serviceImpl.doServiceRegister) + .AddMethod(__Method_doServiceInstanceRegister, serviceImpl.doServiceInstanceRegister) + .AddMethod(__Method_doEndpointRegister, serviceImpl.doEndpointRegister) + .AddMethod(__Method_doNetworkAddressRegister, serviceImpl.doNetworkAddressRegister) + .AddMethod(__Method_doServiceAndNetworkAddressMappingRegister, serviceImpl.doServiceAndNetworkAddressMappingRegister).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, RegisterBase serviceImpl) + { + serviceBinder.AddMethod(__Method_doServiceRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.doServiceRegister)); + serviceBinder.AddMethod(__Method_doServiceInstanceRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.doServiceInstanceRegister)); + serviceBinder.AddMethod(__Method_doEndpointRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.doEndpointRegister)); + serviceBinder.AddMethod(__Method_doNetworkAddressRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.doNetworkAddressRegister)); + serviceBinder.AddMethod(__Method_doServiceAndNetworkAddressMappingRegister, serviceImpl == null ? null : new grpc::UnaryServerMethod(serviceImpl.doServiceAndNetworkAddressMappingRegister)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Service-mesh.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Service-mesh.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Service-meshGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Service-meshGrpc.cs new file mode 100644 index 000000000..93206fa48 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Service-meshGrpc.cs @@ -0,0 +1,115 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: service-mesh-probe/service-mesh.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +public static partial class ServiceMeshMetricService +{ + static readonly string __ServiceName = "ServiceMeshMetricService"; + + static readonly grpc::Marshaller __Marshaller_ServiceMeshMetric = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::ServiceMeshMetric.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_MeshProbeDownstream = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::MeshProbeDownstream.Parser.ParseFrom); + + static readonly grpc::Method __Method_collect = new grpc::Method( + grpc::MethodType.ClientStreaming, + __ServiceName, + "collect", + __Marshaller_ServiceMeshMetric, + __Marshaller_MeshProbeDownstream); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::ServiceMeshReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of ServiceMeshMetricService + [grpc::BindServiceMethod(typeof(ServiceMeshMetricService), "BindService")] + public abstract partial class ServiceMeshMetricServiceBase + { + public virtual global::System.Threading.Tasks.Task collect(grpc::IAsyncStreamReader requestStream, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for ServiceMeshMetricService + public partial class ServiceMeshMetricServiceClient : grpc::ClientBase + { + /// Creates a new client for ServiceMeshMetricService + /// The channel to use to make remote calls. + public ServiceMeshMetricServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for ServiceMeshMetricService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public ServiceMeshMetricServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected ServiceMeshMetricServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected ServiceMeshMetricServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual grpc::AsyncClientStreamingCall collect(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collect(new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncClientStreamingCall collect(grpc::CallOptions options) + { + return CallInvoker.AsyncClientStreamingCall(__Method_collect, null, options); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override ServiceMeshMetricServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new ServiceMeshMetricServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(ServiceMeshMetricServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_collect, serviceImpl.collect).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, ServiceMeshMetricServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_collect, serviceImpl == null ? null : new grpc::ClientStreamingServerMethod(serviceImpl.collect)); + } + +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ServiceMesh.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ServiceMesh.cs new file mode 100644 index 000000000..b916ca872 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/ServiceMesh.cs @@ -0,0 +1,713 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: service-mesh-probe/service-mesh.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +/// Holder for reflection information generated from service-mesh-probe/service-mesh.proto +public static partial class ServiceMeshReflection { + + #region Descriptor + /// File descriptor for service-mesh-probe/service-mesh.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static ServiceMeshReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiVzZXJ2aWNlLW1lc2gtcHJvYmUvc2VydmljZS1tZXNoLnByb3RvGhNjb21t", + "b24vY29tbW9uLnByb3RvIqADChFTZXJ2aWNlTWVzaE1ldHJpYxIRCglzdGFy", + "dFRpbWUYASABKAMSDwoHZW5kVGltZRgCIAEoAxIZChFzb3VyY2VTZXJ2aWNl", + "TmFtZRgDIAEoCRIXCg9zb3VyY2VTZXJ2aWNlSWQYBCABKAUSHQoVc291cmNl", + "U2VydmljZUluc3RhbmNlGAUgASgJEh8KF3NvdXJjZVNlcnZpY2VJbnN0YW5j", + "ZUlkGAYgASgFEhcKD2Rlc3RTZXJ2aWNlTmFtZRgHIAEoCRIVCg1kZXN0U2Vy", + "dmljZUlkGAggASgFEhsKE2Rlc3RTZXJ2aWNlSW5zdGFuY2UYCSABKAkSHQoV", + "ZGVzdFNlcnZpY2VJbnN0YW5jZUlkGAogASgFEhAKCGVuZHBvaW50GAsgASgJ", + "Eg8KB2xhdGVuY3kYDCABKAUSFAoMcmVzcG9uc2VDb2RlGA0gASgFEg4KBnN0", + "YXR1cxgOIAEoCBIbCghwcm90b2NvbBgPIAEoDjIJLlByb3RvY29sEiEKC2Rl", + "dGVjdFBvaW50GBAgASgOMgwuRGV0ZWN0UG9pbnQiFQoTTWVzaFByb2JlRG93", + "bnN0cmVhbSoeCghQcm90b2NvbBIICgRIVFRQEAASCAoEZ1JQQxABMlMKGFNl", + "cnZpY2VNZXNoTWV0cmljU2VydmljZRI3Cgdjb2xsZWN0EhIuU2VydmljZU1l", + "c2hNZXRyaWMaFC5NZXNoUHJvYmVEb3duc3RyZWFtIgAoAUIxCi1vcmcuYXBh", + "Y2hlLnNreXdhbGtpbmcuYXBtLm5ldHdvcmsuc2VydmljZW1lc2hQAWIGcHJv", + "dG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Protocol), }, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::ServiceMeshMetric), global::ServiceMeshMetric.Parser, new[]{ "StartTime", "EndTime", "SourceServiceName", "SourceServiceId", "SourceServiceInstance", "SourceServiceInstanceId", "DestServiceName", "DestServiceId", "DestServiceInstance", "DestServiceInstanceId", "Endpoint", "Latency", "ResponseCode", "Status", "Protocol", "DetectPoint" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::MeshProbeDownstream), global::MeshProbeDownstream.Parser, null, null, null, null) + })); + } + #endregion + +} +#region Enums +public enum Protocol { + [pbr::OriginalName("HTTP")] Http = 0, + [pbr::OriginalName("gRPC")] GRpc = 1, +} + +#endregion + +#region Messages +public sealed partial class ServiceMeshMetric : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ServiceMeshMetric()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceMeshReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceMeshMetric() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceMeshMetric(ServiceMeshMetric other) : this() { + startTime_ = other.startTime_; + endTime_ = other.endTime_; + sourceServiceName_ = other.sourceServiceName_; + sourceServiceId_ = other.sourceServiceId_; + sourceServiceInstance_ = other.sourceServiceInstance_; + sourceServiceInstanceId_ = other.sourceServiceInstanceId_; + destServiceName_ = other.destServiceName_; + destServiceId_ = other.destServiceId_; + destServiceInstance_ = other.destServiceInstance_; + destServiceInstanceId_ = other.destServiceInstanceId_; + endpoint_ = other.endpoint_; + latency_ = other.latency_; + responseCode_ = other.responseCode_; + status_ = other.status_; + protocol_ = other.protocol_; + detectPoint_ = other.detectPoint_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ServiceMeshMetric Clone() { + return new ServiceMeshMetric(this); + } + + /// Field number for the "startTime" field. + public const int StartTimeFieldNumber = 1; + private long startTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long StartTime { + get { return startTime_; } + set { + startTime_ = value; + } + } + + /// Field number for the "endTime" field. + public const int EndTimeFieldNumber = 2; + private long endTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long EndTime { + get { return endTime_; } + set { + endTime_ = value; + } + } + + /// Field number for the "sourceServiceName" field. + public const int SourceServiceNameFieldNumber = 3; + private string sourceServiceName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SourceServiceName { + get { return sourceServiceName_; } + set { + sourceServiceName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sourceServiceId" field. + public const int SourceServiceIdFieldNumber = 4; + private int sourceServiceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int SourceServiceId { + get { return sourceServiceId_; } + set { + sourceServiceId_ = value; + } + } + + /// Field number for the "sourceServiceInstance" field. + public const int SourceServiceInstanceFieldNumber = 5; + private string sourceServiceInstance_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SourceServiceInstance { + get { return sourceServiceInstance_; } + set { + sourceServiceInstance_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sourceServiceInstanceId" field. + public const int SourceServiceInstanceIdFieldNumber = 6; + private int sourceServiceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int SourceServiceInstanceId { + get { return sourceServiceInstanceId_; } + set { + sourceServiceInstanceId_ = value; + } + } + + /// Field number for the "destServiceName" field. + public const int DestServiceNameFieldNumber = 7; + private string destServiceName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string DestServiceName { + get { return destServiceName_; } + set { + destServiceName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "destServiceId" field. + public const int DestServiceIdFieldNumber = 8; + private int destServiceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int DestServiceId { + get { return destServiceId_; } + set { + destServiceId_ = value; + } + } + + /// Field number for the "destServiceInstance" field. + public const int DestServiceInstanceFieldNumber = 9; + private string destServiceInstance_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string DestServiceInstance { + get { return destServiceInstance_; } + set { + destServiceInstance_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "destServiceInstanceId" field. + public const int DestServiceInstanceIdFieldNumber = 10; + private int destServiceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int DestServiceInstanceId { + get { return destServiceInstanceId_; } + set { + destServiceInstanceId_ = value; + } + } + + /// Field number for the "endpoint" field. + public const int EndpointFieldNumber = 11; + private string endpoint_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Endpoint { + get { return endpoint_; } + set { + endpoint_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "latency" field. + public const int LatencyFieldNumber = 12; + private int latency_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Latency { + get { return latency_; } + set { + latency_ = value; + } + } + + /// Field number for the "responseCode" field. + public const int ResponseCodeFieldNumber = 13; + private int responseCode_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ResponseCode { + get { return responseCode_; } + set { + responseCode_ = value; + } + } + + /// Field number for the "status" field. + public const int StatusFieldNumber = 14; + private bool status_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Status { + get { return status_; } + set { + status_ = value; + } + } + + /// Field number for the "protocol" field. + public const int ProtocolFieldNumber = 15; + private global::Protocol protocol_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Protocol Protocol { + get { return protocol_; } + set { + protocol_ = value; + } + } + + /// Field number for the "detectPoint" field. + public const int DetectPointFieldNumber = 16; + private global::SkyWalking.NetworkProtocol.DetectPoint detectPoint_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.DetectPoint DetectPoint { + get { return detectPoint_; } + set { + detectPoint_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ServiceMeshMetric); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ServiceMeshMetric other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (StartTime != other.StartTime) return false; + if (EndTime != other.EndTime) return false; + if (SourceServiceName != other.SourceServiceName) return false; + if (SourceServiceId != other.SourceServiceId) return false; + if (SourceServiceInstance != other.SourceServiceInstance) return false; + if (SourceServiceInstanceId != other.SourceServiceInstanceId) return false; + if (DestServiceName != other.DestServiceName) return false; + if (DestServiceId != other.DestServiceId) return false; + if (DestServiceInstance != other.DestServiceInstance) return false; + if (DestServiceInstanceId != other.DestServiceInstanceId) return false; + if (Endpoint != other.Endpoint) return false; + if (Latency != other.Latency) return false; + if (ResponseCode != other.ResponseCode) return false; + if (Status != other.Status) return false; + if (Protocol != other.Protocol) return false; + if (DetectPoint != other.DetectPoint) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (StartTime != 0L) hash ^= StartTime.GetHashCode(); + if (EndTime != 0L) hash ^= EndTime.GetHashCode(); + if (SourceServiceName.Length != 0) hash ^= SourceServiceName.GetHashCode(); + if (SourceServiceId != 0) hash ^= SourceServiceId.GetHashCode(); + if (SourceServiceInstance.Length != 0) hash ^= SourceServiceInstance.GetHashCode(); + if (SourceServiceInstanceId != 0) hash ^= SourceServiceInstanceId.GetHashCode(); + if (DestServiceName.Length != 0) hash ^= DestServiceName.GetHashCode(); + if (DestServiceId != 0) hash ^= DestServiceId.GetHashCode(); + if (DestServiceInstance.Length != 0) hash ^= DestServiceInstance.GetHashCode(); + if (DestServiceInstanceId != 0) hash ^= DestServiceInstanceId.GetHashCode(); + if (Endpoint.Length != 0) hash ^= Endpoint.GetHashCode(); + if (Latency != 0) hash ^= Latency.GetHashCode(); + if (ResponseCode != 0) hash ^= ResponseCode.GetHashCode(); + if (Status != false) hash ^= Status.GetHashCode(); + if (Protocol != 0) hash ^= Protocol.GetHashCode(); + if (DetectPoint != 0) hash ^= DetectPoint.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (StartTime != 0L) { + output.WriteRawTag(8); + output.WriteInt64(StartTime); + } + if (EndTime != 0L) { + output.WriteRawTag(16); + output.WriteInt64(EndTime); + } + if (SourceServiceName.Length != 0) { + output.WriteRawTag(26); + output.WriteString(SourceServiceName); + } + if (SourceServiceId != 0) { + output.WriteRawTag(32); + output.WriteInt32(SourceServiceId); + } + if (SourceServiceInstance.Length != 0) { + output.WriteRawTag(42); + output.WriteString(SourceServiceInstance); + } + if (SourceServiceInstanceId != 0) { + output.WriteRawTag(48); + output.WriteInt32(SourceServiceInstanceId); + } + if (DestServiceName.Length != 0) { + output.WriteRawTag(58); + output.WriteString(DestServiceName); + } + if (DestServiceId != 0) { + output.WriteRawTag(64); + output.WriteInt32(DestServiceId); + } + if (DestServiceInstance.Length != 0) { + output.WriteRawTag(74); + output.WriteString(DestServiceInstance); + } + if (DestServiceInstanceId != 0) { + output.WriteRawTag(80); + output.WriteInt32(DestServiceInstanceId); + } + if (Endpoint.Length != 0) { + output.WriteRawTag(90); + output.WriteString(Endpoint); + } + if (Latency != 0) { + output.WriteRawTag(96); + output.WriteInt32(Latency); + } + if (ResponseCode != 0) { + output.WriteRawTag(104); + output.WriteInt32(ResponseCode); + } + if (Status != false) { + output.WriteRawTag(112); + output.WriteBool(Status); + } + if (Protocol != 0) { + output.WriteRawTag(120); + output.WriteEnum((int) Protocol); + } + if (DetectPoint != 0) { + output.WriteRawTag(128, 1); + output.WriteEnum((int) DetectPoint); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (StartTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(StartTime); + } + if (EndTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(EndTime); + } + if (SourceServiceName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceServiceName); + } + if (SourceServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(SourceServiceId); + } + if (SourceServiceInstance.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceServiceInstance); + } + if (SourceServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(SourceServiceInstanceId); + } + if (DestServiceName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(DestServiceName); + } + if (DestServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(DestServiceId); + } + if (DestServiceInstance.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(DestServiceInstance); + } + if (DestServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(DestServiceInstanceId); + } + if (Endpoint.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Endpoint); + } + if (Latency != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Latency); + } + if (ResponseCode != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ResponseCode); + } + if (Status != false) { + size += 1 + 1; + } + if (Protocol != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Protocol); + } + if (DetectPoint != 0) { + size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) DetectPoint); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ServiceMeshMetric other) { + if (other == null) { + return; + } + if (other.StartTime != 0L) { + StartTime = other.StartTime; + } + if (other.EndTime != 0L) { + EndTime = other.EndTime; + } + if (other.SourceServiceName.Length != 0) { + SourceServiceName = other.SourceServiceName; + } + if (other.SourceServiceId != 0) { + SourceServiceId = other.SourceServiceId; + } + if (other.SourceServiceInstance.Length != 0) { + SourceServiceInstance = other.SourceServiceInstance; + } + if (other.SourceServiceInstanceId != 0) { + SourceServiceInstanceId = other.SourceServiceInstanceId; + } + if (other.DestServiceName.Length != 0) { + DestServiceName = other.DestServiceName; + } + if (other.DestServiceId != 0) { + DestServiceId = other.DestServiceId; + } + if (other.DestServiceInstance.Length != 0) { + DestServiceInstance = other.DestServiceInstance; + } + if (other.DestServiceInstanceId != 0) { + DestServiceInstanceId = other.DestServiceInstanceId; + } + if (other.Endpoint.Length != 0) { + Endpoint = other.Endpoint; + } + if (other.Latency != 0) { + Latency = other.Latency; + } + if (other.ResponseCode != 0) { + ResponseCode = other.ResponseCode; + } + if (other.Status != false) { + Status = other.Status; + } + if (other.Protocol != 0) { + Protocol = other.Protocol; + } + if (other.DetectPoint != 0) { + DetectPoint = other.DetectPoint; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + StartTime = input.ReadInt64(); + break; + } + case 16: { + EndTime = input.ReadInt64(); + break; + } + case 26: { + SourceServiceName = input.ReadString(); + break; + } + case 32: { + SourceServiceId = input.ReadInt32(); + break; + } + case 42: { + SourceServiceInstance = input.ReadString(); + break; + } + case 48: { + SourceServiceInstanceId = input.ReadInt32(); + break; + } + case 58: { + DestServiceName = input.ReadString(); + break; + } + case 64: { + DestServiceId = input.ReadInt32(); + break; + } + case 74: { + DestServiceInstance = input.ReadString(); + break; + } + case 80: { + DestServiceInstanceId = input.ReadInt32(); + break; + } + case 90: { + Endpoint = input.ReadString(); + break; + } + case 96: { + Latency = input.ReadInt32(); + break; + } + case 104: { + ResponseCode = input.ReadInt32(); + break; + } + case 112: { + Status = input.ReadBool(); + break; + } + case 120: { + Protocol = (global::Protocol) input.ReadEnum(); + break; + } + case 128: { + DetectPoint = (global::SkyWalking.NetworkProtocol.DetectPoint) input.ReadEnum(); + break; + } + } + } + } + +} + +public sealed partial class MeshProbeDownstream : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MeshProbeDownstream()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::ServiceMeshReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MeshProbeDownstream() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MeshProbeDownstream(MeshProbeDownstream other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MeshProbeDownstream Clone() { + return new MeshProbeDownstream(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as MeshProbeDownstream); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(MeshProbeDownstream other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(MeshProbeDownstream other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + } + +} + +#endregion + + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace-common.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace-common.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace-commonGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace-commonGrpc.cs new file mode 100644 index 000000000..e69de29bb diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace.cs new file mode 100644 index 000000000..8752705e5 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/Trace.cs @@ -0,0 +1,1398 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent-v2/trace.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent-v2/trace.proto + public static partial class TraceReflection { + + #region Descriptor + /// File descriptor for language-agent-v2/trace.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static TraceReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Ch1sYW5ndWFnZS1hZ2VudC12Mi90cmFjZS5wcm90bxoTY29tbW9uL2NvbW1v", + "bi5wcm90bxoZY29tbW9uL3RyYWNlLWNvbW1vbi5wcm90byKVAQoNU2VnbWVu", + "dE9iamVjdBIhCg50cmFjZVNlZ21lbnRJZBgBIAEoCzIJLlVuaXF1ZUlkEhwK", + "BXNwYW5zGAIgAygLMg0uU3Bhbk9iamVjdFYyEhEKCXNlcnZpY2VJZBgDIAEo", + "BRIZChFzZXJ2aWNlSW5zdGFuY2VJZBgEIAEoBRIVCg1pc1NpemVMaW1pdGVk", + "GAUgASgIIsECChBTZWdtZW50UmVmZXJlbmNlEhkKB3JlZlR5cGUYASABKA4y", + "CC5SZWZUeXBlEicKFHBhcmVudFRyYWNlU2VnbWVudElkGAIgASgLMgkuVW5p", + "cXVlSWQSFAoMcGFyZW50U3BhbklkGAMgASgFEh8KF3BhcmVudFNlcnZpY2VJ", + "bnN0YW5jZUlkGAQgASgFEhYKDm5ldHdvcmtBZGRyZXNzGAUgASgJEhgKEG5l", + "dHdvcmtBZGRyZXNzSWQYBiABKAUSHgoWZW50cnlTZXJ2aWNlSW5zdGFuY2VJ", + "ZBgHIAEoBRIVCg1lbnRyeUVuZHBvaW50GAggASgJEhcKD2VudHJ5RW5kcG9p", + "bnRJZBgJIAEoBRIWCg5wYXJlbnRFbmRwb2ludBgKIAEoCRIYChBwYXJlbnRF", + "bmRwb2ludElkGAsgASgFIvMCCgxTcGFuT2JqZWN0VjISDgoGc3BhbklkGAEg", + "ASgFEhQKDHBhcmVudFNwYW5JZBgCIAEoBRIRCglzdGFydFRpbWUYAyABKAMS", + "DwoHZW5kVGltZRgEIAEoAxIfCgRyZWZzGAUgAygLMhEuU2VnbWVudFJlZmVy", + "ZW5jZRIXCg9vcGVyYXRpb25OYW1lSWQYBiABKAUSFQoNb3BlcmF0aW9uTmFt", + "ZRgHIAEoCRIOCgZwZWVySWQYCCABKAUSDAoEcGVlchgJIAEoCRIbCghzcGFu", + "VHlwZRgKIAEoDjIJLlNwYW5UeXBlEh0KCXNwYW5MYXllchgLIAEoDjIKLlNw", + "YW5MYXllchITCgtjb21wb25lbnRJZBgMIAEoBRIRCgljb21wb25lbnQYDSAB", + "KAkSDwoHaXNFcnJvchgOIAEoCBIhCgR0YWdzGA8gAygLMhMuS2V5U3RyaW5n", + "VmFsdWVQYWlyEhIKBGxvZ3MYECADKAsyBC5Mb2ciNgoDTG9nEgwKBHRpbWUY", + "ASABKAMSIQoEZGF0YRgCIAMoCzITLktleVN0cmluZ1ZhbHVlUGFpcjJHChlU", + "cmFjZVNlZ21lbnRSZXBvcnRTZXJ2aWNlEioKB2NvbGxlY3QSEC5VcHN0cmVh", + "bVNlZ21lbnQaCS5Db21tYW5kcyIAKAFCVAozb3JnLmFwYWNoZS5za3l3YWxr", + "aW5nLmFwbS5uZXR3b3JrLmxhbmd1YWdlLmFnZW50LnYyUAGqAhpTa3lXYWxr", + "aW5nLk5ldHdvcmtQcm90b2NvbGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.CommonReflection.Descriptor, global::SkyWalking.NetworkProtocol.TraceCommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.SegmentObject), global::SkyWalking.NetworkProtocol.SegmentObject.Parser, new[]{ "TraceSegmentId", "Spans", "ServiceId", "ServiceInstanceId", "IsSizeLimited" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.SegmentReference), global::SkyWalking.NetworkProtocol.SegmentReference.Parser, new[]{ "RefType", "ParentTraceSegmentId", "ParentSpanId", "ParentServiceInstanceId", "NetworkAddress", "NetworkAddressId", "EntryServiceInstanceId", "EntryEndpoint", "EntryEndpointId", "ParentEndpoint", "ParentEndpointId" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.SpanObjectV2), global::SkyWalking.NetworkProtocol.SpanObjectV2.Parser, new[]{ "SpanId", "ParentSpanId", "StartTime", "EndTime", "Refs", "OperationNameId", "OperationName", "PeerId", "Peer", "SpanType", "SpanLayer", "ComponentId", "Component", "IsError", "Tags", "Logs" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.Log), global::SkyWalking.NetworkProtocol.Log.Parser, new[]{ "Time", "Data" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class SegmentObject : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SegmentObject()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SegmentObject() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SegmentObject(SegmentObject other) : this() { + traceSegmentId_ = other.traceSegmentId_ != null ? other.traceSegmentId_.Clone() : null; + spans_ = other.spans_.Clone(); + serviceId_ = other.serviceId_; + serviceInstanceId_ = other.serviceInstanceId_; + isSizeLimited_ = other.isSizeLimited_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SegmentObject Clone() { + return new SegmentObject(this); + } + + /// Field number for the "traceSegmentId" field. + public const int TraceSegmentIdFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.UniqueId traceSegmentId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.UniqueId TraceSegmentId { + get { return traceSegmentId_; } + set { + traceSegmentId_ = value; + } + } + + /// Field number for the "spans" field. + public const int SpansFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_spans_codec + = pb::FieldCodec.ForMessage(18, global::SkyWalking.NetworkProtocol.SpanObjectV2.Parser); + private readonly pbc::RepeatedField spans_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Spans { + get { return spans_; } + } + + /// Field number for the "serviceId" field. + public const int ServiceIdFieldNumber = 3; + private int serviceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceId { + get { return serviceId_; } + set { + serviceId_ = value; + } + } + + /// Field number for the "serviceInstanceId" field. + public const int ServiceInstanceIdFieldNumber = 4; + private int serviceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ServiceInstanceId { + get { return serviceInstanceId_; } + set { + serviceInstanceId_ = value; + } + } + + /// Field number for the "isSizeLimited" field. + public const int IsSizeLimitedFieldNumber = 5; + private bool isSizeLimited_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsSizeLimited { + get { return isSizeLimited_; } + set { + isSizeLimited_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SegmentObject); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SegmentObject other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(TraceSegmentId, other.TraceSegmentId)) return false; + if(!spans_.Equals(other.spans_)) return false; + if (ServiceId != other.ServiceId) return false; + if (ServiceInstanceId != other.ServiceInstanceId) return false; + if (IsSizeLimited != other.IsSizeLimited) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (traceSegmentId_ != null) hash ^= TraceSegmentId.GetHashCode(); + hash ^= spans_.GetHashCode(); + if (ServiceId != 0) hash ^= ServiceId.GetHashCode(); + if (ServiceInstanceId != 0) hash ^= ServiceInstanceId.GetHashCode(); + if (IsSizeLimited != false) hash ^= IsSizeLimited.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (traceSegmentId_ != null) { + output.WriteRawTag(10); + output.WriteMessage(TraceSegmentId); + } + spans_.WriteTo(output, _repeated_spans_codec); + if (ServiceId != 0) { + output.WriteRawTag(24); + output.WriteInt32(ServiceId); + } + if (ServiceInstanceId != 0) { + output.WriteRawTag(32); + output.WriteInt32(ServiceInstanceId); + } + if (IsSizeLimited != false) { + output.WriteRawTag(40); + output.WriteBool(IsSizeLimited); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (traceSegmentId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TraceSegmentId); + } + size += spans_.CalculateSize(_repeated_spans_codec); + if (ServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceId); + } + if (ServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ServiceInstanceId); + } + if (IsSizeLimited != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SegmentObject other) { + if (other == null) { + return; + } + if (other.traceSegmentId_ != null) { + if (traceSegmentId_ == null) { + TraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + TraceSegmentId.MergeFrom(other.TraceSegmentId); + } + spans_.Add(other.spans_); + if (other.ServiceId != 0) { + ServiceId = other.ServiceId; + } + if (other.ServiceInstanceId != 0) { + ServiceInstanceId = other.ServiceInstanceId; + } + if (other.IsSizeLimited != false) { + IsSizeLimited = other.IsSizeLimited; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (traceSegmentId_ == null) { + TraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + input.ReadMessage(TraceSegmentId); + break; + } + case 18: { + spans_.AddEntriesFrom(input, _repeated_spans_codec); + break; + } + case 24: { + ServiceId = input.ReadInt32(); + break; + } + case 32: { + ServiceInstanceId = input.ReadInt32(); + break; + } + case 40: { + IsSizeLimited = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class SegmentReference : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SegmentReference()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SegmentReference() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SegmentReference(SegmentReference other) : this() { + refType_ = other.refType_; + parentTraceSegmentId_ = other.parentTraceSegmentId_ != null ? other.parentTraceSegmentId_.Clone() : null; + parentSpanId_ = other.parentSpanId_; + parentServiceInstanceId_ = other.parentServiceInstanceId_; + networkAddress_ = other.networkAddress_; + networkAddressId_ = other.networkAddressId_; + entryServiceInstanceId_ = other.entryServiceInstanceId_; + entryEndpoint_ = other.entryEndpoint_; + entryEndpointId_ = other.entryEndpointId_; + parentEndpoint_ = other.parentEndpoint_; + parentEndpointId_ = other.parentEndpointId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SegmentReference Clone() { + return new SegmentReference(this); + } + + /// Field number for the "refType" field. + public const int RefTypeFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.RefType refType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.RefType RefType { + get { return refType_; } + set { + refType_ = value; + } + } + + /// Field number for the "parentTraceSegmentId" field. + public const int ParentTraceSegmentIdFieldNumber = 2; + private global::SkyWalking.NetworkProtocol.UniqueId parentTraceSegmentId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.UniqueId ParentTraceSegmentId { + get { return parentTraceSegmentId_; } + set { + parentTraceSegmentId_ = value; + } + } + + /// Field number for the "parentSpanId" field. + public const int ParentSpanIdFieldNumber = 3; + private int parentSpanId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentSpanId { + get { return parentSpanId_; } + set { + parentSpanId_ = value; + } + } + + /// Field number for the "parentServiceInstanceId" field. + public const int ParentServiceInstanceIdFieldNumber = 4; + private int parentServiceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentServiceInstanceId { + get { return parentServiceInstanceId_; } + set { + parentServiceInstanceId_ = value; + } + } + + /// Field number for the "networkAddress" field. + public const int NetworkAddressFieldNumber = 5; + private string networkAddress_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NetworkAddress { + get { return networkAddress_; } + set { + networkAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "networkAddressId" field. + public const int NetworkAddressIdFieldNumber = 6; + private int networkAddressId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NetworkAddressId { + get { return networkAddressId_; } + set { + networkAddressId_ = value; + } + } + + /// Field number for the "entryServiceInstanceId" field. + public const int EntryServiceInstanceIdFieldNumber = 7; + private int entryServiceInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int EntryServiceInstanceId { + get { return entryServiceInstanceId_; } + set { + entryServiceInstanceId_ = value; + } + } + + /// Field number for the "entryEndpoint" field. + public const int EntryEndpointFieldNumber = 8; + private string entryEndpoint_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string EntryEndpoint { + get { return entryEndpoint_; } + set { + entryEndpoint_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "entryEndpointId" field. + public const int EntryEndpointIdFieldNumber = 9; + private int entryEndpointId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int EntryEndpointId { + get { return entryEndpointId_; } + set { + entryEndpointId_ = value; + } + } + + /// Field number for the "parentEndpoint" field. + public const int ParentEndpointFieldNumber = 10; + private string parentEndpoint_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ParentEndpoint { + get { return parentEndpoint_; } + set { + parentEndpoint_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "parentEndpointId" field. + public const int ParentEndpointIdFieldNumber = 11; + private int parentEndpointId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentEndpointId { + get { return parentEndpointId_; } + set { + parentEndpointId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SegmentReference); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SegmentReference other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (RefType != other.RefType) return false; + if (!object.Equals(ParentTraceSegmentId, other.ParentTraceSegmentId)) return false; + if (ParentSpanId != other.ParentSpanId) return false; + if (ParentServiceInstanceId != other.ParentServiceInstanceId) return false; + if (NetworkAddress != other.NetworkAddress) return false; + if (NetworkAddressId != other.NetworkAddressId) return false; + if (EntryServiceInstanceId != other.EntryServiceInstanceId) return false; + if (EntryEndpoint != other.EntryEndpoint) return false; + if (EntryEndpointId != other.EntryEndpointId) return false; + if (ParentEndpoint != other.ParentEndpoint) return false; + if (ParentEndpointId != other.ParentEndpointId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (RefType != 0) hash ^= RefType.GetHashCode(); + if (parentTraceSegmentId_ != null) hash ^= ParentTraceSegmentId.GetHashCode(); + if (ParentSpanId != 0) hash ^= ParentSpanId.GetHashCode(); + if (ParentServiceInstanceId != 0) hash ^= ParentServiceInstanceId.GetHashCode(); + if (NetworkAddress.Length != 0) hash ^= NetworkAddress.GetHashCode(); + if (NetworkAddressId != 0) hash ^= NetworkAddressId.GetHashCode(); + if (EntryServiceInstanceId != 0) hash ^= EntryServiceInstanceId.GetHashCode(); + if (EntryEndpoint.Length != 0) hash ^= EntryEndpoint.GetHashCode(); + if (EntryEndpointId != 0) hash ^= EntryEndpointId.GetHashCode(); + if (ParentEndpoint.Length != 0) hash ^= ParentEndpoint.GetHashCode(); + if (ParentEndpointId != 0) hash ^= ParentEndpointId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (RefType != 0) { + output.WriteRawTag(8); + output.WriteEnum((int) RefType); + } + if (parentTraceSegmentId_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ParentTraceSegmentId); + } + if (ParentSpanId != 0) { + output.WriteRawTag(24); + output.WriteInt32(ParentSpanId); + } + if (ParentServiceInstanceId != 0) { + output.WriteRawTag(32); + output.WriteInt32(ParentServiceInstanceId); + } + if (NetworkAddress.Length != 0) { + output.WriteRawTag(42); + output.WriteString(NetworkAddress); + } + if (NetworkAddressId != 0) { + output.WriteRawTag(48); + output.WriteInt32(NetworkAddressId); + } + if (EntryServiceInstanceId != 0) { + output.WriteRawTag(56); + output.WriteInt32(EntryServiceInstanceId); + } + if (EntryEndpoint.Length != 0) { + output.WriteRawTag(66); + output.WriteString(EntryEndpoint); + } + if (EntryEndpointId != 0) { + output.WriteRawTag(72); + output.WriteInt32(EntryEndpointId); + } + if (ParentEndpoint.Length != 0) { + output.WriteRawTag(82); + output.WriteString(ParentEndpoint); + } + if (ParentEndpointId != 0) { + output.WriteRawTag(88); + output.WriteInt32(ParentEndpointId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (RefType != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RefType); + } + if (parentTraceSegmentId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ParentTraceSegmentId); + } + if (ParentSpanId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentSpanId); + } + if (ParentServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentServiceInstanceId); + } + if (NetworkAddress.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NetworkAddress); + } + if (NetworkAddressId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NetworkAddressId); + } + if (EntryServiceInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(EntryServiceInstanceId); + } + if (EntryEndpoint.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(EntryEndpoint); + } + if (EntryEndpointId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(EntryEndpointId); + } + if (ParentEndpoint.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ParentEndpoint); + } + if (ParentEndpointId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentEndpointId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SegmentReference other) { + if (other == null) { + return; + } + if (other.RefType != 0) { + RefType = other.RefType; + } + if (other.parentTraceSegmentId_ != null) { + if (parentTraceSegmentId_ == null) { + ParentTraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + ParentTraceSegmentId.MergeFrom(other.ParentTraceSegmentId); + } + if (other.ParentSpanId != 0) { + ParentSpanId = other.ParentSpanId; + } + if (other.ParentServiceInstanceId != 0) { + ParentServiceInstanceId = other.ParentServiceInstanceId; + } + if (other.NetworkAddress.Length != 0) { + NetworkAddress = other.NetworkAddress; + } + if (other.NetworkAddressId != 0) { + NetworkAddressId = other.NetworkAddressId; + } + if (other.EntryServiceInstanceId != 0) { + EntryServiceInstanceId = other.EntryServiceInstanceId; + } + if (other.EntryEndpoint.Length != 0) { + EntryEndpoint = other.EntryEndpoint; + } + if (other.EntryEndpointId != 0) { + EntryEndpointId = other.EntryEndpointId; + } + if (other.ParentEndpoint.Length != 0) { + ParentEndpoint = other.ParentEndpoint; + } + if (other.ParentEndpointId != 0) { + ParentEndpointId = other.ParentEndpointId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + RefType = (global::SkyWalking.NetworkProtocol.RefType) input.ReadEnum(); + break; + } + case 18: { + if (parentTraceSegmentId_ == null) { + ParentTraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + input.ReadMessage(ParentTraceSegmentId); + break; + } + case 24: { + ParentSpanId = input.ReadInt32(); + break; + } + case 32: { + ParentServiceInstanceId = input.ReadInt32(); + break; + } + case 42: { + NetworkAddress = input.ReadString(); + break; + } + case 48: { + NetworkAddressId = input.ReadInt32(); + break; + } + case 56: { + EntryServiceInstanceId = input.ReadInt32(); + break; + } + case 66: { + EntryEndpoint = input.ReadString(); + break; + } + case 72: { + EntryEndpointId = input.ReadInt32(); + break; + } + case 82: { + ParentEndpoint = input.ReadString(); + break; + } + case 88: { + ParentEndpointId = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class SpanObjectV2 : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SpanObjectV2()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SpanObjectV2() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SpanObjectV2(SpanObjectV2 other) : this() { + spanId_ = other.spanId_; + parentSpanId_ = other.parentSpanId_; + startTime_ = other.startTime_; + endTime_ = other.endTime_; + refs_ = other.refs_.Clone(); + operationNameId_ = other.operationNameId_; + operationName_ = other.operationName_; + peerId_ = other.peerId_; + peer_ = other.peer_; + spanType_ = other.spanType_; + spanLayer_ = other.spanLayer_; + componentId_ = other.componentId_; + component_ = other.component_; + isError_ = other.isError_; + tags_ = other.tags_.Clone(); + logs_ = other.logs_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SpanObjectV2 Clone() { + return new SpanObjectV2(this); + } + + /// Field number for the "spanId" field. + public const int SpanIdFieldNumber = 1; + private int spanId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int SpanId { + get { return spanId_; } + set { + spanId_ = value; + } + } + + /// Field number for the "parentSpanId" field. + public const int ParentSpanIdFieldNumber = 2; + private int parentSpanId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentSpanId { + get { return parentSpanId_; } + set { + parentSpanId_ = value; + } + } + + /// Field number for the "startTime" field. + public const int StartTimeFieldNumber = 3; + private long startTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long StartTime { + get { return startTime_; } + set { + startTime_ = value; + } + } + + /// Field number for the "endTime" field. + public const int EndTimeFieldNumber = 4; + private long endTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long EndTime { + get { return endTime_; } + set { + endTime_ = value; + } + } + + /// Field number for the "refs" field. + public const int RefsFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_refs_codec + = pb::FieldCodec.ForMessage(42, global::SkyWalking.NetworkProtocol.SegmentReference.Parser); + private readonly pbc::RepeatedField refs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Refs { + get { return refs_; } + } + + /// Field number for the "operationNameId" field. + public const int OperationNameIdFieldNumber = 6; + private int operationNameId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int OperationNameId { + get { return operationNameId_; } + set { + operationNameId_ = value; + } + } + + /// Field number for the "operationName" field. + public const int OperationNameFieldNumber = 7; + private string operationName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OperationName { + get { return operationName_; } + set { + operationName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "peerId" field. + public const int PeerIdFieldNumber = 8; + private int peerId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int PeerId { + get { return peerId_; } + set { + peerId_ = value; + } + } + + /// Field number for the "peer" field. + public const int PeerFieldNumber = 9; + private string peer_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Peer { + get { return peer_; } + set { + peer_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "spanType" field. + public const int SpanTypeFieldNumber = 10; + private global::SkyWalking.NetworkProtocol.SpanType spanType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.SpanType SpanType { + get { return spanType_; } + set { + spanType_ = value; + } + } + + /// Field number for the "spanLayer" field. + public const int SpanLayerFieldNumber = 11; + private global::SkyWalking.NetworkProtocol.SpanLayer spanLayer_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.SpanLayer SpanLayer { + get { return spanLayer_; } + set { + spanLayer_ = value; + } + } + + /// Field number for the "componentId" field. + public const int ComponentIdFieldNumber = 12; + private int componentId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ComponentId { + get { return componentId_; } + set { + componentId_ = value; + } + } + + /// Field number for the "component" field. + public const int ComponentFieldNumber = 13; + private string component_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Component { + get { return component_; } + set { + component_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "isError" field. + public const int IsErrorFieldNumber = 14; + private bool isError_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsError { + get { return isError_; } + set { + isError_ = value; + } + } + + /// Field number for the "tags" field. + public const int TagsFieldNumber = 15; + private static readonly pb::FieldCodec _repeated_tags_codec + = pb::FieldCodec.ForMessage(122, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField tags_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Tags { + get { return tags_; } + } + + /// Field number for the "logs" field. + public const int LogsFieldNumber = 16; + private static readonly pb::FieldCodec _repeated_logs_codec + = pb::FieldCodec.ForMessage(130, global::SkyWalking.NetworkProtocol.Log.Parser); + private readonly pbc::RepeatedField logs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Logs { + get { return logs_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SpanObjectV2); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SpanObjectV2 other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (SpanId != other.SpanId) return false; + if (ParentSpanId != other.ParentSpanId) return false; + if (StartTime != other.StartTime) return false; + if (EndTime != other.EndTime) return false; + if(!refs_.Equals(other.refs_)) return false; + if (OperationNameId != other.OperationNameId) return false; + if (OperationName != other.OperationName) return false; + if (PeerId != other.PeerId) return false; + if (Peer != other.Peer) return false; + if (SpanType != other.SpanType) return false; + if (SpanLayer != other.SpanLayer) return false; + if (ComponentId != other.ComponentId) return false; + if (Component != other.Component) return false; + if (IsError != other.IsError) return false; + if(!tags_.Equals(other.tags_)) return false; + if(!logs_.Equals(other.logs_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (SpanId != 0) hash ^= SpanId.GetHashCode(); + if (ParentSpanId != 0) hash ^= ParentSpanId.GetHashCode(); + if (StartTime != 0L) hash ^= StartTime.GetHashCode(); + if (EndTime != 0L) hash ^= EndTime.GetHashCode(); + hash ^= refs_.GetHashCode(); + if (OperationNameId != 0) hash ^= OperationNameId.GetHashCode(); + if (OperationName.Length != 0) hash ^= OperationName.GetHashCode(); + if (PeerId != 0) hash ^= PeerId.GetHashCode(); + if (Peer.Length != 0) hash ^= Peer.GetHashCode(); + if (SpanType != 0) hash ^= SpanType.GetHashCode(); + if (SpanLayer != 0) hash ^= SpanLayer.GetHashCode(); + if (ComponentId != 0) hash ^= ComponentId.GetHashCode(); + if (Component.Length != 0) hash ^= Component.GetHashCode(); + if (IsError != false) hash ^= IsError.GetHashCode(); + hash ^= tags_.GetHashCode(); + hash ^= logs_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (SpanId != 0) { + output.WriteRawTag(8); + output.WriteInt32(SpanId); + } + if (ParentSpanId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ParentSpanId); + } + if (StartTime != 0L) { + output.WriteRawTag(24); + output.WriteInt64(StartTime); + } + if (EndTime != 0L) { + output.WriteRawTag(32); + output.WriteInt64(EndTime); + } + refs_.WriteTo(output, _repeated_refs_codec); + if (OperationNameId != 0) { + output.WriteRawTag(48); + output.WriteInt32(OperationNameId); + } + if (OperationName.Length != 0) { + output.WriteRawTag(58); + output.WriteString(OperationName); + } + if (PeerId != 0) { + output.WriteRawTag(64); + output.WriteInt32(PeerId); + } + if (Peer.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Peer); + } + if (SpanType != 0) { + output.WriteRawTag(80); + output.WriteEnum((int) SpanType); + } + if (SpanLayer != 0) { + output.WriteRawTag(88); + output.WriteEnum((int) SpanLayer); + } + if (ComponentId != 0) { + output.WriteRawTag(96); + output.WriteInt32(ComponentId); + } + if (Component.Length != 0) { + output.WriteRawTag(106); + output.WriteString(Component); + } + if (IsError != false) { + output.WriteRawTag(112); + output.WriteBool(IsError); + } + tags_.WriteTo(output, _repeated_tags_codec); + logs_.WriteTo(output, _repeated_logs_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (SpanId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(SpanId); + } + if (ParentSpanId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentSpanId); + } + if (StartTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(StartTime); + } + if (EndTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(EndTime); + } + size += refs_.CalculateSize(_repeated_refs_codec); + if (OperationNameId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(OperationNameId); + } + if (OperationName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OperationName); + } + if (PeerId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(PeerId); + } + if (Peer.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Peer); + } + if (SpanType != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SpanType); + } + if (SpanLayer != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SpanLayer); + } + if (ComponentId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ComponentId); + } + if (Component.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Component); + } + if (IsError != false) { + size += 1 + 1; + } + size += tags_.CalculateSize(_repeated_tags_codec); + size += logs_.CalculateSize(_repeated_logs_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SpanObjectV2 other) { + if (other == null) { + return; + } + if (other.SpanId != 0) { + SpanId = other.SpanId; + } + if (other.ParentSpanId != 0) { + ParentSpanId = other.ParentSpanId; + } + if (other.StartTime != 0L) { + StartTime = other.StartTime; + } + if (other.EndTime != 0L) { + EndTime = other.EndTime; + } + refs_.Add(other.refs_); + if (other.OperationNameId != 0) { + OperationNameId = other.OperationNameId; + } + if (other.OperationName.Length != 0) { + OperationName = other.OperationName; + } + if (other.PeerId != 0) { + PeerId = other.PeerId; + } + if (other.Peer.Length != 0) { + Peer = other.Peer; + } + if (other.SpanType != 0) { + SpanType = other.SpanType; + } + if (other.SpanLayer != 0) { + SpanLayer = other.SpanLayer; + } + if (other.ComponentId != 0) { + ComponentId = other.ComponentId; + } + if (other.Component.Length != 0) { + Component = other.Component; + } + if (other.IsError != false) { + IsError = other.IsError; + } + tags_.Add(other.tags_); + logs_.Add(other.logs_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + SpanId = input.ReadInt32(); + break; + } + case 16: { + ParentSpanId = input.ReadInt32(); + break; + } + case 24: { + StartTime = input.ReadInt64(); + break; + } + case 32: { + EndTime = input.ReadInt64(); + break; + } + case 42: { + refs_.AddEntriesFrom(input, _repeated_refs_codec); + break; + } + case 48: { + OperationNameId = input.ReadInt32(); + break; + } + case 58: { + OperationName = input.ReadString(); + break; + } + case 64: { + PeerId = input.ReadInt32(); + break; + } + case 74: { + Peer = input.ReadString(); + break; + } + case 80: { + SpanType = (global::SkyWalking.NetworkProtocol.SpanType) input.ReadEnum(); + break; + } + case 88: { + SpanLayer = (global::SkyWalking.NetworkProtocol.SpanLayer) input.ReadEnum(); + break; + } + case 96: { + ComponentId = input.ReadInt32(); + break; + } + case 106: { + Component = input.ReadString(); + break; + } + case 112: { + IsError = input.ReadBool(); + break; + } + case 122: { + tags_.AddEntriesFrom(input, _repeated_tags_codec); + break; + } + case 130: { + logs_.AddEntriesFrom(input, _repeated_logs_codec); + break; + } + } + } + } + + } + + public sealed partial class Log : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Log()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Log() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Log(Log other) : this() { + time_ = other.time_; + data_ = other.data_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Log Clone() { + return new Log(this); + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 1; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "data" field. + public const int DataFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_data_codec + = pb::FieldCodec.ForMessage(18, global::SkyWalking.NetworkProtocol.KeyStringValuePair.Parser); + private readonly pbc::RepeatedField data_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Data { + get { return data_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Log); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Log other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Time != other.Time) return false; + if(!data_.Equals(other.data_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Time != 0L) hash ^= Time.GetHashCode(); + hash ^= data_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Time != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Time); + } + data_.WriteTo(output, _repeated_data_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + size += data_.CalculateSize(_repeated_data_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Log other) { + if (other == null) { + return; + } + if (other.Time != 0L) { + Time = other.Time; + } + data_.Add(other.data_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Time = input.ReadInt64(); + break; + } + case 18: { + data_.AddEntriesFrom(input, _repeated_data_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceCommon.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceCommon.cs new file mode 100644 index 000000000..925db691f --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceCommon.cs @@ -0,0 +1,348 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: common/trace-common.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from common/trace-common.proto + public static partial class TraceCommonReflection { + + #region Descriptor + /// File descriptor for common/trace-common.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static TraceCommonReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Chljb21tb24vdHJhY2UtY29tbW9uLnByb3RvIkUKD1Vwc3RyZWFtU2VnbWVu", + "dBIhCg5nbG9iYWxUcmFjZUlkcxgBIAMoCzIJLlVuaXF1ZUlkEg8KB3NlZ21l", + "bnQYAiABKAwiGwoIVW5pcXVlSWQSDwoHaWRQYXJ0cxgBIAMoAyoqCghTcGFu", + "VHlwZRIJCgVFbnRyeRAAEggKBEV4aXQQARIJCgVMb2NhbBACKiwKB1JlZlR5", + "cGUSEAoMQ3Jvc3NQcm9jZXNzEAASDwoLQ3Jvc3NUaHJlYWQQASpVCglTcGFu", + "TGF5ZXISCwoHVW5rbm93bhAAEgwKCERhdGFiYXNlEAESEAoMUlBDRnJhbWV3", + "b3JrEAISCAoESHR0cBADEgYKAk1REAQSCQoFQ2FjaGUQBUJRCjBvcmcuYXBh", + "Y2hlLnNreXdhbGtpbmcuYXBtLm5ldHdvcmsubGFuZ3VhZ2UuYWdlbnRQAaoC", + "GlNreVdhbGtpbmcuTmV0d29ya1Byb3RvY29sYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::SkyWalking.NetworkProtocol.SpanType), typeof(global::SkyWalking.NetworkProtocol.RefType), typeof(global::SkyWalking.NetworkProtocol.SpanLayer), }, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.UpstreamSegment), global::SkyWalking.NetworkProtocol.UpstreamSegment.Parser, new[]{ "GlobalTraceIds", "Segment" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.UniqueId), global::SkyWalking.NetworkProtocol.UniqueId.Parser, new[]{ "IdParts" }, null, null, null) + })); + } + #endregion + + } + #region Enums + public enum SpanType { + [pbr::OriginalName("Entry")] Entry = 0, + [pbr::OriginalName("Exit")] Exit = 1, + [pbr::OriginalName("Local")] Local = 2, + } + + public enum RefType { + [pbr::OriginalName("CrossProcess")] CrossProcess = 0, + [pbr::OriginalName("CrossThread")] CrossThread = 1, + } + + public enum SpanLayer { + [pbr::OriginalName("Unknown")] Unknown = 0, + [pbr::OriginalName("Database")] Database = 1, + [pbr::OriginalName("RPCFramework")] Rpcframework = 2, + [pbr::OriginalName("Http")] Http = 3, + [pbr::OriginalName("MQ")] Mq = 4, + [pbr::OriginalName("Cache")] Cache = 5, + } + + #endregion + + #region Messages + public sealed partial class UpstreamSegment : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UpstreamSegment()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceCommonReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpstreamSegment() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpstreamSegment(UpstreamSegment other) : this() { + globalTraceIds_ = other.globalTraceIds_.Clone(); + segment_ = other.segment_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UpstreamSegment Clone() { + return new UpstreamSegment(this); + } + + /// Field number for the "globalTraceIds" field. + public const int GlobalTraceIdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_globalTraceIds_codec + = pb::FieldCodec.ForMessage(10, global::SkyWalking.NetworkProtocol.UniqueId.Parser); + private readonly pbc::RepeatedField globalTraceIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField GlobalTraceIds { + get { return globalTraceIds_; } + } + + /// Field number for the "segment" field. + public const int SegmentFieldNumber = 2; + private pb::ByteString segment_ = pb::ByteString.Empty; + /// + /// the byte array of TraceSegmentObject + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Segment { + get { return segment_; } + set { + segment_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UpstreamSegment); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UpstreamSegment other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!globalTraceIds_.Equals(other.globalTraceIds_)) return false; + if (Segment != other.Segment) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= globalTraceIds_.GetHashCode(); + if (Segment.Length != 0) hash ^= Segment.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + globalTraceIds_.WriteTo(output, _repeated_globalTraceIds_codec); + if (Segment.Length != 0) { + output.WriteRawTag(18); + output.WriteBytes(Segment); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += globalTraceIds_.CalculateSize(_repeated_globalTraceIds_codec); + if (Segment.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Segment); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UpstreamSegment other) { + if (other == null) { + return; + } + globalTraceIds_.Add(other.globalTraceIds_); + if (other.Segment.Length != 0) { + Segment = other.Segment; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + globalTraceIds_.AddEntriesFrom(input, _repeated_globalTraceIds_codec); + break; + } + case 18: { + Segment = input.ReadBytes(); + break; + } + } + } + } + + } + + public sealed partial class UniqueId : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UniqueId()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceCommonReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UniqueId() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UniqueId(UniqueId other) : this() { + idParts_ = other.idParts_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UniqueId Clone() { + return new UniqueId(this); + } + + /// Field number for the "idParts" field. + public const int IdPartsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_idParts_codec + = pb::FieldCodec.ForInt64(10); + private readonly pbc::RepeatedField idParts_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField IdParts { + get { return idParts_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UniqueId); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UniqueId other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!idParts_.Equals(other.idParts_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= idParts_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + idParts_.WriteTo(output, _repeated_idParts_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += idParts_.CalculateSize(_repeated_idParts_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UniqueId other) { + if (other == null) { + return; + } + idParts_.Add(other.idParts_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: + case 8: { + idParts_.AddEntriesFrom(input, _repeated_idParts_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceGrpc.cs new file mode 100644 index 000000000..6c5b57c7b --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceGrpc.cs @@ -0,0 +1,117 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent-v2/trace.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class TraceSegmentReportService + { + static readonly string __ServiceName = "TraceSegmentReportService"; + + static readonly grpc::Marshaller __Marshaller_UpstreamSegment = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.UpstreamSegment.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Commands = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Commands.Parser.ParseFrom); + + static readonly grpc::Method __Method_collect = new grpc::Method( + grpc::MethodType.ClientStreaming, + __ServiceName, + "collect", + __Marshaller_UpstreamSegment, + __Marshaller_Commands); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.TraceReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of TraceSegmentReportService + [grpc::BindServiceMethod(typeof(TraceSegmentReportService), "BindService")] + public abstract partial class TraceSegmentReportServiceBase + { + public virtual global::System.Threading.Tasks.Task collect(grpc::IAsyncStreamReader requestStream, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for TraceSegmentReportService + public partial class TraceSegmentReportServiceClient : grpc::ClientBase + { + /// Creates a new client for TraceSegmentReportService + /// The channel to use to make remote calls. + public TraceSegmentReportServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for TraceSegmentReportService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public TraceSegmentReportServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected TraceSegmentReportServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected TraceSegmentReportServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual grpc::AsyncClientStreamingCall collect(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collect(new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncClientStreamingCall collect(grpc::CallOptions options) + { + return CallInvoker.AsyncClientStreamingCall(__Method_collect, null, options); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override TraceSegmentReportServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new TraceSegmentReportServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(TraceSegmentReportServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_collect, serviceImpl.collect).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, TraceSegmentReportServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_collect, serviceImpl == null ? null : new grpc::ClientStreamingServerMethod(serviceImpl.collect)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceSegmentService.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceSegmentService.cs new file mode 100644 index 000000000..8b1db78ca --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceSegmentService.cs @@ -0,0 +1,1400 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/TraceSegmentService.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace SkyWalking.NetworkProtocol { + + /// Holder for reflection information generated from language-agent/TraceSegmentService.proto + public static partial class TraceSegmentServiceReflection { + + #region Descriptor + /// File descriptor for language-agent/TraceSegmentService.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static TraceSegmentServiceReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CihsYW5ndWFnZS1hZ2VudC9UcmFjZVNlZ21lbnRTZXJ2aWNlLnByb3RvGh9s", + "YW5ndWFnZS1hZ2VudC9Eb3duc3RyZWFtLnByb3RvGidsYW5ndWFnZS1hZ2Vu", + "dC9LZXlXaXRoU3RyaW5nVmFsdWUucHJvdG8aGWNvbW1vbi90cmFjZS1jb21t", + "b24ucHJvdG8ioAEKElRyYWNlU2VnbWVudE9iamVjdBIhCg50cmFjZVNlZ21l", + "bnRJZBgBIAEoCzIJLlVuaXF1ZUlkEhoKBXNwYW5zGAIgAygLMgsuU3Bhbk9i", + "amVjdBIVCg1hcHBsaWNhdGlvbklkGAMgASgFEh0KFWFwcGxpY2F0aW9uSW5z", + "dGFuY2VJZBgEIAEoBRIVCg1pc1NpemVMaW1pdGVkGAUgASgIItICChVUcmFj", + "ZVNlZ21lbnRSZWZlcmVuY2USGQoHcmVmVHlwZRgBIAEoDjIILlJlZlR5cGUS", + "JwoUcGFyZW50VHJhY2VTZWdtZW50SWQYAiABKAsyCS5VbmlxdWVJZBIUCgxw", + "YXJlbnRTcGFuSWQYAyABKAUSIwobcGFyZW50QXBwbGljYXRpb25JbnN0YW5j", + "ZUlkGAQgASgFEhYKDm5ldHdvcmtBZGRyZXNzGAUgASgJEhgKEG5ldHdvcmtB", + "ZGRyZXNzSWQYBiABKAUSIgoaZW50cnlBcHBsaWNhdGlvbkluc3RhbmNlSWQY", + "ByABKAUSGAoQZW50cnlTZXJ2aWNlTmFtZRgIIAEoCRIWCg5lbnRyeVNlcnZp", + "Y2VJZBgJIAEoBRIZChFwYXJlbnRTZXJ2aWNlTmFtZRgKIAEoCRIXCg9wYXJl", + "bnRTZXJ2aWNlSWQYCyABKAUi/QIKClNwYW5PYmplY3QSDgoGc3BhbklkGAEg", + "ASgFEhQKDHBhcmVudFNwYW5JZBgCIAEoBRIRCglzdGFydFRpbWUYAyABKAMS", + "DwoHZW5kVGltZRgEIAEoAxIkCgRyZWZzGAUgAygLMhYuVHJhY2VTZWdtZW50", + "UmVmZXJlbmNlEhcKD29wZXJhdGlvbk5hbWVJZBgGIAEoBRIVCg1vcGVyYXRp", + "b25OYW1lGAcgASgJEg4KBnBlZXJJZBgIIAEoBRIMCgRwZWVyGAkgASgJEhsK", + "CHNwYW5UeXBlGAogASgOMgkuU3BhblR5cGUSHQoJc3BhbkxheWVyGAsgASgO", + "MgouU3BhbkxheWVyEhMKC2NvbXBvbmVudElkGAwgASgFEhEKCWNvbXBvbmVu", + "dBgNIAEoCRIPCgdpc0Vycm9yGA4gASgIEiEKBHRhZ3MYDyADKAsyEy5LZXlX", + "aXRoU3RyaW5nVmFsdWUSGQoEbG9ncxgQIAMoCzILLkxvZ01lc3NhZ2UiPQoK", + "TG9nTWVzc2FnZRIMCgR0aW1lGAEgASgDEiEKBGRhdGEYAiADKAsyEy5LZXlX", + "aXRoU3RyaW5nVmFsdWUyQwoTVHJhY2VTZWdtZW50U2VydmljZRIsCgdjb2xs", + "ZWN0EhAuVXBzdHJlYW1TZWdtZW50GgsuRG93bnN0cmVhbSIAKAFCUQowb3Jn", + "LmFwYWNoZS5za3l3YWxraW5nLmFwbS5uZXR3b3JrLmxhbmd1YWdlLmFnZW50", + "UAGqAhpTa3lXYWxraW5nLk5ldHdvcmtQcm90b2NvbGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::SkyWalking.NetworkProtocol.DownstreamReflection.Descriptor, global::SkyWalking.NetworkProtocol.KeyWithStringValueReflection.Descriptor, global::SkyWalking.NetworkProtocol.TraceCommonReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.TraceSegmentObject), global::SkyWalking.NetworkProtocol.TraceSegmentObject.Parser, new[]{ "TraceSegmentId", "Spans", "ApplicationId", "ApplicationInstanceId", "IsSizeLimited" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.TraceSegmentReference), global::SkyWalking.NetworkProtocol.TraceSegmentReference.Parser, new[]{ "RefType", "ParentTraceSegmentId", "ParentSpanId", "ParentApplicationInstanceId", "NetworkAddress", "NetworkAddressId", "EntryApplicationInstanceId", "EntryServiceName", "EntryServiceId", "ParentServiceName", "ParentServiceId" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.SpanObject), global::SkyWalking.NetworkProtocol.SpanObject.Parser, new[]{ "SpanId", "ParentSpanId", "StartTime", "EndTime", "Refs", "OperationNameId", "OperationName", "PeerId", "Peer", "SpanType", "SpanLayer", "ComponentId", "Component", "IsError", "Tags", "Logs" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::SkyWalking.NetworkProtocol.LogMessage), global::SkyWalking.NetworkProtocol.LogMessage.Parser, new[]{ "Time", "Data" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class TraceSegmentObject : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TraceSegmentObject()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceSegmentServiceReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TraceSegmentObject() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TraceSegmentObject(TraceSegmentObject other) : this() { + traceSegmentId_ = other.traceSegmentId_ != null ? other.traceSegmentId_.Clone() : null; + spans_ = other.spans_.Clone(); + applicationId_ = other.applicationId_; + applicationInstanceId_ = other.applicationInstanceId_; + isSizeLimited_ = other.isSizeLimited_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TraceSegmentObject Clone() { + return new TraceSegmentObject(this); + } + + /// Field number for the "traceSegmentId" field. + public const int TraceSegmentIdFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.UniqueId traceSegmentId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.UniqueId TraceSegmentId { + get { return traceSegmentId_; } + set { + traceSegmentId_ = value; + } + } + + /// Field number for the "spans" field. + public const int SpansFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_spans_codec + = pb::FieldCodec.ForMessage(18, global::SkyWalking.NetworkProtocol.SpanObject.Parser); + private readonly pbc::RepeatedField spans_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Spans { + get { return spans_; } + } + + /// Field number for the "applicationId" field. + public const int ApplicationIdFieldNumber = 3; + private int applicationId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationId { + get { return applicationId_; } + set { + applicationId_ = value; + } + } + + /// Field number for the "applicationInstanceId" field. + public const int ApplicationInstanceIdFieldNumber = 4; + private int applicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ApplicationInstanceId { + get { return applicationInstanceId_; } + set { + applicationInstanceId_ = value; + } + } + + /// Field number for the "isSizeLimited" field. + public const int IsSizeLimitedFieldNumber = 5; + private bool isSizeLimited_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsSizeLimited { + get { return isSizeLimited_; } + set { + isSizeLimited_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TraceSegmentObject); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TraceSegmentObject other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(TraceSegmentId, other.TraceSegmentId)) return false; + if(!spans_.Equals(other.spans_)) return false; + if (ApplicationId != other.ApplicationId) return false; + if (ApplicationInstanceId != other.ApplicationInstanceId) return false; + if (IsSizeLimited != other.IsSizeLimited) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (traceSegmentId_ != null) hash ^= TraceSegmentId.GetHashCode(); + hash ^= spans_.GetHashCode(); + if (ApplicationId != 0) hash ^= ApplicationId.GetHashCode(); + if (ApplicationInstanceId != 0) hash ^= ApplicationInstanceId.GetHashCode(); + if (IsSizeLimited != false) hash ^= IsSizeLimited.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (traceSegmentId_ != null) { + output.WriteRawTag(10); + output.WriteMessage(TraceSegmentId); + } + spans_.WriteTo(output, _repeated_spans_codec); + if (ApplicationId != 0) { + output.WriteRawTag(24); + output.WriteInt32(ApplicationId); + } + if (ApplicationInstanceId != 0) { + output.WriteRawTag(32); + output.WriteInt32(ApplicationInstanceId); + } + if (IsSizeLimited != false) { + output.WriteRawTag(40); + output.WriteBool(IsSizeLimited); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (traceSegmentId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TraceSegmentId); + } + size += spans_.CalculateSize(_repeated_spans_codec); + if (ApplicationId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationId); + } + if (ApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ApplicationInstanceId); + } + if (IsSizeLimited != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TraceSegmentObject other) { + if (other == null) { + return; + } + if (other.traceSegmentId_ != null) { + if (traceSegmentId_ == null) { + TraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + TraceSegmentId.MergeFrom(other.TraceSegmentId); + } + spans_.Add(other.spans_); + if (other.ApplicationId != 0) { + ApplicationId = other.ApplicationId; + } + if (other.ApplicationInstanceId != 0) { + ApplicationInstanceId = other.ApplicationInstanceId; + } + if (other.IsSizeLimited != false) { + IsSizeLimited = other.IsSizeLimited; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (traceSegmentId_ == null) { + TraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + input.ReadMessage(TraceSegmentId); + break; + } + case 18: { + spans_.AddEntriesFrom(input, _repeated_spans_codec); + break; + } + case 24: { + ApplicationId = input.ReadInt32(); + break; + } + case 32: { + ApplicationInstanceId = input.ReadInt32(); + break; + } + case 40: { + IsSizeLimited = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class TraceSegmentReference : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TraceSegmentReference()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceSegmentServiceReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TraceSegmentReference() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TraceSegmentReference(TraceSegmentReference other) : this() { + refType_ = other.refType_; + parentTraceSegmentId_ = other.parentTraceSegmentId_ != null ? other.parentTraceSegmentId_.Clone() : null; + parentSpanId_ = other.parentSpanId_; + parentApplicationInstanceId_ = other.parentApplicationInstanceId_; + networkAddress_ = other.networkAddress_; + networkAddressId_ = other.networkAddressId_; + entryApplicationInstanceId_ = other.entryApplicationInstanceId_; + entryServiceName_ = other.entryServiceName_; + entryServiceId_ = other.entryServiceId_; + parentServiceName_ = other.parentServiceName_; + parentServiceId_ = other.parentServiceId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TraceSegmentReference Clone() { + return new TraceSegmentReference(this); + } + + /// Field number for the "refType" field. + public const int RefTypeFieldNumber = 1; + private global::SkyWalking.NetworkProtocol.RefType refType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.RefType RefType { + get { return refType_; } + set { + refType_ = value; + } + } + + /// Field number for the "parentTraceSegmentId" field. + public const int ParentTraceSegmentIdFieldNumber = 2; + private global::SkyWalking.NetworkProtocol.UniqueId parentTraceSegmentId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.UniqueId ParentTraceSegmentId { + get { return parentTraceSegmentId_; } + set { + parentTraceSegmentId_ = value; + } + } + + /// Field number for the "parentSpanId" field. + public const int ParentSpanIdFieldNumber = 3; + private int parentSpanId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentSpanId { + get { return parentSpanId_; } + set { + parentSpanId_ = value; + } + } + + /// Field number for the "parentApplicationInstanceId" field. + public const int ParentApplicationInstanceIdFieldNumber = 4; + private int parentApplicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentApplicationInstanceId { + get { return parentApplicationInstanceId_; } + set { + parentApplicationInstanceId_ = value; + } + } + + /// Field number for the "networkAddress" field. + public const int NetworkAddressFieldNumber = 5; + private string networkAddress_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NetworkAddress { + get { return networkAddress_; } + set { + networkAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "networkAddressId" field. + public const int NetworkAddressIdFieldNumber = 6; + private int networkAddressId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int NetworkAddressId { + get { return networkAddressId_; } + set { + networkAddressId_ = value; + } + } + + /// Field number for the "entryApplicationInstanceId" field. + public const int EntryApplicationInstanceIdFieldNumber = 7; + private int entryApplicationInstanceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int EntryApplicationInstanceId { + get { return entryApplicationInstanceId_; } + set { + entryApplicationInstanceId_ = value; + } + } + + /// Field number for the "entryServiceName" field. + public const int EntryServiceNameFieldNumber = 8; + private string entryServiceName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string EntryServiceName { + get { return entryServiceName_; } + set { + entryServiceName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "entryServiceId" field. + public const int EntryServiceIdFieldNumber = 9; + private int entryServiceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int EntryServiceId { + get { return entryServiceId_; } + set { + entryServiceId_ = value; + } + } + + /// Field number for the "parentServiceName" field. + public const int ParentServiceNameFieldNumber = 10; + private string parentServiceName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ParentServiceName { + get { return parentServiceName_; } + set { + parentServiceName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "parentServiceId" field. + public const int ParentServiceIdFieldNumber = 11; + private int parentServiceId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentServiceId { + get { return parentServiceId_; } + set { + parentServiceId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TraceSegmentReference); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TraceSegmentReference other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (RefType != other.RefType) return false; + if (!object.Equals(ParentTraceSegmentId, other.ParentTraceSegmentId)) return false; + if (ParentSpanId != other.ParentSpanId) return false; + if (ParentApplicationInstanceId != other.ParentApplicationInstanceId) return false; + if (NetworkAddress != other.NetworkAddress) return false; + if (NetworkAddressId != other.NetworkAddressId) return false; + if (EntryApplicationInstanceId != other.EntryApplicationInstanceId) return false; + if (EntryServiceName != other.EntryServiceName) return false; + if (EntryServiceId != other.EntryServiceId) return false; + if (ParentServiceName != other.ParentServiceName) return false; + if (ParentServiceId != other.ParentServiceId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (RefType != 0) hash ^= RefType.GetHashCode(); + if (parentTraceSegmentId_ != null) hash ^= ParentTraceSegmentId.GetHashCode(); + if (ParentSpanId != 0) hash ^= ParentSpanId.GetHashCode(); + if (ParentApplicationInstanceId != 0) hash ^= ParentApplicationInstanceId.GetHashCode(); + if (NetworkAddress.Length != 0) hash ^= NetworkAddress.GetHashCode(); + if (NetworkAddressId != 0) hash ^= NetworkAddressId.GetHashCode(); + if (EntryApplicationInstanceId != 0) hash ^= EntryApplicationInstanceId.GetHashCode(); + if (EntryServiceName.Length != 0) hash ^= EntryServiceName.GetHashCode(); + if (EntryServiceId != 0) hash ^= EntryServiceId.GetHashCode(); + if (ParentServiceName.Length != 0) hash ^= ParentServiceName.GetHashCode(); + if (ParentServiceId != 0) hash ^= ParentServiceId.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (RefType != 0) { + output.WriteRawTag(8); + output.WriteEnum((int) RefType); + } + if (parentTraceSegmentId_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ParentTraceSegmentId); + } + if (ParentSpanId != 0) { + output.WriteRawTag(24); + output.WriteInt32(ParentSpanId); + } + if (ParentApplicationInstanceId != 0) { + output.WriteRawTag(32); + output.WriteInt32(ParentApplicationInstanceId); + } + if (NetworkAddress.Length != 0) { + output.WriteRawTag(42); + output.WriteString(NetworkAddress); + } + if (NetworkAddressId != 0) { + output.WriteRawTag(48); + output.WriteInt32(NetworkAddressId); + } + if (EntryApplicationInstanceId != 0) { + output.WriteRawTag(56); + output.WriteInt32(EntryApplicationInstanceId); + } + if (EntryServiceName.Length != 0) { + output.WriteRawTag(66); + output.WriteString(EntryServiceName); + } + if (EntryServiceId != 0) { + output.WriteRawTag(72); + output.WriteInt32(EntryServiceId); + } + if (ParentServiceName.Length != 0) { + output.WriteRawTag(82); + output.WriteString(ParentServiceName); + } + if (ParentServiceId != 0) { + output.WriteRawTag(88); + output.WriteInt32(ParentServiceId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (RefType != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RefType); + } + if (parentTraceSegmentId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ParentTraceSegmentId); + } + if (ParentSpanId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentSpanId); + } + if (ParentApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentApplicationInstanceId); + } + if (NetworkAddress.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NetworkAddress); + } + if (NetworkAddressId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(NetworkAddressId); + } + if (EntryApplicationInstanceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(EntryApplicationInstanceId); + } + if (EntryServiceName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(EntryServiceName); + } + if (EntryServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(EntryServiceId); + } + if (ParentServiceName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ParentServiceName); + } + if (ParentServiceId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentServiceId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TraceSegmentReference other) { + if (other == null) { + return; + } + if (other.RefType != 0) { + RefType = other.RefType; + } + if (other.parentTraceSegmentId_ != null) { + if (parentTraceSegmentId_ == null) { + ParentTraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + ParentTraceSegmentId.MergeFrom(other.ParentTraceSegmentId); + } + if (other.ParentSpanId != 0) { + ParentSpanId = other.ParentSpanId; + } + if (other.ParentApplicationInstanceId != 0) { + ParentApplicationInstanceId = other.ParentApplicationInstanceId; + } + if (other.NetworkAddress.Length != 0) { + NetworkAddress = other.NetworkAddress; + } + if (other.NetworkAddressId != 0) { + NetworkAddressId = other.NetworkAddressId; + } + if (other.EntryApplicationInstanceId != 0) { + EntryApplicationInstanceId = other.EntryApplicationInstanceId; + } + if (other.EntryServiceName.Length != 0) { + EntryServiceName = other.EntryServiceName; + } + if (other.EntryServiceId != 0) { + EntryServiceId = other.EntryServiceId; + } + if (other.ParentServiceName.Length != 0) { + ParentServiceName = other.ParentServiceName; + } + if (other.ParentServiceId != 0) { + ParentServiceId = other.ParentServiceId; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + RefType = (global::SkyWalking.NetworkProtocol.RefType) input.ReadEnum(); + break; + } + case 18: { + if (parentTraceSegmentId_ == null) { + ParentTraceSegmentId = new global::SkyWalking.NetworkProtocol.UniqueId(); + } + input.ReadMessage(ParentTraceSegmentId); + break; + } + case 24: { + ParentSpanId = input.ReadInt32(); + break; + } + case 32: { + ParentApplicationInstanceId = input.ReadInt32(); + break; + } + case 42: { + NetworkAddress = input.ReadString(); + break; + } + case 48: { + NetworkAddressId = input.ReadInt32(); + break; + } + case 56: { + EntryApplicationInstanceId = input.ReadInt32(); + break; + } + case 66: { + EntryServiceName = input.ReadString(); + break; + } + case 72: { + EntryServiceId = input.ReadInt32(); + break; + } + case 82: { + ParentServiceName = input.ReadString(); + break; + } + case 88: { + ParentServiceId = input.ReadInt32(); + break; + } + } + } + } + + } + + public sealed partial class SpanObject : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SpanObject()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceSegmentServiceReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SpanObject() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SpanObject(SpanObject other) : this() { + spanId_ = other.spanId_; + parentSpanId_ = other.parentSpanId_; + startTime_ = other.startTime_; + endTime_ = other.endTime_; + refs_ = other.refs_.Clone(); + operationNameId_ = other.operationNameId_; + operationName_ = other.operationName_; + peerId_ = other.peerId_; + peer_ = other.peer_; + spanType_ = other.spanType_; + spanLayer_ = other.spanLayer_; + componentId_ = other.componentId_; + component_ = other.component_; + isError_ = other.isError_; + tags_ = other.tags_.Clone(); + logs_ = other.logs_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SpanObject Clone() { + return new SpanObject(this); + } + + /// Field number for the "spanId" field. + public const int SpanIdFieldNumber = 1; + private int spanId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int SpanId { + get { return spanId_; } + set { + spanId_ = value; + } + } + + /// Field number for the "parentSpanId" field. + public const int ParentSpanIdFieldNumber = 2; + private int parentSpanId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ParentSpanId { + get { return parentSpanId_; } + set { + parentSpanId_ = value; + } + } + + /// Field number for the "startTime" field. + public const int StartTimeFieldNumber = 3; + private long startTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long StartTime { + get { return startTime_; } + set { + startTime_ = value; + } + } + + /// Field number for the "endTime" field. + public const int EndTimeFieldNumber = 4; + private long endTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long EndTime { + get { return endTime_; } + set { + endTime_ = value; + } + } + + /// Field number for the "refs" field. + public const int RefsFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_refs_codec + = pb::FieldCodec.ForMessage(42, global::SkyWalking.NetworkProtocol.TraceSegmentReference.Parser); + private readonly pbc::RepeatedField refs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Refs { + get { return refs_; } + } + + /// Field number for the "operationNameId" field. + public const int OperationNameIdFieldNumber = 6; + private int operationNameId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int OperationNameId { + get { return operationNameId_; } + set { + operationNameId_ = value; + } + } + + /// Field number for the "operationName" field. + public const int OperationNameFieldNumber = 7; + private string operationName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string OperationName { + get { return operationName_; } + set { + operationName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "peerId" field. + public const int PeerIdFieldNumber = 8; + private int peerId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int PeerId { + get { return peerId_; } + set { + peerId_ = value; + } + } + + /// Field number for the "peer" field. + public const int PeerFieldNumber = 9; + private string peer_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Peer { + get { return peer_; } + set { + peer_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "spanType" field. + public const int SpanTypeFieldNumber = 10; + private global::SkyWalking.NetworkProtocol.SpanType spanType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.SpanType SpanType { + get { return spanType_; } + set { + spanType_ = value; + } + } + + /// Field number for the "spanLayer" field. + public const int SpanLayerFieldNumber = 11; + private global::SkyWalking.NetworkProtocol.SpanLayer spanLayer_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::SkyWalking.NetworkProtocol.SpanLayer SpanLayer { + get { return spanLayer_; } + set { + spanLayer_ = value; + } + } + + /// Field number for the "componentId" field. + public const int ComponentIdFieldNumber = 12; + private int componentId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int ComponentId { + get { return componentId_; } + set { + componentId_ = value; + } + } + + /// Field number for the "component" field. + public const int ComponentFieldNumber = 13; + private string component_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Component { + get { return component_; } + set { + component_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "isError" field. + public const int IsErrorFieldNumber = 14; + private bool isError_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsError { + get { return isError_; } + set { + isError_ = value; + } + } + + /// Field number for the "tags" field. + public const int TagsFieldNumber = 15; + private static readonly pb::FieldCodec _repeated_tags_codec + = pb::FieldCodec.ForMessage(122, global::SkyWalking.NetworkProtocol.KeyWithStringValue.Parser); + private readonly pbc::RepeatedField tags_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Tags { + get { return tags_; } + } + + /// Field number for the "logs" field. + public const int LogsFieldNumber = 16; + private static readonly pb::FieldCodec _repeated_logs_codec + = pb::FieldCodec.ForMessage(130, global::SkyWalking.NetworkProtocol.LogMessage.Parser); + private readonly pbc::RepeatedField logs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Logs { + get { return logs_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SpanObject); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SpanObject other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (SpanId != other.SpanId) return false; + if (ParentSpanId != other.ParentSpanId) return false; + if (StartTime != other.StartTime) return false; + if (EndTime != other.EndTime) return false; + if(!refs_.Equals(other.refs_)) return false; + if (OperationNameId != other.OperationNameId) return false; + if (OperationName != other.OperationName) return false; + if (PeerId != other.PeerId) return false; + if (Peer != other.Peer) return false; + if (SpanType != other.SpanType) return false; + if (SpanLayer != other.SpanLayer) return false; + if (ComponentId != other.ComponentId) return false; + if (Component != other.Component) return false; + if (IsError != other.IsError) return false; + if(!tags_.Equals(other.tags_)) return false; + if(!logs_.Equals(other.logs_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (SpanId != 0) hash ^= SpanId.GetHashCode(); + if (ParentSpanId != 0) hash ^= ParentSpanId.GetHashCode(); + if (StartTime != 0L) hash ^= StartTime.GetHashCode(); + if (EndTime != 0L) hash ^= EndTime.GetHashCode(); + hash ^= refs_.GetHashCode(); + if (OperationNameId != 0) hash ^= OperationNameId.GetHashCode(); + if (OperationName.Length != 0) hash ^= OperationName.GetHashCode(); + if (PeerId != 0) hash ^= PeerId.GetHashCode(); + if (Peer.Length != 0) hash ^= Peer.GetHashCode(); + if (SpanType != 0) hash ^= SpanType.GetHashCode(); + if (SpanLayer != 0) hash ^= SpanLayer.GetHashCode(); + if (ComponentId != 0) hash ^= ComponentId.GetHashCode(); + if (Component.Length != 0) hash ^= Component.GetHashCode(); + if (IsError != false) hash ^= IsError.GetHashCode(); + hash ^= tags_.GetHashCode(); + hash ^= logs_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (SpanId != 0) { + output.WriteRawTag(8); + output.WriteInt32(SpanId); + } + if (ParentSpanId != 0) { + output.WriteRawTag(16); + output.WriteInt32(ParentSpanId); + } + if (StartTime != 0L) { + output.WriteRawTag(24); + output.WriteInt64(StartTime); + } + if (EndTime != 0L) { + output.WriteRawTag(32); + output.WriteInt64(EndTime); + } + refs_.WriteTo(output, _repeated_refs_codec); + if (OperationNameId != 0) { + output.WriteRawTag(48); + output.WriteInt32(OperationNameId); + } + if (OperationName.Length != 0) { + output.WriteRawTag(58); + output.WriteString(OperationName); + } + if (PeerId != 0) { + output.WriteRawTag(64); + output.WriteInt32(PeerId); + } + if (Peer.Length != 0) { + output.WriteRawTag(74); + output.WriteString(Peer); + } + if (SpanType != 0) { + output.WriteRawTag(80); + output.WriteEnum((int) SpanType); + } + if (SpanLayer != 0) { + output.WriteRawTag(88); + output.WriteEnum((int) SpanLayer); + } + if (ComponentId != 0) { + output.WriteRawTag(96); + output.WriteInt32(ComponentId); + } + if (Component.Length != 0) { + output.WriteRawTag(106); + output.WriteString(Component); + } + if (IsError != false) { + output.WriteRawTag(112); + output.WriteBool(IsError); + } + tags_.WriteTo(output, _repeated_tags_codec); + logs_.WriteTo(output, _repeated_logs_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (SpanId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(SpanId); + } + if (ParentSpanId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ParentSpanId); + } + if (StartTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(StartTime); + } + if (EndTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(EndTime); + } + size += refs_.CalculateSize(_repeated_refs_codec); + if (OperationNameId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(OperationNameId); + } + if (OperationName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OperationName); + } + if (PeerId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(PeerId); + } + if (Peer.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Peer); + } + if (SpanType != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SpanType); + } + if (SpanLayer != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SpanLayer); + } + if (ComponentId != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ComponentId); + } + if (Component.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Component); + } + if (IsError != false) { + size += 1 + 1; + } + size += tags_.CalculateSize(_repeated_tags_codec); + size += logs_.CalculateSize(_repeated_logs_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SpanObject other) { + if (other == null) { + return; + } + if (other.SpanId != 0) { + SpanId = other.SpanId; + } + if (other.ParentSpanId != 0) { + ParentSpanId = other.ParentSpanId; + } + if (other.StartTime != 0L) { + StartTime = other.StartTime; + } + if (other.EndTime != 0L) { + EndTime = other.EndTime; + } + refs_.Add(other.refs_); + if (other.OperationNameId != 0) { + OperationNameId = other.OperationNameId; + } + if (other.OperationName.Length != 0) { + OperationName = other.OperationName; + } + if (other.PeerId != 0) { + PeerId = other.PeerId; + } + if (other.Peer.Length != 0) { + Peer = other.Peer; + } + if (other.SpanType != 0) { + SpanType = other.SpanType; + } + if (other.SpanLayer != 0) { + SpanLayer = other.SpanLayer; + } + if (other.ComponentId != 0) { + ComponentId = other.ComponentId; + } + if (other.Component.Length != 0) { + Component = other.Component; + } + if (other.IsError != false) { + IsError = other.IsError; + } + tags_.Add(other.tags_); + logs_.Add(other.logs_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + SpanId = input.ReadInt32(); + break; + } + case 16: { + ParentSpanId = input.ReadInt32(); + break; + } + case 24: { + StartTime = input.ReadInt64(); + break; + } + case 32: { + EndTime = input.ReadInt64(); + break; + } + case 42: { + refs_.AddEntriesFrom(input, _repeated_refs_codec); + break; + } + case 48: { + OperationNameId = input.ReadInt32(); + break; + } + case 58: { + OperationName = input.ReadString(); + break; + } + case 64: { + PeerId = input.ReadInt32(); + break; + } + case 74: { + Peer = input.ReadString(); + break; + } + case 80: { + SpanType = (global::SkyWalking.NetworkProtocol.SpanType) input.ReadEnum(); + break; + } + case 88: { + SpanLayer = (global::SkyWalking.NetworkProtocol.SpanLayer) input.ReadEnum(); + break; + } + case 96: { + ComponentId = input.ReadInt32(); + break; + } + case 106: { + Component = input.ReadString(); + break; + } + case 112: { + IsError = input.ReadBool(); + break; + } + case 122: { + tags_.AddEntriesFrom(input, _repeated_tags_codec); + break; + } + case 130: { + logs_.AddEntriesFrom(input, _repeated_logs_codec); + break; + } + } + } + } + + } + + public sealed partial class LogMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new LogMessage()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::SkyWalking.NetworkProtocol.TraceSegmentServiceReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public LogMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public LogMessage(LogMessage other) : this() { + time_ = other.time_; + data_ = other.data_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public LogMessage Clone() { + return new LogMessage(this); + } + + /// Field number for the "time" field. + public const int TimeFieldNumber = 1; + private long time_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Time { + get { return time_; } + set { + time_ = value; + } + } + + /// Field number for the "data" field. + public const int DataFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_data_codec + = pb::FieldCodec.ForMessage(18, global::SkyWalking.NetworkProtocol.KeyWithStringValue.Parser); + private readonly pbc::RepeatedField data_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Data { + get { return data_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as LogMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(LogMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Time != other.Time) return false; + if(!data_.Equals(other.data_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Time != 0L) hash ^= Time.GetHashCode(); + hash ^= data_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Time != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Time); + } + data_.WriteTo(output, _repeated_data_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Time != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); + } + size += data_.CalculateSize(_repeated_data_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(LogMessage other) { + if (other == null) { + return; + } + if (other.Time != 0L) { + Time = other.Time; + } + data_.Add(other.data_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Time = input.ReadInt64(); + break; + } + case 18: { + data_.AddEntriesFrom(input, _repeated_data_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceSegmentServiceGrpc.cs b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceSegmentServiceGrpc.cs new file mode 100644 index 000000000..14e0eae7d --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/generated/TraceSegmentServiceGrpc.cs @@ -0,0 +1,117 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: language-agent/TraceSegmentService.proto +// +// Original file comments: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +#pragma warning disable 0414, 1591 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace SkyWalking.NetworkProtocol { + public static partial class TraceSegmentService + { + static readonly string __ServiceName = "TraceSegmentService"; + + static readonly grpc::Marshaller __Marshaller_UpstreamSegment = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.UpstreamSegment.Parser.ParseFrom); + static readonly grpc::Marshaller __Marshaller_Downstream = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::SkyWalking.NetworkProtocol.Downstream.Parser.ParseFrom); + + static readonly grpc::Method __Method_collect = new grpc::Method( + grpc::MethodType.ClientStreaming, + __ServiceName, + "collect", + __Marshaller_UpstreamSegment, + __Marshaller_Downstream); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::SkyWalking.NetworkProtocol.TraceSegmentServiceReflection.Descriptor.Services[0]; } + } + + /// Base class for server-side implementations of TraceSegmentService + [grpc::BindServiceMethod(typeof(TraceSegmentService), "BindService")] + public abstract partial class TraceSegmentServiceBase + { + public virtual global::System.Threading.Tasks.Task collect(grpc::IAsyncStreamReader requestStream, grpc::ServerCallContext context) + { + throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); + } + + } + + /// Client for TraceSegmentService + public partial class TraceSegmentServiceClient : grpc::ClientBase + { + /// Creates a new client for TraceSegmentService + /// The channel to use to make remote calls. + public TraceSegmentServiceClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for TraceSegmentService that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + public TraceSegmentServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + protected TraceSegmentServiceClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + protected TraceSegmentServiceClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + public virtual grpc::AsyncClientStreamingCall collect(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return collect(new grpc::CallOptions(headers, deadline, cancellationToken)); + } + public virtual grpc::AsyncClientStreamingCall collect(grpc::CallOptions options) + { + return CallInvoker.AsyncClientStreamingCall(__Method_collect, null, options); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + protected override TraceSegmentServiceClient NewInstance(ClientBaseConfiguration configuration) + { + return new TraceSegmentServiceClient(configuration); + } + } + + /// Creates service definition that can be registered with a server + /// An object implementing the server-side handling logic. + public static grpc::ServerServiceDefinition BindService(TraceSegmentServiceBase serviceImpl) + { + return grpc::ServerServiceDefinition.CreateBuilder() + .AddMethod(__Method_collect, serviceImpl.collect).Build(); + } + + /// Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + /// Note: this method is part of an experimental API that can change or be removed without any prior notice. + /// Service methods will be bound by calling AddMethod on this object. + /// An object implementing the server-side handling logic. + public static void BindService(grpc::ServiceBinderBase serviceBinder, TraceSegmentServiceBase serviceImpl) + { + serviceBinder.AddMethod(__Method_collect, serviceImpl == null ? null : new grpc::ClientStreamingServerMethod(serviceImpl.collect)); + } + + } +} +#endregion diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/README.md b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/README.md new file mode 100644 index 000000000..536bc1f2e --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/README.md @@ -0,0 +1,5 @@ +# Apache SkyWalking data collect protocol +Apache SkyWalking can collect data from different sources. Each kind of source should follow the protocols in this repo. + +## License +Apache 2.0 diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/CLR.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/CLR.proto new file mode 100644 index 000000000..57bc8600f --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/CLR.proto @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; + +message CLRMetric { + int64 time = 1; + CPU cpu = 2; + ClrGC gc = 3; + ClrThread thread = 4; +} + +message ClrGC { + int64 Gen0CollectCount = 1; + int64 Gen1CollectCount = 2; + int64 Gen2CollectCount = 3; + int64 HeapMemory = 4; +} + +message ClrThread { + int32 AvailableCompletionPortThreads = 1; + int32 AvailableWorkerThreads = 2; + int32 MaxCompletionPortThreads = 3; + int32 MaxWorkerThreads = 4; +} \ No newline at end of file diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/JVM.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/JVM.proto new file mode 100644 index 000000000..543c640dc --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/JVM.proto @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; + +message JVMMetric { + int64 time = 1; + CPU cpu = 2; + repeated Memory memory = 3; + repeated MemoryPool memoryPool = 4; + repeated GC gc = 5; +} + +message Memory { + bool isHeap = 1; + int64 init = 2; + int64 max = 3; + int64 used = 4; + int64 committed = 5; +} + +message MemoryPool { + PoolType type = 1; + int64 init = 2; + int64 max = 3; + int64 used = 4; + int64 commited = 5; +} + +enum PoolType { + CODE_CACHE_USAGE = 0; + NEWGEN_USAGE = 1; + OLDGEN_USAGE = 2; + SURVIVOR_USAGE = 3; + PERMGEN_USAGE = 4; + METASPACE_USAGE = 5; +} + +message GC { + GCPhrase phrase = 1; + int64 count = 2; + int64 time = 3; +} + +enum GCPhrase { + NEW = 0; + OLD = 1; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/common.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/common.proto new file mode 100644 index 000000000..ce50c7662 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/common.proto @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.common"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +message KeyStringValuePair { + string key = 1; + string value = 2; +} + +message KeyIntValuePair { + string key = 1; + int32 value = 2; +} + +message CPU { + double usagePercent = 2; +} + +// In most cases, detect point should be `server` or `client`. +// Even in service mesh, this means `server`/`client` side sidecar +// `proxy` is reserved only. +enum DetectPoint { + client = 0; + server = 1; + proxy = 2; +} + +message Commands { + repeated Command commands = 1; +} + +message Command { + string command = 1; + repeated KeyStringValuePair args = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/trace-common.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/trace-common.proto new file mode 100644 index 000000000..dcbe03d16 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/common/trace-common.proto @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +message UpstreamSegment { + repeated UniqueId globalTraceIds = 1; + bytes segment = 2; // the byte array of TraceSegmentObject +} + +enum SpanType { + Entry = 0; + Exit = 1; + Local = 2; +} + +message UniqueId { + repeated int64 idParts = 1; +} + +enum RefType { + CrossProcess = 0; + CrossThread = 1; +} + +enum SpanLayer { + Unknown = 0; + Database = 1; + RPCFramework = 2; + Http = 3; + MQ = 4; + Cache = 5; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/CLRMetric.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/CLRMetric.proto new file mode 100644 index 000000000..da023b6a2 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/CLRMetric.proto @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent.v2"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; +import "common/CLR.proto"; + +service CLRMetricReportService { + rpc collect (CLRMetricCollection) returns (Commands) { + } +} + +message CLRMetricCollection { + repeated CLRMetric metrics = 1; + int32 serviceInstanceId = 2; +} \ No newline at end of file diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/JVMMetric.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/JVMMetric.proto new file mode 100644 index 000000000..845624cdf --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/JVMMetric.proto @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent.v2"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; +import "common/JVM.proto"; + +service JVMMetricReportService { + rpc collect (JVMMetricCollection) returns (Commands) { + } +} + +message JVMMetricCollection { + repeated JVMMetric metrics = 1; + int32 serviceInstanceId = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/trace.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/trace.proto new file mode 100644 index 000000000..c6120c585 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent-v2/trace.proto @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent.v2"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; +import "common/trace-common.proto"; + +service TraceSegmentReportService { + rpc collect (stream UpstreamSegment) returns (Commands) { + } +} + +message SegmentObject { + UniqueId traceSegmentId = 1; + repeated SpanObjectV2 spans = 2; + int32 serviceId = 3; + int32 serviceInstanceId = 4; + bool isSizeLimited = 5; +} + +message SegmentReference { + RefType refType = 1; + UniqueId parentTraceSegmentId = 2; + int32 parentSpanId = 3; + int32 parentServiceInstanceId = 4; + string networkAddress = 5; + int32 networkAddressId = 6; + int32 entryServiceInstanceId = 7; + string entryEndpoint = 8; + int32 entryEndpointId = 9; + string parentEndpoint = 10; + int32 parentEndpointId = 11; +} + +message SpanObjectV2 { + int32 spanId = 1; + int32 parentSpanId = 2; + int64 startTime = 3; + int64 endTime = 4; + repeated SegmentReference refs = 5; + int32 operationNameId = 6; + string operationName = 7; + int32 peerId = 8; + string peer = 9; + SpanType spanType = 10; + SpanLayer spanLayer = 11; + int32 componentId = 12; + string component = 13; + bool isError = 14; + repeated KeyStringValuePair tags = 15; + repeated Log logs = 16; +} + +message Log { + int64 time = 1; + repeated KeyStringValuePair data = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/ApplicationRegisterService.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/ApplicationRegisterService.proto new file mode 100644 index 000000000..fd8ee0d4d --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/ApplicationRegisterService.proto @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "language-agent/KeyWithIntegerValue.proto"; + +//register service for ApplicationCode, this service is called when service starts. +service ApplicationRegisterService { + rpc applicationCodeRegister (Application) returns (ApplicationMapping) { + } +} + +message Application { + string applicationCode = 1; +} + +message ApplicationMapping { + KeyWithIntegerValue application = 1; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/DiscoveryService.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/DiscoveryService.proto new file mode 100644 index 000000000..bc392a72c --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/DiscoveryService.proto @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "language-agent/Downstream.proto"; +import "common/trace-common.proto"; + +service InstanceDiscoveryService { + rpc registerInstance (ApplicationInstance) returns (ApplicationInstanceMapping) { + } + + rpc heartbeat (ApplicationInstanceHeartbeat) returns (Downstream) { + } + +} + +message ApplicationInstance { + int32 applicationId = 1; + string agentUUID = 2; + int64 registerTime = 3; + OSInfo osinfo = 4; +} + +message ApplicationInstanceMapping { + int32 applicationId = 1; + int32 applicationInstanceId = 2; +} + +message ApplicationInstanceRecover { + int32 applicationId = 1; + int32 applicationInstanceId = 2; + int64 registerTime = 3; + OSInfo osinfo = 4; +} + +message ApplicationInstanceHeartbeat { + int32 applicationInstanceId = 1; + int64 heartbeatTime = 2; +} + +message OSInfo { + string osName = 1; + string hostname = 2; + int32 processNo = 3; + repeated string ipv4s = 4; +} + +//discovery service for ServiceName by Network address or application code +service ServiceNameDiscoveryService { + rpc discovery (ServiceNameCollection) returns (ServiceNameMappingCollection) { + } +} + +message ServiceNameCollection { + repeated ServiceNameElement elements = 1; +} + +message ServiceNameMappingCollection { + repeated ServiceNameMappingElement elements = 1; +} + +message ServiceNameMappingElement { + int32 serviceId = 1; + ServiceNameElement element = 2; +} + +message ServiceNameElement { + string serviceName = 1; + int32 applicationId = 2; + SpanType srcSpanType = 3; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/Downstream.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/Downstream.proto new file mode 100644 index 000000000..e7bbb39a2 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/Downstream.proto @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +// nothing down stream from collector yet. +message Downstream { +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/JVMMetricsService.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/JVMMetricsService.proto new file mode 100644 index 000000000..229f41a96 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/JVMMetricsService.proto @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "language-agent/Downstream.proto"; +import "common/JVM.proto"; + +service JVMMetricsService { + rpc collect (JVMMetrics) returns (Downstream) { + } +} + +message JVMMetrics { + repeated JVMMetric metrics = 1; + int32 applicationInstanceId = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/KeyWithIntegerValue.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/KeyWithIntegerValue.proto new file mode 100644 index 000000000..ed48a5485 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/KeyWithIntegerValue.proto @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +message KeyWithIntegerValue { + string key = 1; + int32 value = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/KeyWithStringValue.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/KeyWithStringValue.proto new file mode 100644 index 000000000..111426775 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/KeyWithStringValue.proto @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +message KeyWithStringValue { + string key = 1; + string value = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/NetworkAddressRegisterService.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/NetworkAddressRegisterService.proto new file mode 100644 index 000000000..a299edcf6 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/NetworkAddressRegisterService.proto @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "language-agent/KeyWithIntegerValue.proto"; + +service NetworkAddressRegisterService { + rpc batchRegister (NetworkAddresses) returns (NetworkAddressMappings) { + } +} + +message NetworkAddresses { + repeated string addresses = 1; +} + +message NetworkAddressMappings { + repeated KeyWithIntegerValue addressIds = 1; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/TraceSegmentService.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/TraceSegmentService.proto new file mode 100644 index 000000000..f8566b2da --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/language-agent/TraceSegmentService.proto @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.language.agent"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "language-agent/Downstream.proto"; +import "language-agent/KeyWithStringValue.proto"; +import "common/trace-common.proto"; + +service TraceSegmentService { + rpc collect (stream UpstreamSegment) returns (Downstream) { + } +} + +message TraceSegmentObject { + UniqueId traceSegmentId = 1; + repeated SpanObject spans = 2; + int32 applicationId = 3; + int32 applicationInstanceId = 4; + bool isSizeLimited = 5; +} + +message TraceSegmentReference { + RefType refType = 1; + UniqueId parentTraceSegmentId = 2; + int32 parentSpanId = 3; + int32 parentApplicationInstanceId = 4; + string networkAddress = 5; + int32 networkAddressId = 6; + int32 entryApplicationInstanceId = 7; + string entryServiceName = 8; + int32 entryServiceId = 9; + string parentServiceName = 10; + int32 parentServiceId = 11; +} + +message SpanObject { + int32 spanId = 1; + int32 parentSpanId = 2; + int64 startTime = 3; + int64 endTime = 4; + repeated TraceSegmentReference refs = 5; + int32 operationNameId = 6; + string operationName = 7; + int32 peerId = 8; + string peer = 9; + SpanType spanType = 10; + SpanLayer spanLayer = 11; + int32 componentId = 12; + string component = 13; + bool isError = 14; + repeated KeyWithStringValue tags = 15; + repeated LogMessage logs = 16; +} + +message LogMessage { + int64 time = 1; + repeated KeyWithStringValue data = 2; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/register/InstancePing.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/register/InstancePing.proto new file mode 100644 index 000000000..3a8ffe16c --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/register/InstancePing.proto @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.register.v2"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; + +service ServiceInstancePing { + rpc doPing (ServiceInstancePingPkg) returns (Commands) { + } +} + +message ServiceInstancePingPkg { + int32 serviceInstanceId = 1; + int64 time = 2; + string serviceInstanceUUID = 3; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/register/Register.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/register/Register.proto new file mode 100644 index 000000000..aff9ea5be --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/register/Register.proto @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.register.v2"; +option csharp_namespace = "SkyWalking.NetworkProtocol"; + +import "common/common.proto"; + +//register service for ApplicationCode, this service is called when service starts. +service Register { + rpc doServiceRegister (Services) returns (ServiceRegisterMapping) { + } + + rpc doServiceInstanceRegister (ServiceInstances) returns (ServiceInstanceRegisterMapping) { + } + + rpc doEndpointRegister (Enpoints) returns (EndpointMapping) { + } + + rpc doNetworkAddressRegister (NetAddresses) returns (NetAddressMapping) { + } + + rpc doServiceAndNetworkAddressMappingRegister (ServiceAndNetworkAddressMappings) returns(Commands) { + } +} + +// Service register +message Services { + repeated Service services = 1; +} + +message Service { + string serviceName = 1; + repeated KeyStringValuePair tags = 3; + repeated KeyStringValuePair properties = 4; +} + +message ServiceRegisterMapping { + repeated KeyIntValuePair services = 1; +} + +// Service Instance register +message ServiceInstances { + repeated ServiceInstance instances = 1; +} + +message ServiceInstance { + int32 serviceId = 1; + string instanceUUID = 2; + int64 time = 3; + repeated KeyStringValuePair tags = 4; + repeated KeyStringValuePair properties = 5; +} + +message ServiceInstanceRegisterMapping { + repeated KeyIntValuePair serviceInstances = 1; +} + +// Network address register + +// Only known use case is the language agent. +// Network address represents the ip/hostname:port, which is usually used at client side of RPC. +message NetAddresses { + repeated string addresses = 1; +} + +message NetAddressMapping { + repeated KeyIntValuePair addressIds = 1; +} + +// Endpint register +message Enpoints { + repeated Endpoint endpoints = 1; +} + +message Endpoint { + int32 serviceId = 1; + string endpointName = 2; + repeated KeyStringValuePair tags = 3; + repeated KeyStringValuePair properties = 4; + // For endpoint + // from DetectPoint is either `client` or `server`. No chance to be `proxy`. + DetectPoint from = 5; +} + +message EndpointMapping { + repeated EndpointMappingElement elements = 1; +} + +message EndpointMappingElement { + int32 serviceId = 1; + string endpointName = 2; + int32 endpointId = 3; + DetectPoint from = 4; +} + +message ServiceAndNetworkAddressMappings { + repeated ServiceAndNetworkAddressMapping mappings = 1; +} + +message ServiceAndNetworkAddressMapping { + int32 serviceId = 1; + int32 serviceInstanceId = 2; + string networkAddress = 3; + int32 networkAddressId = 4; +} diff --git a/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/service-mesh-probe/service-mesh.proto b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/service-mesh-probe/service-mesh.proto new file mode 100644 index 000000000..87e0b70d4 --- /dev/null +++ b/src/Surging.Apm/SkyApm.Transport.Grpc.Protocol/protocol/service-mesh-probe/service-mesh.proto @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.skywalking.apm.network.servicemesh"; + +import "common/common.proto"; + +service ServiceMeshMetricService { + rpc collect(stream ServiceMeshMetric) returns (MeshProbeDownstream) { + } +} + +message ServiceMeshMetric { + int64 startTime = 1; + int64 endTime = 2; + string sourceServiceName = 3; + int32 sourceServiceId = 4; + string sourceServiceInstance = 5; + int32 sourceServiceInstanceId = 6; + string destServiceName = 7; + int32 destServiceId = 8; + string destServiceInstance = 9; + int32 destServiceInstanceId = 10; + string endpoint = 11; + int32 latency = 12; + int32 responseCode = 13; + bool status = 14; + Protocol protocol = 15; + DetectPoint detectPoint = 16; +} + +enum Protocol { + HTTP = 0; + gRPC = 1; +} + +message MeshProbeDownstream { +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Common/NullableValue.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Common/NullableValue.cs new file mode 100644 index 000000000..74dea8952 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Common/NullableValue.cs @@ -0,0 +1,36 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Common +{ + public struct NullableValue + { + public static readonly NullableValue Null = new NullableValue(0); + + private const int NULL_VALUE = 0; + + public int Value { get; } + + public NullableValue(int value) + { + Value = value; + } + + public bool HasValue => Value != NULL_VALUE; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/ConfigAttribute.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/ConfigAttribute.cs new file mode 100644 index 000000000..90f0dd8ad --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/ConfigAttribute.cs @@ -0,0 +1,32 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + +namespace Surging.Apm.Skywalking.Abstractions.Config +{ + public class ConfigAttribute : Attribute + { + public string[] Sections { get; } + + public ConfigAttribute(params string[] sections) + { + Sections = sections; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/IConfigAccessor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/IConfigAccessor.cs new file mode 100644 index 000000000..56823c954 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/IConfigAccessor.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Config +{ + public interface IConfigAccessor + { + T Get() where T : class, new(); + + T Value(string key, params string[] sections); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/InstrumentConfig.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/InstrumentConfig.cs new file mode 100644 index 000000000..4d0fec1a4 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/InstrumentConfig.cs @@ -0,0 +1,42 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + +namespace Surging.Apm.Skywalking.Abstractions.Config +{ + [Config("SkyWalking")] + public class InstrumentConfig + { + public string Namespace { get; set; } + + [Obsolete("Use ServiceName.")] + public string ApplicationCode { get; set; } + + public string ServiceName { get; set; } + + public string[] HeaderVersions { get; set; } + } + + public static class HeaderVersions + { + public static string SW3 { get; } = "sw3"; + + public static string SW6 { get; } = "sw6"; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/SamplingConfig.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/SamplingConfig.cs new file mode 100644 index 000000000..13a24dc3a --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/SamplingConfig.cs @@ -0,0 +1,28 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Config +{ + [Config("SkyWalking", "Sampling")] + public class SamplingConfig + { + public int SamplePer3Secs { get; set; } = -1; + + public double Percentage { get; set; } = -1d; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/TransportConfig.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/TransportConfig.cs new file mode 100644 index 000000000..9738509e2 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Config/TransportConfig.cs @@ -0,0 +1,45 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Config +{ + [Config("SkyWalking", "Transport")] + public class TransportConfig + { + public int QueueSize { get; set; } = 30000; + + /// + /// Flush Interval Millisecond + /// + public int Interval { get; set; } = 3000; + + /// + /// Data queued beyond this time will be discarded. + /// + public int BatchSize { get; set; } = 3000; + + public string ProtocolVersion { get; set; } = ProtocolVersions.V6; + } + + public static class ProtocolVersions + { + public static string V5 { get; } = "v5"; + + public static string V6 { get; } = "v6"; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/ExecutionService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/ExecutionService.cs new file mode 100644 index 000000000..f5742dab8 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/ExecutionService.cs @@ -0,0 +1,85 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Microsoft.Extensions.Logging; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions +{ + public abstract class ExecutionService : IExecutionService, IDisposable + { + private Timer _timer; + private CancellationTokenSource _cancellationTokenSource; + + protected readonly ILogger Logger; + protected readonly IRuntimeEnvironment RuntimeEnvironment; + + protected ExecutionService(IRuntimeEnvironment runtimeEnvironment, ILoggerFactory loggerFactory) + { + RuntimeEnvironment = runtimeEnvironment; + Logger = loggerFactory.CreateLogger(GetType()); + } + + public Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + _cancellationTokenSource = new CancellationTokenSource(); + var source = CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token, cancellationToken); + _timer = new Timer(Callback, source, DueTime, Period); + Logger.LogInformation($"Loaded instrument service [{GetType().FullName}]."); + return Task.CompletedTask; + } + + public async Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + _cancellationTokenSource?.Cancel(); + await Stopping(cancellationToken); + Logger.LogInformation($"Stopped instrument service {GetType().Name}."); + } + + public void Dispose() + { + _timer?.Dispose(); + } + + private async void Callback(object state) + { + if (!(state is CancellationTokenSource token) || token.IsCancellationRequested || !CanExecute()) return; + + try + { + await ExecuteAsync(token.Token); + } + catch (Exception ex) + { + Logger.LogError(GetType().FullName + ".ExecuteAsync(token.Token) fail", ex); + } + } + + protected virtual bool CanExecute() => RuntimeEnvironment.Initialized; + + protected virtual Task Stopping(CancellationToken cancellationToke) => Task.CompletedTask; + + protected abstract TimeSpan DueTime { get; } + + protected abstract TimeSpan Period { get; } + + protected abstract Task ExecuteAsync(CancellationToken cancellationToken); + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IBase64Formatter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IBase64Formatter.cs new file mode 100644 index 000000000..2336b2b26 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IBase64Formatter.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions +{ + public interface IBase64Formatter + { + string Decode(string value); + + string Encode(string value); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IEnvironmentProvider.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IEnvironmentProvider.cs new file mode 100644 index 000000000..2f1607fe3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IEnvironmentProvider.cs @@ -0,0 +1,25 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions +{ + public interface IEnvironmentProvider + { + string EnvironmentName { get; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IExecutionService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IExecutionService.cs new file mode 100644 index 000000000..70ae5a9e0 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IExecutionService.cs @@ -0,0 +1,30 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions +{ + public interface IExecutionService + { + Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)); + + Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IInstrumentStartup.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IInstrumentStartup.cs new file mode 100644 index 000000000..4dcfbf7a3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IInstrumentStartup.cs @@ -0,0 +1,30 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions +{ + public interface IInstrumentStartup + { + Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)); + + Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IRuntimeEnvironment.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IRuntimeEnvironment.cs new file mode 100644 index 000000000..e68e603bb --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/IRuntimeEnvironment.cs @@ -0,0 +1,36 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using Surging.Apm.Skywalking.Abstractions.Common; + +namespace Surging.Apm.Skywalking.Abstractions +{ + public interface IRuntimeEnvironment + { + NullableValue ServiceId { get; } + + NullableValue ServiceInstanceId { get; } + + bool Initialized { get; } + + Guid InstanceId { get; } + + IEnvironmentProvider Environment { get; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Logging/ILogger.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Logging/ILogger.cs new file mode 100644 index 000000000..493c38528 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Logging/ILogger.cs @@ -0,0 +1,35 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + +namespace Surging.Apm.Skywalking.Abstractions.Logging +{ + public interface ILogger + { + void Debug(string message); + + void Information(string message); + + void Warning(string message); + + void Error(string message, Exception exception); + + void Trace(string message); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Logging/ILoggerFactory.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Logging/ILoggerFactory.cs new file mode 100644 index 000000000..987411f14 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Logging/ILoggerFactory.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + +namespace Surging.Apm.Skywalking.Abstractions.Logging +{ + public interface ILoggerFactory + { + ILogger CreateLogger(Type type); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrier.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrier.cs new file mode 100644 index 000000000..40ac77e59 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrier.cs @@ -0,0 +1,46 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface ICarrier + { + bool HasValue { get; } + + bool? Sampled { get; } + + UniqueId TraceId { get; } + + UniqueId ParentSegmentId { get; } + + int ParentSpanId { get; } + + int ParentServiceInstanceId { get; } + + int EntryServiceInstanceId { get; } + + StringOrIntValue NetworkAddress { get; } + + StringOrIntValue EntryEndpoint { get; } + + StringOrIntValue ParentEndpoint { get; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrierFormatter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrierFormatter.cs new file mode 100644 index 000000000..2f2978035 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrierFormatter.cs @@ -0,0 +1,32 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface ICarrierFormatter + { + string Key { get; } + + bool Enable { get; } + + ICarrier Decode(string content); + + string Encode(ICarrier carrier); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrierPropagator.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrierPropagator.cs new file mode 100644 index 000000000..7156f4027 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ICarrierPropagator.cs @@ -0,0 +1,28 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface ICarrierPropagator + { + void Inject(SegmentContext segmentContext, ICarrierHeaderCollection carrier); + + ICarrier Extract(ICarrierHeaderCollection carrier); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISamplerChainBuilder.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISamplerChainBuilder.cs new file mode 100644 index 000000000..951b7064f --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISamplerChainBuilder.cs @@ -0,0 +1,25 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface ISamplerChainBuilder + { + Sampler Build(); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISamplingInterceptor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISamplingInterceptor.cs new file mode 100644 index 000000000..39f62b1f5 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISamplingInterceptor.cs @@ -0,0 +1,28 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface ISamplingInterceptor + { + int Priority { get; } + + bool Invoke(SamplingContext samplingContext, Sampler next); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISegmentContextFactory.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISegmentContextFactory.cs new file mode 100644 index 000000000..6792f72f6 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/ISegmentContextFactory.cs @@ -0,0 +1,32 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface ISegmentContextFactory + { + SegmentContext CreateEntrySegment(string operationName, ICarrier carrier); + + SegmentContext CreateLocalSegment(string operationName); + + SegmentContext CreateExitSegment(string operationName, StringOrIntValue networkAddress); + + void Release(SegmentContext segmentContext); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/IUniqueIdGenerator.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/IUniqueIdGenerator.cs new file mode 100644 index 000000000..257965474 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/IUniqueIdGenerator.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface IUniqueIdGenerator + { + UniqueId Generate(); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/IUniqueIdParser.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/IUniqueIdParser.cs new file mode 100644 index 000000000..e0b2b6796 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/IUniqueIdParser.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public interface IUniqueIdParser + { + bool TryParse(string text, out UniqueId uniqueId); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/Sampler.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/Sampler.cs new file mode 100644 index 000000000..a78402846 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Tracing/Sampler.cs @@ -0,0 +1,45 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Tracing +{ + public delegate bool Sampler(SamplingContext samplingContext); + + public class SamplingContext + { + public string OperationName { get; } + + public StringOrIntValue Peer { get; } + + public StringOrIntValue EntryEndpoint { get; } + + public StringOrIntValue ParentEndpoint { get; } + + public SamplingContext(string operationName, StringOrIntValue peer, StringOrIntValue entryEndpoint, + StringOrIntValue parentEndpoint) + { + OperationName = operationName; + Peer = peer; + EntryEndpoint = entryEndpoint; + ParentEndpoint = parentEndpoint; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/AgentOsInfoRequest.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/AgentOsInfoRequest.cs new file mode 100644 index 000000000..e0e59766d --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/AgentOsInfoRequest.cs @@ -0,0 +1,35 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public class AgentOsInfoRequest + { + public string OsName { get; set; } + + public string HostName { get; set; } + + public int ProcessNo { get; set; } + + public string[] IpAddress { get; set; } + + public string Language { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/CLRStatsRequest.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/CLRStatsRequest.cs new file mode 100644 index 000000000..75454813a --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/CLRStatsRequest.cs @@ -0,0 +1,56 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public class CLRStatsRequest + { + public CPUStatsRequest CPU { get; set; } + + public GCStatsRequest GC { get; set; } + + public ThreadStatsRequest Thread { get; set; } + } + + public class CPUStatsRequest + { + public double UsagePercent { get; set; } + } + + public class GCStatsRequest + { + public long Gen0CollectCount { get; set; } + + public long Gen1CollectCount { get; set; } + + public long Gen2CollectCount { get; set; } + + public long HeapMemory { get; set; } + } + + public class ThreadStatsRequest + { + public int AvailableCompletionPortThreads { get; set; } + + public int AvailableWorkerThreads { get; set; } + + public int MaxCompletionPortThreads { get; set; } + + public int MaxWorkerThreads { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ICLRStatsReporter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ICLRStatsReporter.cs new file mode 100644 index 000000000..85f31a912 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ICLRStatsReporter.cs @@ -0,0 +1,29 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface ICLRStatsReporter + { + Task ReportAsync(CLRStatsRequest statsRequest, + CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/IPingCaller.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/IPingCaller.cs new file mode 100644 index 000000000..7f8d816e0 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/IPingCaller.cs @@ -0,0 +1,29 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Threading; +using System.Threading.Tasks; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface IPingCaller + { + Task PingAsync(PingRequest request, CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentContextMapper.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentContextMapper.cs new file mode 100644 index 000000000..92d919b20 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentContextMapper.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface ISegmentContextMapper + { + SegmentRequest Map(SegmentContext segmentContext); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentDispatcher.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentDispatcher.cs new file mode 100644 index 000000000..96e7caa89 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentDispatcher.cs @@ -0,0 +1,33 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface ISegmentDispatcher + { + bool Dispatch(SegmentContext segmentContext); + + Task Flush(CancellationToken token = default(CancellationToken)); + + void Close(); + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentReporter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentReporter.cs new file mode 100644 index 000000000..41704ca32 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ISegmentReporter.cs @@ -0,0 +1,30 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface ISegmentReporter + { + Task ReportAsync(IReadOnlyCollection segmentRequests, + CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/IServiceRegister.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/IServiceRegister.cs new file mode 100644 index 000000000..298dd117c --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/IServiceRegister.cs @@ -0,0 +1,35 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface IServiceRegister + { + Task RegisterServiceAsync(ServiceRequest serviceRequest, + CancellationToken cancellationToken = default(CancellationToken)); + + Task RegisterServiceInstanceAsync(ServiceInstanceRequest serviceInstanceRequest, + CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/PingRequest.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/PingRequest.cs new file mode 100644 index 000000000..84ab006db --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/PingRequest.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public class PingRequest + { + public int ServiceInstanceId { get; set; } + + public string InstanceId { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/SegmentRequest.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/SegmentRequest.cs new file mode 100644 index 000000000..c261698b9 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/SegmentRequest.cs @@ -0,0 +1,111 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public class SegmentRequest + { + public IEnumerable UniqueIds { get; set; } + + public SegmentObjectRequest Segment { get; set; } + } + + public class UniqueIdRequest + { + public long Part1 { get; set; } + + public long Part2 { get; set; } + + public long Part3 { get; set; } + + public override string ToString() + { + return $"{Part1}.{Part2}.{Part3}"; + } + } + + public class SegmentObjectRequest + { + public UniqueIdRequest SegmentId { get; set; } + + public int ServiceId { get; set; } + + public int ServiceInstanceId { get; set; } + + public IList Spans { get; set; } = new List(); + } + + public class SpanRequest + { + public int SpanId { get; set; } + + public int SpanType { get; set; } + + public int SpanLayer { get; set; } + + public int ParentSpanId { get; set; } + + public long StartTime { get; set; } + + public long EndTime { get; set; } + + public StringOrIntValue Component { get; set; } + + public StringOrIntValue OperationName { get; set; } + + public StringOrIntValue Peer { get; set; } + + public bool IsError { get; set; } + + public IList References { get; } = new List(); + + public IList> Tags { get; } = new List>(); + + public IList Logs { get; } = new List(); + } + + public class SegmentReferenceRequest + { + public UniqueIdRequest ParentSegmentId { get; set; } + + public int ParentServiceInstanceId { get; set; } + + public int ParentSpanId { get; set; } + + public int EntryServiceInstanceId { get; set; } + + public int RefType { get; set; } + + public StringOrIntValue ParentEndpointName { get; set; } + + public StringOrIntValue EntryEndpointName { get; set; } + + public StringOrIntValue NetworkAddress { get; set; } + } + + public class LogDataRequest + { + public long Timestamp { get; set; } + + public IList> Data { get; } = new List>(); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ServiceInstanceRequest.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ServiceInstanceRequest.cs new file mode 100644 index 000000000..6cf086b4d --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ServiceInstanceRequest.cs @@ -0,0 +1,29 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public class ServiceInstanceRequest + { + public int ServiceId { get; set; } + + public string InstanceUUID { get; set; } + + public AgentOsInfoRequest Properties { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ServiceRequest.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ServiceRequest.cs new file mode 100644 index 000000000..cb5b06c96 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/ServiceRequest.cs @@ -0,0 +1,31 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public class ServiceRequest + { + public string ServiceName { get; set; } + + public Dictionary Tags { get; set; } + + public Dictionary Properties { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/V5/ISkyApmClientV5.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/V5/ISkyApmClientV5.cs new file mode 100644 index 000000000..6a7442c9d --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Abstractions/Transport/V5/ISkyApmClientV5.cs @@ -0,0 +1,35 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Surging.Apm.Skywalking.Abstractions.Common; + +namespace Surging.Apm.Skywalking.Abstractions.Transport +{ + public interface ISkyApmClientV5 + { + Task RegisterApplicationAsync(string applicationCode, CancellationToken cancellationToken = default(CancellationToken)); + + Task RegisterApplicationInstanceAsync(int applicationId, Guid agentUUID, long registerTime, AgentOsInfoRequest osInfoRequest, + CancellationToken cancellationToken = default(CancellationToken)); + + Task HeartbeatAsync(int applicationInstance, long heartbeatTime, CancellationToken cancellationToken = default(CancellationToken)); + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigAccessor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigAccessor.cs new file mode 100644 index 000000000..42afad5d9 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigAccessor.cs @@ -0,0 +1,61 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Linq.Expressions; +using System.Reflection; +using Microsoft.Extensions.Configuration; +using Surging.Apm.Skywalking.Abstractions.Config; + +namespace Surging.Apm.Skywalking.Configuration +{ + public class ConfigAccessor : IConfigAccessor + { + private readonly IConfiguration _configuration; + + public ConfigAccessor(IConfigurationFactory factory) + { + _configuration = factory.Create(); + } + + public T Get() where T : class, new() + { + var config = typeof(T).GetCustomAttribute(); + var instance = New.Instance(); + _configuration.GetSection(config.GetSections()).Bind(instance); + return instance; + } + + public T Value(string key, params string[] sections) + { + var config = new ConfigAttribute(sections); + return _configuration.GetSection(config.GetSections()).GetValue(key); + } + + /// + /// high performance + /// + private static class New where T : new() + { + public static readonly Func Instance = Expression.Lambda> + ( + Expression.New(typeof(T)) + ).Compile(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigSectionExtensions.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigSectionExtensions.cs new file mode 100644 index 000000000..8c7a146d3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigSectionExtensions.cs @@ -0,0 +1,36 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Config; +using System.Linq; + +namespace Surging.Apm.Skywalking.Configuration +{ + public static class ConfigSectionExtensions + { + public static string GetSections(this ConfigAttribute config) + { + if (config.Sections == null || config.Sections.Length == 0) + { + return null; + } + + return config.Sections.Length == 1 ? config.Sections[0] : config.Sections.Aggregate((x, y) => x + ":" + y); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigurationBuilderExtensions.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigurationBuilderExtensions.cs new file mode 100644 index 000000000..cd47d323c --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigurationBuilderExtensions.cs @@ -0,0 +1,52 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.Configuration; +using Surging.Apm.Skywalking.Abstractions.Config; + +namespace Surging.Apm.Skywalking.Configuration +{ + internal static class ConfigurationBuilderExtensions + { + public static IConfigurationBuilder AddSkyWalkingDefaultConfig(this IConfigurationBuilder builder) + { + var defaultLogFile = Path.Combine("logs", "skyapm-{Date}.log"); + var defaultConfig = new Dictionary + { + {"SkyWalking:Namespace", string.Empty}, + {"SkyWalking:ServiceName", "My_Service"}, + {"SkyWalking:HeaderVersions:0", HeaderVersions.SW6}, + {"SkyWalking:Sampling:SamplePer3Secs", "-1"}, + {"SkyWalking:Sampling:Percentage", "-1"}, + {"SkyWalking:Logging:Level", "Information"}, + {"SkyWalking:Logging:FilePath", defaultLogFile}, + {"SkyWalking:Transport:Interval", "3000"}, + {"SkyWalking:Transport:ProtocolVersion", ProtocolVersions.V6}, + {"SkyWalking:Transport:QueueSize", "30000"}, + {"SkyWalking:Transport:BatchSize", "3000"}, + {"SkyWalking:Transport:gRPC:Servers", "localhost:11800"}, + {"SkyWalking:Transport:gRPC:Timeout", "10000"}, + {"SkyWalking:Transport:gRPC:ReportTimeout", "600000"}, + {"SkyWalking:Transport:gRPC:ConnectTimeout", "10000"} + }; + return builder.AddInMemoryCollection(defaultConfig); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigurationFactory.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigurationFactory.cs new file mode 100644 index 000000000..ac51c0406 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/ConfigurationFactory.cs @@ -0,0 +1,83 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.Configuration; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Core.CPlatform; + +// ReSharper disable StringLiteralTypo +namespace Surging.Apm.Skywalking.Configuration +{ + public class ConfigurationFactory : IConfigurationFactory + { + private const string CONFIG_FILE_PATH_COMPATIBLE = "SKYWALKING__CONFIG__PATH"; + private const string CONFIG_FILE_PATH = "SKYAPM__CONFIG__PATH"; + private readonly IEnvironmentProvider _environmentProvider; + private readonly IEnumerable _additionalConfigurations; + + public ConfigurationFactory(IEnvironmentProvider environmentProvider, + IEnumerable additionalConfigurations) + { + _environmentProvider = environmentProvider; + _additionalConfigurations = additionalConfigurations; + } + + public IConfiguration Create() + { + var builder = new ConfigurationBuilder(); + + builder.AddSkyWalkingDefaultConfig(); + + builder.AddJsonFile("appsettings.json", true) + .AddJsonFile($"appsettings.{_environmentProvider.EnvironmentName}.json", true); + + builder.AddJsonFile("skywalking.json", true) + .AddJsonFile($"skywalking.{_environmentProvider.EnvironmentName}.json", true); + + builder.AddJsonFile("skyapm.json", true) + .AddJsonFile($"skyapm.{_environmentProvider.EnvironmentName}.json", true); + + if (!string.IsNullOrEmpty(AppConfig.ServerOptions.RootPath)) + { + var skyapmPath = Path.Combine(AppConfig.ServerOptions.RootPath, "skyapm.json"); + builder.AddJsonFile(skyapmPath, true); + } + if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(CONFIG_FILE_PATH_COMPATIBLE))) + { + builder.AddJsonFile(Environment.GetEnvironmentVariable(CONFIG_FILE_PATH_COMPATIBLE), false); + } + + if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(CONFIG_FILE_PATH))) + { + builder.AddJsonFile(Environment.GetEnvironmentVariable(CONFIG_FILE_PATH), false); + } + + builder.AddEnvironmentVariables(); + + foreach (var additionalConfiguration in _additionalConfigurations) + { + additionalConfiguration.Load(builder); + } + + return builder.Build(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/IAdditionalConfigurationSource.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/IAdditionalConfigurationSource.cs new file mode 100644 index 000000000..5ee888e78 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/IAdditionalConfigurationSource.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Microsoft.Extensions.Configuration; + +namespace Surging.Apm.Skywalking.Configuration +{ + public interface IAdditionalConfigurationSource + { + void Load(ConfigurationBuilder builder); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/IConfigurationFactory.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/IConfigurationFactory.cs new file mode 100644 index 000000000..b7651ec9f --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Configuration/IConfigurationFactory.cs @@ -0,0 +1,27 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Microsoft.Extensions.Configuration; + +namespace Surging.Apm.Skywalking.Configuration +{ + public interface IConfigurationFactory + { + IConfiguration Create(); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/ContainerBuilderExtensions.cs b/src/Surging.Apm/Surging.Apm.Skywalking/ContainerBuilderExtensions.cs new file mode 100644 index 000000000..c18cc9308 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/ContainerBuilderExtensions.cs @@ -0,0 +1,86 @@ +using Autofac; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Common.Tracing; +using Surging.Apm.Skywalking.Abstractions.Common.Transport; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Configuration; +using Surging.Apm.Skywalking.Core; +using Surging.Apm.Skywalking.Core.Common; +using Surging.Apm.Skywalking.Core.Diagnostics; +using Surging.Apm.Skywalking.Core.Sampling; +using Surging.Apm.Skywalking.Core.Service; +using Surging.Apm.Skywalking.Core.Tracing; +using Surging.Apm.Skywalking.Transport.Grpc; +using Surging.Apm.Skywalking.Transport.Grpc.V5; +using Surging.Apm.Skywalking.Transport.Grpc.V6; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Diagnostics; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Apm.Skywalking +{ + public static class ContainerBuilderExtensions + { + public static IServiceBuilder UseSkywalking(this IServiceBuilder builder) + { + var services = builder.Services; + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.Register(p => RuntimeEnvironment.Instance).SingleInstance(); + services.RegisterType().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + return AddTracing(builder).AddSampling().AddGrpcTransport(); + } + + private static IServiceBuilder AddTracing(this IServiceBuilder builder) + { + var services = builder.Services; + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + return builder; + } + + private static IServiceBuilder AddSampling(this IServiceBuilder builder) + { + var services = builder.Services; + services.RegisterType().SingleInstance(); + services.Register(p => p.Resolve()).SingleInstance(); + services.Register(p => p.Resolve()).SingleInstance(); + services.RegisterType().As().SingleInstance(); + return builder; + } + + private static IServiceBuilder AddGrpcTransport(this IServiceBuilder builder) + { + var services = builder.Services; + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); + return builder; + } + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Base64Formatter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Base64Formatter.cs new file mode 100644 index 000000000..31b7a1f2a --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Base64Formatter.cs @@ -0,0 +1,37 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions; +using System; +using System.Text; + +namespace Surging.Apm.Skywalking.Core +{ + public class Base64Formatter : IBase64Formatter + { + public string Decode(string value) + { + return value == null ? value : Encoding.UTF8.GetString(Convert.FromBase64String(value)); + } + + public string Encode(string value) + { + return value == null ? value : Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/AtomicInteger.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/AtomicInteger.cs new file mode 100644 index 000000000..6d1787ec9 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/AtomicInteger.cs @@ -0,0 +1,138 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Threading; + +namespace Surging.Apm.Skywalking.Core.Common +{ + public class AtomicInteger + { + private int _value; + + public int Value + { + get => _value; + set => Interlocked.Exchange(ref _value, value); + } + + public AtomicInteger() + : this(0) + { + } + + public AtomicInteger(int defaultValue) + { + _value = defaultValue; + } + + public int Increment() + { + Interlocked.Increment(ref _value); + return _value; + } + + public int Decrement() + { + Interlocked.Decrement(ref _value); + return _value; + } + + public int Add(int value) + { + AddInternal(value); + return _value; + } + + private void AddInternal(int value) + { + Interlocked.Add(ref _value, value); + } + + public override bool Equals(object obj) + { + switch (obj) + { + case AtomicInteger atomicInteger: + return atomicInteger._value == _value; + case int value: + return value == _value; + default: + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public static AtomicInteger operator +(AtomicInteger atomicInteger, int value) + { + atomicInteger.AddInternal(value); + return atomicInteger; + } + + public static AtomicInteger operator +(int value, AtomicInteger atomicInteger) + { + atomicInteger.AddInternal(value); + return atomicInteger; + } + + public static AtomicInteger operator -(AtomicInteger atomicInteger, int value) + { + atomicInteger.AddInternal(-value); + return atomicInteger; + } + + public static AtomicInteger operator -(int value, AtomicInteger atomicInteger) + { + atomicInteger.AddInternal(-value); + return atomicInteger; + } + + public static implicit operator AtomicInteger(int value) + { + return new AtomicInteger(value); + } + + public static implicit operator int(AtomicInteger atomicInteger) + { + return atomicInteger._value; + } + + public static bool operator ==(AtomicInteger atomicInteger, int value) + { + return atomicInteger._value == value; + } + + public static bool operator !=(AtomicInteger atomicInteger, int value) + { + return !(atomicInteger == value); + } + + public static bool operator ==(int value, AtomicInteger atomicInteger) + { + return atomicInteger._value == value; + } + + public static bool operator !=(int value, AtomicInteger atomicInteger) + { + return !(value == atomicInteger); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/CpuHelpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/CpuHelpers.cs new file mode 100644 index 000000000..fb0f223dc --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/CpuHelpers.cs @@ -0,0 +1,52 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Core.Common +{ + internal static class CpuHelpers + { + private const int interval = 1000; + private static double _usagePercent; + private static readonly Task _task; + + public static double UsagePercent => _usagePercent; + + static CpuHelpers() + { + var process = Process.GetCurrentProcess(); + _task = Task.Factory.StartNew(async () => + { + var _prevCpuTime = process.TotalProcessorTime.TotalMilliseconds; + while (true) + { + var prevCpuTime = _prevCpuTime; + var currentCpuTime = process.TotalProcessorTime; + var usagePercent = (currentCpuTime.TotalMilliseconds - prevCpuTime) / interval; + Interlocked.Exchange(ref _prevCpuTime, currentCpuTime.TotalMilliseconds); + Interlocked.Exchange(ref _usagePercent, usagePercent); + await Task.Delay(1000); + } + }); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/DnsHelpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/DnsHelpers.cs new file mode 100644 index 000000000..674704d9d --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/DnsHelpers.cs @@ -0,0 +1,45 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Linq; +using System.Net; +using System.Net.Sockets; + +namespace Surging.Apm.Skywalking.Core.Common +{ + public static class DnsHelpers + { + public static string GetHostName() + { + return Dns.GetHostName(); + } + + public static string[] GetIpV4s() + { + try + { + var ipAddresses = Dns.GetHostAddresses(Dns.GetHostName()); + return ipAddresses.Where(x => x.AddressFamily == AddressFamily.InterNetwork).Select(ipAddress => ipAddress.ToString()).ToArray(); + } + catch + { + return new string[0]; + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/EnumerableExtensions.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/EnumerableExtensions.cs new file mode 100644 index 000000000..0de2f0932 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/EnumerableExtensions.cs @@ -0,0 +1,38 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; + +namespace Surging.Apm.Skywalking.Core.Common +{ + internal static class EnumerableExtensions + { + public static IEnumerable Distinct(this IEnumerable source, Func predicate) + { + HashSet sets = new HashSet(); + foreach (var item in source) + { + if (sets.Add(predicate(item))) + { + yield return item; + } + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/GCHelpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/GCHelpers.cs new file mode 100644 index 000000000..cc7cc08f2 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/GCHelpers.cs @@ -0,0 +1,79 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; + +namespace Surging.Apm.Skywalking.Core.Common +{ + internal static class GCHelpers + { + private static long _prevGen0CollectCount; + + private static long _prevGen1CollectCount; + + private static long _prevGen2CollectCount; + + private static readonly int _maxGen = GC.MaxGeneration; + + public static long Gen0CollectCount + { + get + { + var count = GC.CollectionCount(0); + var prevCount = _prevGen0CollectCount; + Interlocked.Exchange(ref _prevGen0CollectCount, count); + return count - prevCount; + } + } + + public static long Gen1CollectCount + { + get + { + if (_maxGen < 1) + { + return 0; + } + + var count = GC.CollectionCount(1); + var prevCount = _prevGen1CollectCount; + Interlocked.Exchange(ref _prevGen1CollectCount, count); + return count - prevCount; + } + } + + public static long Gen2CollectCount + { + get + { + if (_maxGen < 2) + { + return 0; + } + + var count = GC.CollectionCount(2); + var prevCount = _prevGen2CollectCount; + Interlocked.Exchange(ref _prevGen2CollectCount, count); + return count - prevCount; + } + } + + public static long TotalMemory => GC.GetTotalMemory(false); + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/HostingEnvironmentProvider.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/HostingEnvironmentProvider.cs new file mode 100644 index 000000000..38e2975e8 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/HostingEnvironmentProvider.cs @@ -0,0 +1,15 @@ +using Surging.Apm.Skywalking.Abstractions; +using Surging.Core.CPlatform.Utilities; + +namespace Surging.Apm.Skywalking.Core.Common +{ + internal class HostingEnvironmentProvider : IEnvironmentProvider + { + public string EnvironmentName { get; } + + public HostingEnvironmentProvider() + { + EnvironmentName =""; + } + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/PlatformInformation.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/PlatformInformation.cs new file mode 100644 index 000000000..0a64dcec2 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/PlatformInformation.cs @@ -0,0 +1,47 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Runtime.InteropServices; + +namespace Surging.Apm.Skywalking.Core.Common +{ + internal static class PlatformInformation + { + private const string OSX = "Mac OS X"; + private const string LINUX = "Linux"; + private const string WINDOWS = "Windows"; + + public static string GetOSName() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return WINDOWS; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return LINUX; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return OSX; + } + + return "Unknown"; + } + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/StackExtensions.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/StackExtensions.cs new file mode 100644 index 000000000..b8a8aa930 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/StackExtensions.cs @@ -0,0 +1,49 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; + +namespace Surging.Apm.Skywalking.Core.Common +{ + public static class StackExtensions + { + public static bool TryPeek(this Stack stack, out T value) + { + if (stack == null || stack.Count == 0) + { + value = default(T); + return false; + } + + value = stack.Peek(); + return true; + } + + public static bool TryPop(this Stack stack, out T value) + { + if (stack == null || stack.Count == 0) + { + value = default(T); + return false; + } + + value = stack.Pop(); + return true; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/StringOrIntValueHelpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/StringOrIntValueHelpers.cs new file mode 100644 index 000000000..e3d5ff5e3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Common/StringOrIntValueHelpers.cs @@ -0,0 +1,32 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Core.CPlatform.Diagnostics; +using System; + +namespace Surging.Apm.Skywalking.Core.Common +{ + public static class StringOrIntValueHelpers + { + public static StringOrIntValue ParseStringOrIntValue(string value) + { + return value.StartsWith("#") ? new StringOrIntValue(new string(value.AsSpan().Slice(1, value.Length - 1).ToArray())) : new StringOrIntValue(int.Parse(value)); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/AnonymousObject.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/AnonymousObject.cs new file mode 100644 index 000000000..a98680906 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/AnonymousObject.cs @@ -0,0 +1,30 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + public class AnonymousObject : ParameterBinder + { + public override object Resolve(object value) + { + return value; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/NullParameterResolver.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/NullParameterResolver.cs new file mode 100644 index 000000000..2b5f24695 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/NullParameterResolver.cs @@ -0,0 +1,30 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + public class NullParameterResolver : IParameterResolver + { + public object Resolve(object value) + { + return null; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/PropertyAttribute.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/PropertyAttribute.cs new file mode 100644 index 000000000..f98ebee5a --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/PropertyAttribute.cs @@ -0,0 +1,40 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using AspectCore.Extensions.Reflection; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + public class PropertyAttribute : ParameterBinder + { + public string Name { get; set; } + + public override object Resolve(object value) + { + if (value == null || Name == null) + { + return null; + } + + var property = value.GetType().GetProperty(Name); + + return property?.GetReflector()?.GetValue(value); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticMethod.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticMethod.cs new file mode 100644 index 000000000..d0e121609 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticMethod.cs @@ -0,0 +1,91 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using AspectCore.Extensions.Reflection; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Core.Diagnostics; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + internal class TracingDiagnosticMethod + { + private readonly ITracingDiagnosticProcessor _tracingDiagnosticProcessor; + private readonly string _diagnosticName; + private readonly IParameterResolver[] _parameterResolvers; + private readonly MethodReflector _reflector; + + public TracingDiagnosticMethod(ITracingDiagnosticProcessor tracingDiagnosticProcessor, MethodInfo method, + string diagnosticName) + { + _tracingDiagnosticProcessor = tracingDiagnosticProcessor; + _reflector = method.GetReflector(); + _diagnosticName = diagnosticName; + _parameterResolvers = GetParameterResolvers(method).ToArray(); + } + + public void Invoke(string diagnosticName, object value) + { + if (_diagnosticName != diagnosticName) + { + return; + } + + var args = new object[_parameterResolvers.Length]; + for (var i = 0; i < _parameterResolvers.Length; i++) + { + args[i] = _parameterResolvers[i].Resolve(value); + } + + _reflector.Invoke(_tracingDiagnosticProcessor, args); + } + + private static IEnumerable GetParameterResolvers(MethodInfo methodInfo) + { + foreach (var parameter in methodInfo.GetParameters()) + { + var binder = parameter.GetCustomAttribute(); + if (binder != null) + { + if(binder is ObjectAttribute objectBinder) + { + if (objectBinder.TargetType == null) + { + objectBinder.TargetType = parameter.ParameterType; + } + } + if(binder is PropertyAttribute propertyBinder) + { + if (propertyBinder.Name == null) + { + propertyBinder.Name = parameter.Name; + } + } + yield return binder; + } + else + { + yield return new NullParameterResolver(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticMethodCollection.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticMethodCollection.cs new file mode 100644 index 000000000..632c7b2a2 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticMethodCollection.cs @@ -0,0 +1,54 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Core.Diagnostics; +using Surging.Core.CPlatform.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + internal class TracingDiagnosticMethodCollection : IEnumerable + { + private readonly List _methods; + + public TracingDiagnosticMethodCollection(ITracingDiagnosticProcessor tracingDiagnosticProcessor) + { + _methods = new List(); + foreach (var method in tracingDiagnosticProcessor.GetType().GetMethods()) + { + var diagnosticName = method.GetCustomAttribute(); + if(diagnosticName==null) + continue; + _methods.Add(new TracingDiagnosticMethod(tracingDiagnosticProcessor, method, diagnosticName.Name)); + } + } + + public IEnumerator GetEnumerator() + { + return _methods.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _methods.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticObserver.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticObserver.cs new file mode 100644 index 000000000..9ca2a3132 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticObserver.cs @@ -0,0 +1,62 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + internal class TracingDiagnosticObserver : IObserver> + { + private readonly TracingDiagnosticMethodCollection _methodCollection; + private readonly ILogger _logger; + + public TracingDiagnosticObserver(ITracingDiagnosticProcessor tracingDiagnosticProcessor, + ILoggerFactory loggerFactory) + { + _methodCollection = new TracingDiagnosticMethodCollection(tracingDiagnosticProcessor); + _logger = loggerFactory.CreateLogger(typeof(TracingDiagnosticObserver)); + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(KeyValuePair value) + { + foreach (var method in _methodCollection) + { + try + { + method.Invoke(value.Key, value.Value); + } + catch (Exception exception) + { + _logger.LogError("Invoke diagnostic method exception.", exception); + } + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticProcessorObserver.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticProcessorObserver.cs new file mode 100644 index 000000000..249f1a671 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Diagnostics/TracingDiagnosticProcessorObserver.cs @@ -0,0 +1,71 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Core.Common; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Diagnostics +{ + public class TracingDiagnosticProcessorObserver : IObserver + { + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; + private readonly IEnumerable _tracingDiagnosticProcessors; + + public TracingDiagnosticProcessorObserver(IEnumerable tracingDiagnosticProcessors, + ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(typeof(TracingDiagnosticProcessorObserver)); + _loggerFactory = loggerFactory; + _tracingDiagnosticProcessors = tracingDiagnosticProcessors ?? + throw new ArgumentNullException(nameof(tracingDiagnosticProcessors)); + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(DiagnosticListener listener) + { + foreach (var diagnosticProcessor in _tracingDiagnosticProcessors) + { + if (listener.Name == diagnosticProcessor.ListenerName) + { + Subscribe(listener, diagnosticProcessor); + _logger.LogInformation( + $"Loaded diagnostic listener [{diagnosticProcessor.ListenerName}]."); + } + } + } + + protected virtual void Subscribe(DiagnosticListener listener, + ITracingDiagnosticProcessor tracingDiagnosticProcessor) + { + listener.Subscribe(new TracingDiagnosticObserver(tracingDiagnosticProcessor, _loggerFactory)); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/InstrumentStartup.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/InstrumentStartup.cs new file mode 100644 index 000000000..28fc14e08 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/InstrumentStartup.cs @@ -0,0 +1,62 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Core.Diagnostics; + +namespace Surging.Apm.Skywalking.Core +{ + public class InstrumentStartup : IInstrumentStartup + { + private readonly TracingDiagnosticProcessorObserver _observer; + private readonly IEnumerable _services; + private readonly ILogger _logger; + + public InstrumentStartup(TracingDiagnosticProcessorObserver observer, IEnumerable services, ILoggerFactory loggerFactory) + { + _observer = observer; + _services = services; + _logger = loggerFactory.CreateLogger(typeof(InstrumentStartup)); + } + + public async Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + _logger.LogInformation("Initializing ..."); + foreach (var service in _services) + await service.StartAsync(cancellationToken); + DiagnosticListener.AllListeners.Subscribe(_observer); + _logger.LogInformation("Started SkyAPM .NET Core Agent."); + } + + public async Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + foreach (var service in _services) + await service.StopAsync(cancellationToken); + _logger.LogInformation("Stopped SkyAPM .NET Core Agent."); + // ReSharper disable once MethodSupportsCancellation + await Task.Delay(TimeSpan.FromSeconds(2)); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Logging/NullLogger.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Logging/NullLogger.cs new file mode 100644 index 000000000..03d689c90 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Logging/NullLogger.cs @@ -0,0 +1,46 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Logging; +using System; + +namespace Surging.Apm.Skywalking.Core.Logging +{ + internal class NullLogger : ILogger + { + public void Debug(string message) + { + } + + public void Information(string message) + { + } + + public void Warning(string message) + { + } + + public void Error(string message, Exception exception) + { + } + + public void Trace(string message) + { + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Logging/NullLoggerFactory.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Logging/NullLoggerFactory.cs new file mode 100644 index 000000000..b87e4f0f7 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Logging/NullLoggerFactory.cs @@ -0,0 +1,31 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Logging; +using System; + +namespace Surging.Apm.Skywalking.Core.Logging +{ + public class NullLoggerFactory : ILoggerFactory + { + public ILogger CreateLogger(Type type) + { + return new NullLogger(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/RuntimeEnvironment.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/RuntimeEnvironment.cs new file mode 100644 index 000000000..03d37254f --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/RuntimeEnvironment.cs @@ -0,0 +1,39 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Common; +using System; + +namespace Surging.Apm.Skywalking.Core +{ + public class RuntimeEnvironment : IRuntimeEnvironment + { + public static IRuntimeEnvironment Instance { get; } = new RuntimeEnvironment(); + + public NullableValue ServiceId { get; internal set; } + + public NullableValue ServiceInstanceId { get; internal set; } + + public bool Initialized => ServiceId.HasValue && ServiceInstanceId.HasValue; + + public Guid InstanceId { get; } = Guid.NewGuid(); + + public IEnvironmentProvider Environment { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Sampling/RandomSamplingInterceptor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Sampling/RandomSamplingInterceptor.cs new file mode 100644 index 000000000..b5e7ae87f --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Sampling/RandomSamplingInterceptor.cs @@ -0,0 +1,51 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Tracing; + +namespace Surging.Apm.Skywalking.Core.Sampling +{ + public class RandomSamplingInterceptor : ISamplingInterceptor + { + private readonly Random _random; + private readonly int _samplingRate; + private readonly bool _sample_on; + + public RandomSamplingInterceptor(IConfigAccessor configAccessor) + { + var percentage = configAccessor.Get().Percentage; + _sample_on = percentage > 0; + if (_sample_on) + { + _samplingRate = (int)(percentage * 100d); + } + _random = new Random(); + } + + public int Priority { get; } = int.MinValue + 1000; + + public bool Invoke(SamplingContext samplingContext, Sampler next) + { + if (!_sample_on) return next(samplingContext); + var r = _random.Next(10000); + return r <= _samplingRate && next(samplingContext); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Sampling/SimpleCountSamplingInterceptor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Sampling/SimpleCountSamplingInterceptor.cs new file mode 100644 index 000000000..a2917c762 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Sampling/SimpleCountSamplingInterceptor.cs @@ -0,0 +1,69 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Core.Common; + +namespace Surging.Apm.Skywalking.Core.Sampling +{ + public class SimpleCountSamplingInterceptor : ExecutionService, ISamplingInterceptor + { + private readonly bool _sample_on; + private readonly int _samplePer3Secs; + private readonly AtomicInteger _idx = new AtomicInteger(); + + public SimpleCountSamplingInterceptor(IConfigAccessor configAccessor,IRuntimeEnvironment runtimeEnvironment, ILoggerFactory loggerFactory) : + base(runtimeEnvironment, loggerFactory) + { + var samplingConfig = configAccessor.Get(); + _samplePer3Secs = samplingConfig.SamplePer3Secs; + _sample_on = _samplePer3Secs > -1; + } + + public int Priority { get; } = int.MinValue + 999; + + public bool Invoke(SamplingContext samplingContext, Sampler next) + { + if (!_sample_on) return next(samplingContext); + return _idx.Increment() <= _samplePer3Secs && next(samplingContext); + } + + protected override TimeSpan DueTime { get; } = TimeSpan.Zero; + + protected override TimeSpan Period { get; } = TimeSpan.FromSeconds(3); + + protected override bool CanExecute() => _sample_on && base.CanExecute(); + + protected override Task ExecuteAsync(CancellationToken cancellationToken) + { + Reset(); + return Task.CompletedTask; + } + + private void Reset() + { + _idx.Value = 0; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/CLRStatsService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/CLRStatsService.cs new file mode 100644 index 000000000..e70ff2199 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/CLRStatsService.cs @@ -0,0 +1,84 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Core.Common; + +namespace Surging.Apm.Skywalking.Core.Service +{ + public class CLRStatsService : ExecutionService + { + private readonly ICLRStatsReporter _reporter; + + public CLRStatsService(ICLRStatsReporter reporter, IRuntimeEnvironment runtimeEnvironment, + ILoggerFactory loggerFactory) + : base(runtimeEnvironment, loggerFactory) + { + _reporter = reporter; + } + + protected override TimeSpan DueTime { get; } = TimeSpan.FromSeconds(30); + protected override TimeSpan Period { get; } = TimeSpan.FromSeconds(30); + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + var cpuStats = new CPUStatsRequest + { + UsagePercent = CpuHelpers.UsagePercent + }; + var gcStats = new GCStatsRequest + { + Gen0CollectCount = GCHelpers.Gen0CollectCount, + Gen1CollectCount = GCHelpers.Gen1CollectCount, + Gen2CollectCount = GCHelpers.Gen2CollectCount, + HeapMemory = GCHelpers.TotalMemory + }; + ThreadPool.GetAvailableThreads(out var availableWorkerThreads, out var availableCompletionPortThreads); + ThreadPool.GetMaxThreads(out var maxWorkerThreads, out var maxCompletionPortThreads); + var threadStats = new ThreadStatsRequest + { + MaxCompletionPortThreads = maxCompletionPortThreads, + MaxWorkerThreads = maxWorkerThreads, + AvailableCompletionPortThreads = availableCompletionPortThreads, + AvailableWorkerThreads = availableWorkerThreads + }; + var statsRequest = new CLRStatsRequest + { + CPU = cpuStats, + GC = gcStats, + Thread = threadStats + }; + try + { + await _reporter.ReportAsync(statsRequest, cancellationToken); + Logger.LogInformation( + $"Report CLR Stats. CPU UsagePercent {cpuStats.UsagePercent} GenCollectCount {gcStats.Gen0CollectCount} {gcStats.Gen1CollectCount} {gcStats.Gen2CollectCount} {gcStats.HeapMemory / (1024 * 1024)}M ThreadPool {threadStats.AvailableWorkerThreads} {threadStats.MaxWorkerThreads} {threadStats.AvailableCompletionPortThreads} {threadStats.MaxCompletionPortThreads}"); + } + catch (Exception exception) + { + Logger.LogError("Report CLR Stats error.", exception); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/PingService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/PingService.cs new file mode 100644 index 000000000..f584cfc7e --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/PingService.cs @@ -0,0 +1,67 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Core.Service +{ + public class PingService : ExecutionService + { + private readonly IPingCaller _pingCaller; + private readonly TransportConfig _transportConfig; + + public PingService(IConfigAccessor configAccessor, IPingCaller pingCaller, + IRuntimeEnvironment runtimeEnvironment, + ILoggerFactory loggerFactory) : base( + runtimeEnvironment, loggerFactory) + { + _pingCaller = pingCaller; + _transportConfig = configAccessor.Get(); + } + + protected override bool CanExecute() => + _transportConfig.ProtocolVersion == ProtocolVersions.V6 && base.CanExecute(); + + protected override TimeSpan DueTime { get; } = TimeSpan.FromSeconds(30); + protected override TimeSpan Period { get; } = TimeSpan.FromSeconds(60); + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + try + { + await _pingCaller.PingAsync( + new PingRequest + { + ServiceInstanceId = RuntimeEnvironment.ServiceInstanceId.Value, + InstanceId = RuntimeEnvironment.InstanceId.ToString("N") + }, cancellationToken); + Logger.LogInformation($"Ping server @{DateTimeOffset.UtcNow}"); + } + catch (Exception exception) + { + Logger.LogError($"Ping server fail @{DateTimeOffset.UtcNow}", exception); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/RegisterService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/RegisterService.cs new file mode 100644 index 000000000..e84152824 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/RegisterService.cs @@ -0,0 +1,126 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Core.Common; + +namespace Surging.Apm.Skywalking.Core.Service +{ + public class RegisterService : ExecutionService + { + private readonly InstrumentConfig _config; + private readonly IServiceRegister _serviceRegister; + private readonly TransportConfig _transportConfig; + + public RegisterService(IConfigAccessor configAccessor, IServiceRegister serviceRegister, + IRuntimeEnvironment runtimeEnvironment, ILoggerFactory loggerFactory) : base(runtimeEnvironment, + loggerFactory) + { + _serviceRegister = serviceRegister; + _config = configAccessor.Get(); + _transportConfig = configAccessor.Get(); + } + + protected override TimeSpan DueTime { get; } = TimeSpan.Zero; + + protected override TimeSpan Period { get; } = TimeSpan.FromSeconds(30); + + protected override bool CanExecute() => + _transportConfig.ProtocolVersion == ProtocolVersions.V6 && !RuntimeEnvironment.Initialized; + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + await RegisterServiceAsync(cancellationToken); + await RegisterServiceInstanceAsync(cancellationToken); + } + + private async Task RegisterServiceAsync(CancellationToken cancellationToken) + { + if (!RuntimeEnvironment.ServiceId.HasValue) + { + var request = new ServiceRequest + { + ServiceName = _config.ServiceName ?? _config.ApplicationCode + }; + var value = await Polling(3, + () => _serviceRegister.RegisterServiceAsync(request, cancellationToken), + cancellationToken); + if (value.HasValue && RuntimeEnvironment is RuntimeEnvironment environment) + { + environment.ServiceId = value; + Logger.LogInformation($"Registered Service[Id={environment.ServiceId.Value}]."); + } + } + } + + private async Task RegisterServiceInstanceAsync(CancellationToken cancellationToken) + { + if (RuntimeEnvironment.ServiceId.HasValue && !RuntimeEnvironment.ServiceInstanceId.HasValue) + { + var properties = new AgentOsInfoRequest + { + HostName = DnsHelpers.GetHostName(), + IpAddress = DnsHelpers.GetIpV4s(), + OsName = PlatformInformation.GetOSName(), + ProcessNo = Process.GetCurrentProcess().Id, + Language = "dotnet" + }; + var request = new ServiceInstanceRequest + { + ServiceId = RuntimeEnvironment.ServiceId.Value, + InstanceUUID = RuntimeEnvironment.InstanceId.ToString("N"), + Properties = properties + }; + var value = await Polling(3, + () => _serviceRegister.RegisterServiceInstanceAsync(request, cancellationToken), + cancellationToken); + if (value.HasValue && RuntimeEnvironment is RuntimeEnvironment environment) + { + environment.ServiceInstanceId = value; + Logger.LogInformation($"Registered ServiceInstance[Id={environment.ServiceInstanceId.Value}]."); + } + } + } + + private static async Task Polling(int retry, Func> execute, + CancellationToken cancellationToken) + { + var index = 0; + while (index++ < retry) + { + var value = await execute(); + if (value.HasValue) + { + return value; + } + + await Task.Delay(500, cancellationToken); + } + + return NullableValue.Null; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/SegmentReportService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/SegmentReportService.cs new file mode 100644 index 000000000..f2105d420 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/SegmentReportService.cs @@ -0,0 +1,58 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Core.Service +{ + public class SegmentReportService : ExecutionService + { + private readonly TransportConfig _config; + private readonly ISegmentDispatcher _dispatcher; + + public SegmentReportService(IConfigAccessor configAccessor, ISegmentDispatcher dispatcher, + IRuntimeEnvironment runtimeEnvironment, ILoggerFactory loggerFactory) + : base(runtimeEnvironment, loggerFactory) + { + _dispatcher = dispatcher; + _config = configAccessor.Get(); + Period = TimeSpan.FromMilliseconds(_config.Interval); + } + + protected override TimeSpan DueTime { get; } = TimeSpan.FromSeconds(3); + + protected override TimeSpan Period { get; } + + protected override Task ExecuteAsync(CancellationToken cancellationToken) + { + return _dispatcher.Flush(cancellationToken); + } + + protected override Task Stopping(CancellationToken cancellationToke) + { + _dispatcher.Close(); + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/ServiceDiscoveryV5Service.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/ServiceDiscoveryV5Service.cs new file mode 100644 index 000000000..e1a66115a --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Service/ServiceDiscoveryV5Service.cs @@ -0,0 +1,137 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Core.Common; +using Surging.Apm.Skywalking.Transport.Grpc.V5; + +namespace Surging.Apm.Skywalking.Core.Service +{ + public class ServiceDiscoveryV5Service : ExecutionService + { + private readonly InstrumentConfig _config; + private readonly TransportConfig _transportConfig; + private readonly ISkyApmClientV5 skyApmClient; + + protected override TimeSpan DueTime { get; } = TimeSpan.Zero; + + protected override TimeSpan Period { get; } = TimeSpan.FromSeconds(30); + + public ServiceDiscoveryV5Service(IConfigAccessor configAccessor, ISkyApmClientV5 skyApmClient, + IRuntimeEnvironment runtimeEnvironment, ILoggerFactory loggerFactory) + : base(runtimeEnvironment, loggerFactory) + { + _config = configAccessor.Get(); + _transportConfig = configAccessor.Get(); + this.skyApmClient = skyApmClient; + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + await RegisterApplication(cancellationToken); + await RegisterApplicationInstance(cancellationToken); + await Heartbeat(cancellationToken); + } + + protected override bool CanExecute() => + _transportConfig.ProtocolVersion == ProtocolVersions.V5 && !RuntimeEnvironment.Initialized; + + private async Task RegisterApplication(CancellationToken cancellationToken) + { + if (!RuntimeEnvironment.ServiceId.HasValue) + { + var value = await Polling(3, + () => skyApmClient.RegisterApplicationAsync(_config.ServiceName ?? _config.ApplicationCode, cancellationToken), + cancellationToken); + if (value.HasValue && RuntimeEnvironment is RuntimeEnvironment environment) + { + environment.ServiceId = value; + Logger.LogInformation($"Registered Application[Id={environment.ServiceId.Value}]."); + } + } + } + + private async Task RegisterApplicationInstance(CancellationToken cancellationToken) + { + if (RuntimeEnvironment.ServiceId.HasValue && !RuntimeEnvironment.ServiceInstanceId.HasValue) + { + var osInfoRequest = new AgentOsInfoRequest + { + HostName = DnsHelpers.GetHostName(), + IpAddress = DnsHelpers.GetIpV4s(), + OsName = PlatformInformation.GetOSName(), + ProcessNo = Process.GetCurrentProcess().Id + }; + var value = await Polling(3, + () => skyApmClient.RegisterApplicationInstanceAsync(RuntimeEnvironment.ServiceId.Value, + RuntimeEnvironment.InstanceId, + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), osInfoRequest, cancellationToken), + cancellationToken); + if (value.HasValue && RuntimeEnvironment is RuntimeEnvironment environment) + { + environment.ServiceInstanceId = value; + Logger.LogInformation( + $"Registered Application Instance[Id={environment.ServiceInstanceId.Value}]."); + } + } + } + + private static async Task Polling(int retry, Func> execute, + CancellationToken cancellationToken) + { + var index = 0; + while (index++ < retry) + { + var value = await execute(); + if (value.HasValue) + { + return value; + } + + await Task.Delay(500, cancellationToken); + } + + return NullableValue.Null; + } + + private async Task Heartbeat(CancellationToken cancellationToken) + { + if (RuntimeEnvironment.Initialized) + { + try + { + await skyApmClient.HeartbeatAsync(RuntimeEnvironment.ServiceInstanceId.Value, + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), cancellationToken); + Logger.LogDebug($"Heartbeat at {DateTimeOffset.UtcNow}."); + } + catch (Exception e) + { + Logger.LogError("Heartbeat error.", e); + } + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Carrier.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Carrier.cs new file mode 100644 index 000000000..a0f3b9555 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Carrier.cs @@ -0,0 +1,57 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class Carrier : ICarrier + { + public bool HasValue { get; } = true; + + public bool? Sampled { get; set; } + + public UniqueId TraceId { get; } + + public UniqueId ParentSegmentId { get; } + + public int ParentSpanId { get; } + + public int ParentServiceInstanceId { get; } + + public int EntryServiceInstanceId { get; } + + public StringOrIntValue NetworkAddress { get; set; } + + public StringOrIntValue EntryEndpoint { get; set; } + + public StringOrIntValue ParentEndpoint { get; set; } + + public Carrier(UniqueId traceId, UniqueId parentSegmentId, int parentSpanId, int parentServiceInstanceId, + int entryServiceInstanceId) + { + TraceId = traceId; + ParentSegmentId = parentSegmentId; + ParentSpanId = parentSpanId; + ParentServiceInstanceId = parentServiceInstanceId; + EntryServiceInstanceId = entryServiceInstanceId; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/CarrierPropagator.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/CarrierPropagator.cs new file mode 100644 index 000000000..029e2ce46 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/CarrierPropagator.cs @@ -0,0 +1,93 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System.Collections.Generic; +using System.Linq; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class CarrierPropagator : ICarrierPropagator + { + private readonly IEnumerable _carrierFormatters; + private readonly ISegmentContextFactory _segmentContextFactory; + + public CarrierPropagator(IEnumerable carrierFormatters, + ISegmentContextFactory segmentContextFactory) + { + _carrierFormatters = carrierFormatters; + _segmentContextFactory = segmentContextFactory; + } + + public void Inject(SegmentContext segmentContext, ICarrierHeaderCollection headerCollection) + { + var reference = segmentContext.References.FirstOrDefault(); + + var carrier = new Carrier(segmentContext.TraceId, segmentContext.SegmentId, segmentContext.Span.SpanId, + segmentContext.ServiceInstanceId, reference?.EntryServiceInstanceId ?? segmentContext.ServiceInstanceId) + { + NetworkAddress = segmentContext.Span.Peer, + EntryEndpoint = reference?.EntryEndpoint ?? segmentContext.Span.OperationName, + ParentEndpoint = segmentContext.Span.OperationName, + Sampled = segmentContext.Sampled + }; + + foreach (var formatter in _carrierFormatters) + { + if (formatter.Enable) + headerCollection.Add(formatter.Key, formatter.Encode(carrier)); + } + } + + public ICarrier Extract(ICarrierHeaderCollection headerCollection) + { + ICarrier carrier = NullableCarrier.Instance; + if (headerCollection == null) + { + return carrier; + } + foreach (var formatter in _carrierFormatters.OrderByDescending(x => x.Key)) + { + if (!formatter.Enable) + { + continue; + } + + foreach (var header in headerCollection) + { + if (formatter.Key == header.Key) + { + carrier = formatter.Decode(header.Value); + if (carrier.HasValue) + { + if (formatter.Key.EndsWith("sw3") && carrier is Carrier c) + { + c.Sampled = true; + } + + return carrier; + } + } + } + } + + return carrier; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/EntrySegmentContextAccessor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/EntrySegmentContextAccessor.cs new file mode 100644 index 000000000..277d0d933 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/EntrySegmentContextAccessor.cs @@ -0,0 +1,35 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System.Threading; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class EntrySegmentContextAccessor : IEntrySegmentContextAccessor + { + private readonly AsyncLocal _segmentContext = new AsyncLocal(); + + public SegmentContext Context + { + get => _segmentContext.Value; + set => _segmentContext.Value = value; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/ExitSegmentContextAccessor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/ExitSegmentContextAccessor.cs new file mode 100644 index 000000000..5a7fce621 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/ExitSegmentContextAccessor.cs @@ -0,0 +1,34 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Core.CPlatform.Diagnostics; +using System.Threading; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class ExitSegmentContextAccessor : IExitSegmentContextAccessor + { + private readonly AsyncLocal _segmentContext = new AsyncLocal(); + + public SegmentContext Context + { + get => _segmentContext.Value; + set => _segmentContext.Value = value; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/LocalSegmentContextAccessor.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/LocalSegmentContextAccessor.cs new file mode 100644 index 000000000..30a11d052 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/LocalSegmentContextAccessor.cs @@ -0,0 +1,50 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class LocalSegmentContextAccessor : ILocalSegmentContextAccessor + { + private readonly ConditionalWeakTable _parent = new ConditionalWeakTable(); + private readonly AsyncLocal _segmentContext = new AsyncLocal(); + + public SegmentContext Context + { + get => _segmentContext.Value; + set + { + var current = _segmentContext.Value; + if (value == null) + { + if (_parent.TryGetValue(current, out var parent)) + _segmentContext.Value = parent; + } + else + { + _parent.Add(value, current); + _segmentContext.Value = value; + } + } + } + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/NullableCarrier.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/NullableCarrier.cs new file mode 100644 index 000000000..c13d97ca0 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/NullableCarrier.cs @@ -0,0 +1,49 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class NullableCarrier : ICarrier + { + public static NullableCarrier Instance { get; } = new NullableCarrier(); + + public bool HasValue { get; } = false; + + public bool? Sampled { get; } + + public UniqueId TraceId { get; } + + public UniqueId ParentSegmentId { get; } + + public int ParentSpanId { get; } + + public int ParentServiceInstanceId { get; } + + public int EntryServiceInstanceId { get; } + + public StringOrIntValue NetworkAddress { get; } + + public StringOrIntValue EntryEndpoint { get; } + + public StringOrIntValue ParentEndpoint { get; } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/SamplerChainBuilder.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/SamplerChainBuilder.cs new file mode 100644 index 000000000..6c4ab1f48 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/SamplerChainBuilder.cs @@ -0,0 +1,64 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class SamplerChainBuilder : ISamplerChainBuilder + { + private volatile int state = 0; + private readonly IEnumerable _sampledInterceptors; + private Sampler _sampler; + + public SamplerChainBuilder(IEnumerable sampledInterceptors) + { + _sampledInterceptors = sampledInterceptors; + } + + public Sampler Build() + { + if (_sampler != null) + return _sampler; + + if (Interlocked.CompareExchange(ref state, 1, 0) == 0) + { + var samplers = _sampledInterceptors.OrderBy(x => x.Priority).Select(interceptor => + (Func) (next => ctx => interceptor.Invoke(ctx, next))).ToList(); + + Sampler sampler = ctx => true; + foreach (var next in samplers) + { + sampler = next(sampler); + } + + return _sampler = sampler; + } + + while (_sampler == null) + { + } + + return _sampler; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/SegmentContextFactory.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/SegmentContextFactory.cs new file mode 100644 index 000000000..bca975303 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/SegmentContextFactory.cs @@ -0,0 +1,225 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Linq; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class SegmentContextFactory : ISegmentContextFactory + { + private readonly IEntrySegmentContextAccessor _entrySegmentContextAccessor; + private readonly ILocalSegmentContextAccessor _localSegmentContextAccessor; + private readonly IExitSegmentContextAccessor _exitSegmentContextAccessor; + private readonly IRuntimeEnvironment _runtimeEnvironment; + private readonly ISamplerChainBuilder _samplerChainBuilder; + private readonly IUniqueIdGenerator _uniqueIdGenerator; + + public SegmentContextFactory(IRuntimeEnvironment runtimeEnvironment, + ISamplerChainBuilder samplerChainBuilder, + IUniqueIdGenerator uniqueIdGenerator, + IEntrySegmentContextAccessor entrySegmentContextAccessor, + ILocalSegmentContextAccessor localSegmentContextAccessor, + IExitSegmentContextAccessor exitSegmentContextAccessor) + { + _runtimeEnvironment = runtimeEnvironment; + _samplerChainBuilder = samplerChainBuilder; + _uniqueIdGenerator = uniqueIdGenerator; + _entrySegmentContextAccessor = entrySegmentContextAccessor; + _localSegmentContextAccessor = localSegmentContextAccessor; + _exitSegmentContextAccessor = exitSegmentContextAccessor; + } + + public SegmentContext CreateEntrySegment(string operationName, ICarrier carrier) + { + var traceId = GetTraceId(carrier); + var segmentId = GetSegmentId(); + var sampled = GetSampled(carrier, operationName); + var segmentContext = new SegmentContext(traceId, segmentId, sampled, _runtimeEnvironment.ServiceId.Value, + _runtimeEnvironment.ServiceInstanceId.Value, operationName, SpanType.Entry); + + if (carrier.HasValue) + { + var segmentReference = new SegmentReference + { + Reference = Reference.CrossProcess, + EntryEndpoint = carrier.EntryEndpoint, + NetworkAddress = carrier.NetworkAddress, + ParentEndpoint = carrier.ParentEndpoint, + ParentSpanId = carrier.ParentSpanId, + ParentSegmentId = carrier.ParentSegmentId, + EntryServiceInstanceId = carrier.EntryServiceInstanceId, + ParentServiceInstanceId = carrier.ParentServiceInstanceId + }; + segmentContext.References.Add(segmentReference); + } + + _entrySegmentContextAccessor.Context = segmentContext; + return segmentContext; + } + + public SegmentContext CreateLocalSegment(string operationName) + { + var parentSegmentContext = GetParentSegmentContext(SpanType.Local); + var traceId = GetTraceId(parentSegmentContext); + var segmentId = GetSegmentId(); + var sampled = GetSampled(parentSegmentContext, operationName); + var segmentContext = new SegmentContext(traceId, segmentId, sampled, _runtimeEnvironment.ServiceId.Value, + _runtimeEnvironment.ServiceInstanceId.Value, operationName, SpanType.Local); + + if (parentSegmentContext != null) + { + var parentReference = parentSegmentContext.References.FirstOrDefault(); + var reference = new SegmentReference + { + Reference = Reference.CrossThread, + EntryEndpoint = parentReference?.EntryEndpoint ?? parentSegmentContext.Span.OperationName, + NetworkAddress = parentReference?.NetworkAddress ?? parentSegmentContext.Span.OperationName, + ParentEndpoint = parentSegmentContext.Span.OperationName, + ParentSpanId = parentSegmentContext.Span.SpanId, + ParentSegmentId = parentSegmentContext.SegmentId, + EntryServiceInstanceId = + parentReference?.EntryServiceInstanceId ?? parentSegmentContext.ServiceInstanceId, + ParentServiceInstanceId = parentSegmentContext.ServiceInstanceId + }; + segmentContext.References.Add(reference); + } + + _localSegmentContextAccessor.Context = segmentContext; + return segmentContext; + } + + public SegmentContext CreateExitSegment(string operationName, StringOrIntValue networkAddress) + { + var parentSegmentContext = GetParentSegmentContext(SpanType.Exit); + var traceId = GetTraceId(parentSegmentContext); + var segmentId = GetSegmentId(); + var sampled = GetSampled(parentSegmentContext, operationName, networkAddress); + var segmentContext = new SegmentContext(traceId, segmentId, sampled, _runtimeEnvironment.ServiceId.Value, + _runtimeEnvironment.ServiceInstanceId.Value, operationName, SpanType.Exit); + + if (parentSegmentContext != null) + { + var parentReference = parentSegmentContext.References.FirstOrDefault(); + var reference = new SegmentReference + { + Reference = Reference.CrossThread, + EntryEndpoint = parentReference?.EntryEndpoint ?? parentSegmentContext.Span.OperationName, + NetworkAddress = parentReference?.NetworkAddress ?? parentSegmentContext.Span.OperationName, + ParentEndpoint = parentSegmentContext.Span.OperationName, + ParentSpanId = parentSegmentContext.Span.SpanId, + ParentSegmentId = parentSegmentContext.SegmentId, + EntryServiceInstanceId = + parentReference?.EntryServiceInstanceId ?? parentSegmentContext.ServiceInstanceId, + ParentServiceInstanceId = parentSegmentContext.ServiceInstanceId + }; + segmentContext.References.Add(reference); + } + + segmentContext.Span.Peer = networkAddress; + _exitSegmentContextAccessor.Context = segmentContext; + return segmentContext; + } + + public void Release(SegmentContext segmentContext) + { + segmentContext.Span.Finish(); + switch (segmentContext.Span.SpanType) + { + case SpanType.Entry: + _entrySegmentContextAccessor.Context = null; + break; + case SpanType.Local: + _localSegmentContextAccessor.Context = null; + break; + case SpanType.Exit: + _exitSegmentContextAccessor.Context = null; + break; + default: + throw new ArgumentOutOfRangeException(nameof(SpanType), segmentContext.Span.SpanType, "Invalid SpanType."); + } + } + + private UniqueId GetTraceId(ICarrier carrier) + { + return carrier.HasValue ? carrier.TraceId : _uniqueIdGenerator.Generate(); + } + + private UniqueId GetTraceId(SegmentContext parentSegmentContext) + { + return parentSegmentContext?.TraceId ?? _uniqueIdGenerator.Generate(); + } + + private UniqueId GetSegmentId() + { + return _uniqueIdGenerator.Generate(); + } + + private bool GetSampled(ICarrier carrier, string operationName) + { + if (carrier.HasValue && carrier.Sampled.HasValue) + { + return carrier.Sampled.Value; + } + + SamplingContext samplingContext; + if (carrier.HasValue) + { + samplingContext = new SamplingContext(operationName, carrier.NetworkAddress, carrier.EntryEndpoint, + carrier.ParentEndpoint); + } + else + { + samplingContext = new SamplingContext(operationName, default(StringOrIntValue), default(StringOrIntValue), + default(StringOrIntValue)); + } + + var sampler = _samplerChainBuilder.Build(); + return sampler(samplingContext); + } + + private bool GetSampled(SegmentContext parentSegmentContext, string operationName, + StringOrIntValue peer = default(StringOrIntValue)) + { + if (parentSegmentContext != null) return parentSegmentContext.Sampled; + var sampledContext = new SamplingContext(operationName, peer, new StringOrIntValue(operationName), + default(StringOrIntValue)); + var sampler = _samplerChainBuilder.Build(); + return sampler(sampledContext); + } + + private SegmentContext GetParentSegmentContext(SpanType spanType) + { + switch (spanType) + { + case SpanType.Entry: + return null; + case SpanType.Local: + //return _entrySegmentContextAccessor.Context; + case SpanType.Exit: + return _localSegmentContextAccessor.Context ?? _entrySegmentContextAccessor.Context; + default: + throw new ArgumentOutOfRangeException(nameof(spanType), spanType, "Invalid SpanType."); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Sw3CarrierFormatter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Sw3CarrierFormatter.cs new file mode 100644 index 000000000..41d7ac6e6 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Sw3CarrierFormatter.cs @@ -0,0 +1,109 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Core.Common; +using Surging.Apm.Skywalking.Abstractions.Common; +using System.Linq; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Core.Tracing +{ + public class Sw3CarrierFormatter : ICarrierFormatter + { + private readonly IUniqueIdParser _uniqueIdParser; + + public Sw3CarrierFormatter(IUniqueIdParser uniqueIdParser, IConfigAccessor configAccessor) + { + _uniqueIdParser = uniqueIdParser; + var config = configAccessor.Get(); + Key = string.IsNullOrEmpty(config.Namespace) + ? HeaderVersions.SW3 + : $"{config.Namespace}-{HeaderVersions.SW3}"; + Enable = config.HeaderVersions != null && config.HeaderVersions.Contains(HeaderVersions.SW3); + } + + public string Key { get; } + + public bool Enable { get; } + + public ICarrier Decode(string content) + { + NullableCarrier Defer() + { + return NullableCarrier.Instance; + } + + if (string.IsNullOrEmpty(content)) + return Defer(); + + var parts = content.Split('|'); + if (parts.Length < 8) + return Defer(); + + if (!_uniqueIdParser.TryParse(parts[0], out var segmentId)) + return Defer(); + + if (!int.TryParse(parts[1], out var parentSpanId)) + return Defer(); + + if (!int.TryParse(parts[2], out var parentServiceInstanceId)) + return Defer(); + + if (!int.TryParse(parts[3], out var entryServiceInstanceId)) + return Defer(); + + if (!_uniqueIdParser.TryParse(parts[7], out var traceId)) + return Defer(); + + return new Carrier(traceId, segmentId, parentSpanId, parentServiceInstanceId, + entryServiceInstanceId) + { + NetworkAddress = StringOrIntValueHelpers.ParseStringOrIntValue(parts[4]), + EntryEndpoint = StringOrIntValueHelpers.ParseStringOrIntValue(parts[5]), + ParentEndpoint = StringOrIntValueHelpers.ParseStringOrIntValue(parts[6]) + }; + } + + public string Encode(ICarrier carrier) + { + if (!carrier.HasValue) + return string.Empty; + return string.Join("|", + carrier.ParentSegmentId.ToString(), + carrier.ParentSpanId.ToString(), + carrier.ParentServiceInstanceId.ToString(), + carrier.EntryServiceInstanceId.ToString(), + ConvertStringOrIntValue(carrier.NetworkAddress), + ConvertStringOrIntValue(carrier.EntryEndpoint), + ConvertStringOrIntValue(carrier.ParentEndpoint), + carrier.TraceId.ToString()); + } + + private static string ConvertStringOrIntValue(StringOrIntValue value) + { + if (value.HasIntValue) + { + return value.GetIntValue().ToString(); + } + + return "#" + value.GetStringValue(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Sw6CarrierFormatter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Sw6CarrierFormatter.cs new file mode 100644 index 000000000..e992b8925 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/Sw6CarrierFormatter.cs @@ -0,0 +1,125 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Core.Common; +using Surging.Apm.Skywalking.Core.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System.Linq; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Tracing +{ + public class Sw6CarrierFormatter : ICarrierFormatter + { + private readonly IUniqueIdParser _uniqueIdParser; + private readonly IBase64Formatter _base64Formatter; + + public Sw6CarrierFormatter(IUniqueIdParser uniqueIdParser, IBase64Formatter base64Formatter, + IConfigAccessor configAccessor) + { + _uniqueIdParser = uniqueIdParser; + _base64Formatter = base64Formatter; + var config = configAccessor.Get(); + Key = string.IsNullOrEmpty(config.Namespace) + ? HeaderVersions.SW6 + : $"{config.Namespace}-{HeaderVersions.SW6}"; + Enable = config.HeaderVersions == null || config.HeaderVersions.Contains(HeaderVersions.SW6); + } + + public string Key { get; } + + public bool Enable { get; } + + public ICarrier Decode(string content) + { + NullableCarrier Defer() + { + return NullableCarrier.Instance; + } + + if (string.IsNullOrEmpty(content)) + return Defer(); + + var parts = content.Split('-'); + if (parts.Length < 7) + return Defer(); + + if (!int.TryParse(parts[0], out var sampled)) + return Defer(); + + if (!_uniqueIdParser.TryParse(_base64Formatter.Decode(parts[1]), out var traceId)) + return Defer(); + + if (!_uniqueIdParser.TryParse(_base64Formatter.Decode(parts[2]), out var segmentId)) + return Defer(); + + if (!int.TryParse(parts[3], out var parentSpanId)) + return Defer(); + + if (!int.TryParse(parts[4], out var parentServiceInstanceId)) + return Defer(); + + if (!int.TryParse(parts[5], out var entryServiceInstanceId)) + return Defer(); + + var carrier = new Carrier(traceId, segmentId, parentSpanId, parentServiceInstanceId, + entryServiceInstanceId) + { + NetworkAddress = StringOrIntValueHelpers.ParseStringOrIntValue(_base64Formatter.Decode(parts[6])), + Sampled = sampled != 0 + }; + + if (parts.Length >= 9) + { + carrier.ParentEndpoint = + StringOrIntValueHelpers.ParseStringOrIntValue(_base64Formatter.Decode(parts[7])); + carrier.EntryEndpoint = + StringOrIntValueHelpers.ParseStringOrIntValue(_base64Formatter.Decode(parts[8])); + } + + return carrier; + } + + public string Encode(ICarrier carrier) + { + if (!carrier.HasValue) + return string.Empty; + return string.Join("-", + carrier.Sampled != null && carrier.Sampled.Value ? "1" : "0", + _base64Formatter.Encode(carrier.TraceId.ToString()), + _base64Formatter.Encode(carrier.ParentSegmentId.ToString()), + carrier.ParentSpanId.ToString(), + carrier.ParentServiceInstanceId.ToString(), + carrier.EntryServiceInstanceId.ToString(), + _base64Formatter.Encode(ConvertStringOrIntValue(carrier.NetworkAddress)), + _base64Formatter.Encode(ConvertStringOrIntValue(carrier.ParentEndpoint)), + _base64Formatter.Encode(ConvertStringOrIntValue(carrier.EntryEndpoint))); + } + + private static string ConvertStringOrIntValue(StringOrIntValue value) + { + if (value.HasIntValue) + { + return value.GetIntValue().ToString(); + } + + return "#" + value.GetStringValue(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/TextCarrierHeaderCollection.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/TextCarrierHeaderCollection.cs new file mode 100644 index 000000000..9dba9d1c7 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/TextCarrierHeaderCollection.cs @@ -0,0 +1,59 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System.Collections; +using System.Collections.Generic; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Tracing +{ + public class TextCarrierHeaderCollection : ICarrierHeaderCollection + { + private readonly IDictionary _headers; + + public TextCarrierHeaderCollection(IEnumerable> headers) + { + _headers = new Dictionary(); + foreach (var header in headers) + { + _headers[header.Key] = header.Value; + } + } + + public TextCarrierHeaderCollection(IDictionary headers) + { + _headers = headers; + } + + public IEnumerator> GetEnumerator() + { + return _headers.GetEnumerator(); + } + + public void Add(string key, string value) + { + _headers[key] = value; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _headers.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/TracingContext.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/TracingContext.cs new file mode 100644 index 000000000..f2b4f6af0 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/TracingContext.cs @@ -0,0 +1,75 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Tracing +{ + public class TracingContext : ITracingContext + { + private readonly ISegmentContextFactory _segmentContextFactory; + private readonly ICarrierPropagator _carrierPropagator; + private readonly ISegmentDispatcher _segmentDispatcher; + + public TracingContext(ISegmentContextFactory segmentContextFactory, ICarrierPropagator carrierPropagator, + ISegmentDispatcher segmentDispatcher) + { + _segmentContextFactory = segmentContextFactory; + _carrierPropagator = carrierPropagator; + _segmentDispatcher = segmentDispatcher; + } + + public SegmentContext CreateEntrySegmentContext(string operationName, ICarrierHeaderCollection carrierHeader) + { + if (operationName == null) throw new ArgumentNullException(nameof(operationName)); + var carrier = _carrierPropagator.Extract(carrierHeader); + return _segmentContextFactory.CreateEntrySegment(operationName, carrier); + } + + public SegmentContext CreateLocalSegmentContext(string operationName) + { + if (operationName == null) throw new ArgumentNullException(nameof(operationName)); + return _segmentContextFactory.CreateLocalSegment(operationName); + } + + public SegmentContext CreateExitSegmentContext(string operationName, string networkAddress, + ICarrierHeaderCollection carrierHeader = default(ICarrierHeaderCollection)) + { + var segmentContext = + _segmentContextFactory.CreateExitSegment(operationName, new StringOrIntValue(networkAddress)); + if (carrierHeader != null) + _carrierPropagator.Inject(segmentContext, carrierHeader); + return segmentContext; + } + + public void Release(SegmentContext segmentContext) + { + if (segmentContext == null) + { + return; + } + + _segmentContextFactory.Release(segmentContext); + if (segmentContext.Sampled) + _segmentDispatcher.Dispatch(segmentContext); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/UniqueIdGenerator.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/UniqueIdGenerator.cs new file mode 100644 index 000000000..82baccab3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/UniqueIdGenerator.cs @@ -0,0 +1,53 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System; +using System.Threading; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Tracing +{ + public class UniqueIdGenerator : IUniqueIdGenerator + { + private readonly ThreadLocal sequence = new ThreadLocal(() => 0); + private readonly IRuntimeEnvironment _runtimeEnvironment; + + public UniqueIdGenerator(IRuntimeEnvironment runtimeEnvironment) + { + _runtimeEnvironment = runtimeEnvironment; + } + + public UniqueId Generate() + { + return new UniqueId(_runtimeEnvironment.ServiceInstanceId.Value, + Thread.CurrentThread.ManagedThreadId, + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 10000 + GetSequence()); + } + + private long GetSequence() + { + if (sequence.Value++ >= 9999) + { + sequence.Value = 0; + } + + return sequence.Value; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/UniqueIdParser.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/UniqueIdParser.cs new file mode 100644 index 000000000..323dc9347 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Tracing/UniqueIdParser.cs @@ -0,0 +1,68 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Core.CPlatform.Diagnostics; +using System; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Tracing +{ + public class UniqueIdParser : IUniqueIdParser + { + public bool TryParse(string text, out UniqueId uniqueId) + { + uniqueId = default(UniqueId); + if (string.IsNullOrEmpty(text)) return false; +#if SPAN + var id = text.AsSpan(); + var index = FindIndex(id); + + if (index < 1) return false; + var id1 = id.Slice(0, index); + + index = FindIndex(id.Slice(index + 1)); + if (index < 1) return false; + + if (!long.TryParse(id1, out var part0)) return false; + if (!long.TryParse(id.Slice(id1.Length + 1, index), out var part1)) return false; + if (!long.TryParse(id.Slice(id1.Length + index + 2), out var part2)) return false; +#else + var parts = text.Split("\\.".ToCharArray(), 3); + if (parts.Length < 3) return false; + if (!long.TryParse(parts[0], out var part0)) return false; + if (!long.TryParse(parts[1], out var part1)) return false; + if (!long.TryParse(parts[2], out var part2)) return false; +#endif + uniqueId = new UniqueId(part0, part1, part2); + return true; + } +#if SPAN + private static int FindIndex(ReadOnlySpan id) + { + var index = 0; + do + { + if (id[index] == '\\' || id[index] == '.') + return index; + } while (++index < id.Length); + + return -1; + } +#endif + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Transport/AsyncQueueSegmentDispatcher.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Transport/AsyncQueueSegmentDispatcher.cs new file mode 100644 index 000000000..1dcd3c44c --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Transport/AsyncQueueSegmentDispatcher.cs @@ -0,0 +1,104 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Core.CPlatform.Diagnostics; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Transport +{ + public class AsyncQueueSegmentDispatcher : ISegmentDispatcher + { + private readonly ILogger _logger; + private readonly TransportConfig _config; + private readonly ISegmentReporter _segmentReporter; + private readonly ISegmentContextMapper _segmentContextMapper; + private readonly ConcurrentQueue _segmentQueue; + private readonly IRuntimeEnvironment _runtimeEnvironment; + private readonly CancellationTokenSource _cancellation; + private int _offset; + + public AsyncQueueSegmentDispatcher(IConfigAccessor configAccessor, + ISegmentReporter segmentReporter, IRuntimeEnvironment runtimeEnvironment, + ISegmentContextMapper segmentContextMapper, ILoggerFactory loggerFactory) + { + _segmentReporter = segmentReporter; + _segmentContextMapper = segmentContextMapper; + _runtimeEnvironment = runtimeEnvironment; + _logger = loggerFactory.CreateLogger(typeof(AsyncQueueSegmentDispatcher)); + _config = configAccessor.Get(); + _segmentQueue = new ConcurrentQueue(); + _cancellation = new CancellationTokenSource(); + } + + public bool Dispatch(SegmentContext segmentContext) + { + if (!_runtimeEnvironment.Initialized || segmentContext == null || !segmentContext.Sampled) + return false; + + // todo performance optimization for ConcurrentQueue + if (_config.QueueSize < _offset || _cancellation.IsCancellationRequested) + return false; + + var segment = _segmentContextMapper.Map(segmentContext); + + if (segment == null) + return false; + + _segmentQueue.Enqueue(segment); + + Interlocked.Increment(ref _offset); + + _logger.LogDebug($"Dispatch trace segment. [SegmentId]={segmentContext.SegmentId}."); + return true; + } + + public Task Flush(CancellationToken token = default(CancellationToken)) + { + // todo performance optimization for ConcurrentQueue + //var queued = _segmentQueue.Count; + //var limit = queued <= _config.PendingSegmentLimit ? queued : _config.PendingSegmentLimit; + var limit = _config.BatchSize; + var index = 0; + var segments = new List(limit); + while (index++ < limit && _segmentQueue.TryDequeue(out var request)) + { + segments.Add(request); + Interlocked.Decrement(ref _offset); + } + + // send async + if (segments.Count > 0) + _segmentReporter.ReportAsync(segments, token); + + Interlocked.Exchange(ref _offset, _segmentQueue.Count); + + return Task.CompletedTask; + } + + public void Close() + { + _cancellation.Cancel(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Core/Transport/SegmentContextMapper.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Transport/SegmentContextMapper.cs new file mode 100644 index 000000000..8a5d4e539 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Core/Transport/SegmentContextMapper.cs @@ -0,0 +1,95 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Core.CPlatform.Diagnostics; +using System.Collections.Generic; + +namespace Surging.Apm.Skywalking.Abstractions.Common.Transport +{ + public class SegmentContextMapper : ISegmentContextMapper + { + public SegmentRequest Map(SegmentContext segmentContext) + { + var segmentRequest = new SegmentRequest + { + UniqueIds = new[] + { + MapUniqueId(segmentContext.TraceId) + } + }; + var segmentObjectRequest = new SegmentObjectRequest + { + SegmentId = MapUniqueId(segmentContext.SegmentId), + ServiceId = segmentContext.ServiceId, + ServiceInstanceId = segmentContext.ServiceInstanceId + }; + segmentRequest.Segment = segmentObjectRequest; + var span = new SpanRequest + { + SpanId = segmentContext.Span.SpanId, + ParentSpanId = segmentContext.Span.ParentSpanId, + OperationName = segmentContext.Span.OperationName, + StartTime = segmentContext.Span.StartTime, + EndTime = segmentContext.Span.EndTime, + SpanType = (int) segmentContext.Span.SpanType, + SpanLayer = (int) segmentContext.Span.SpanLayer, + IsError = segmentContext.Span.IsError, + Peer = segmentContext.Span.Peer, + Component = segmentContext.Span.Component + }; + foreach (var reference in segmentContext.References) + span.References.Add(new SegmentReferenceRequest + { + ParentSegmentId = MapUniqueId(reference.ParentSegmentId), + ParentServiceInstanceId = reference.ParentServiceInstanceId, + ParentSpanId = reference.ParentSpanId, + ParentEndpointName = reference.ParentEndpoint, + EntryServiceInstanceId = reference.EntryServiceInstanceId, + EntryEndpointName = reference.EntryEndpoint, + NetworkAddress = reference.NetworkAddress, + RefType = (int) reference.Reference + }); + + foreach (var tag in segmentContext.Span.Tags) + span.Tags.Add(new KeyValuePair(tag.Key, tag.Value)); + + foreach (var log in segmentContext.Span.Logs) + { + var logData = new LogDataRequest {Timestamp = log.Timestamp}; + foreach (var data in log.Data) + logData.Data.Add(new KeyValuePair(data.Key, data.Value)); + span.Logs.Add(logData); + } + + segmentObjectRequest.Spans.Add(span); + return segmentRequest; + } + + private static UniqueIdRequest MapUniqueId(UniqueId uniqueId) + { + return new UniqueIdRequest + { + Part1 = uniqueId.Part1, + Part2 = uniqueId.Part2, + Part3 = uniqueId.Part3 + }; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/SkywalkingModule.cs b/src/Surging.Apm/Surging.Apm.Skywalking/SkywalkingModule.cs new file mode 100644 index 000000000..b2e8548f3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/SkywalkingModule.cs @@ -0,0 +1,93 @@ +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Tracing; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Core.Sampling; +using Surging.Apm.Skywalking.Transport.Grpc; +using Surging.Apm.Skywalking.Transport.Grpc.V6; +using Surging.Core.CPlatform.Module; +using Autofac; +using Surging.Apm.Skywalking.Abstractions.Common.Tracing; +using Surging.Apm.Skywalking.Core.Tracing; +using Surging.Apm.Skywalking.Abstractions.Common.Transport; +using Surging.Apm.Skywalking.Core; +using Surging.Apm.Skywalking.Core.Service; +using Surging.Apm.Skywalking.Core.Diagnostics; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Configuration; +using Surging.Apm.Skywalking.Core.Common; +using System.Collections.Generic; +using System; +using Surging.Apm.Skywalking.Transport.Grpc.V5; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Apm.Skywalking +{ + public class SkywalkingModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + context.ServiceProvoider.GetInstances().StartAsync(); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.Register(p => RuntimeEnvironment.Instance).SingleInstance(); + builder.RegisterType().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + AddTracing(builder).AddSampling(builder).AddGrpcTransport(builder); + } + + private SkywalkingModule AddTracing(ContainerBuilderWrapper builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + return this; + } + + private SkywalkingModule AddSampling(ContainerBuilderWrapper builder) + { + builder.RegisterType().SingleInstance(); + builder.Register(p => p.Resolve()).SingleInstance(); + builder.Register(p => p.Resolve()).SingleInstance(); + builder.RegisterType().As().SingleInstance(); + return this; + } + + private SkywalkingModule AddGrpcTransport(ContainerBuilderWrapper builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + return this; + } + } +} diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Surging.Apm.Skywalking.csproj b/src/Surging.Apm/Surging.Apm.Skywalking/Surging.Apm.Skywalking.csproj new file mode 100644 index 000000000..bde2133dd --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Surging.Apm.Skywalking.csproj @@ -0,0 +1,27 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + + C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.hosting.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Abstractions.dll + + + + diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/AsyncLock.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/AsyncLock.cs new file mode 100644 index 000000000..0ac90845f --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/AsyncLock.cs @@ -0,0 +1,69 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Transport.Grpc.Common +{ + internal class AsyncLock + { + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1); + private readonly Release _release; + private readonly Task _releaseTask; + + public AsyncLock() + { + _release = new Release(this); + _releaseTask = Task.FromResult(_release); + } + + public Task LockAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var wait = _semaphore.WaitAsync(cancellationToken); + + return wait.IsCompleted + ? _releaseTask + : wait.ContinueWith( + (_, state) => ((AsyncLock) state)._release, + this, CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + + public Release Lock() + { + _semaphore.Wait(); + + return _release; + } + + public struct Release : IDisposable + { + private readonly AsyncLock _toRelease; + + internal Release(AsyncLock toRelease) + { + _toRelease = toRelease; + } + + public void Dispose() + => _toRelease._semaphore.Release(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/Call.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/Call.cs new file mode 100644 index 000000000..a0f08462b --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/Call.cs @@ -0,0 +1,63 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Transport.Grpc.Common +{ + internal class Call + { + private readonly ILogger _logger; + private readonly ConnectionManager _connectionManager; + + public Call(ILogger logger, ConnectionManager connectionManager) + { + _logger = logger; + _connectionManager = connectionManager; + } + + public async Task Execute(Func task, Func errMessage) + { + try + { + await task(); + } + catch (Exception ex) + { + _logger.LogError(errMessage(), ex); + _connectionManager.Failure(ex); + } + } + + public async Task Execute(Func> task, Func errCallback, Func errMessage) + { + try + { + return await task(); + } + catch (Exception ex) + { + _logger.LogError(errMessage(), ex); + _connectionManager.Failure(ex); + return errCallback(); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/ExceptionHelpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/ExceptionHelpers.cs new file mode 100644 index 000000000..e7d6bcf89 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/ExceptionHelpers.cs @@ -0,0 +1,32 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Apm.Skywalking.Transport.Grpc.Common +{ + internal static class ExceptionHelpers + { + public static readonly string RegisterApplicationError = "Register application fail."; + public static readonly string RegisterApplicationInstanceError = "Register application instance fail."; + public static readonly string HeartbeatError = "Heartbeat fail."; + public static readonly string CollectError = "Send trace segment fail."; + + public static readonly string RegisterServiceError = "Register service fail."; + public static readonly string RegisterServiceInstanceError = "Register service instance fail."; + public static readonly string PingError = "Ping server fail."; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/SegmentV5Helpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/SegmentV5Helpers.cs new file mode 100644 index 000000000..9004b5cf3 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/SegmentV5Helpers.cs @@ -0,0 +1,132 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Linq; +using Google.Protobuf; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Transport.Grpc.Common +{ + internal static class SegmentV5Helpers + { + public static UpstreamSegment Map(SegmentRequest request) + { + var upstreamSegment = new UpstreamSegment(); + + upstreamSegment.GlobalTraceIds.AddRange(request.UniqueIds.Select(MapToUniqueId).ToArray()); + + var traceSegment = new TraceSegmentObject + { + TraceSegmentId = MapToUniqueId(request.Segment.SegmentId), + ApplicationId = request.Segment.ServiceId, + ApplicationInstanceId = request.Segment.ServiceInstanceId, + IsSizeLimited = false + }; + + traceSegment.Spans.Add(request.Segment.Spans.Select(MapToSpan).ToArray()); + + upstreamSegment.Segment = traceSegment.ToByteString(); + return upstreamSegment; + } + + private static UniqueId MapToUniqueId(UniqueIdRequest uniqueIdRequest) + { + var uniqueId = new UniqueId(); + uniqueId.IdParts.Add(uniqueIdRequest.Part1); + uniqueId.IdParts.Add(uniqueIdRequest.Part2); + uniqueId.IdParts.Add(uniqueIdRequest.Part3); + return uniqueId; + } + + private static SpanObject MapToSpan(SpanRequest request) + { + var spanObject = new SpanObject + { + SpanId = request.SpanId, + ParentSpanId = request.ParentSpanId, + StartTime = request.StartTime, + EndTime = request.EndTime, + SpanType = (SpanType) request.SpanType, + SpanLayer = (SpanLayer) request.SpanLayer, + IsError = request.IsError + }; + + ReadStringOrIntValue(spanObject, request.Component, ComponentReader, ComponentIdReader); + ReadStringOrIntValue(spanObject, request.OperationName, OperationNameReader, OperationNameIdReader); + ReadStringOrIntValue(spanObject, request.Peer, PeerReader, PeerIdReader); + + spanObject.Tags.Add(request.Tags.Select(x => new KeyWithStringValue {Key = x.Key, Value = x.Value})); + spanObject.Refs.AddRange(request.References.Select(MapToSegmentReference).ToArray()); + spanObject.Logs.AddRange(request.Logs.Select(MapToLogMessage).ToArray()); + + return spanObject; + } + + private static TraceSegmentReference MapToSegmentReference(SegmentReferenceRequest referenceRequest) + { + var reference = new TraceSegmentReference + { + ParentApplicationInstanceId = referenceRequest.ParentServiceInstanceId, + EntryApplicationInstanceId = referenceRequest.EntryServiceInstanceId, + ParentSpanId = referenceRequest.ParentSpanId, + RefType = (RefType) referenceRequest.RefType, + ParentTraceSegmentId = MapToUniqueId(referenceRequest.ParentSegmentId) + }; + + ReadStringOrIntValue(reference, referenceRequest.NetworkAddress, NetworkAddressReader, NetworkAddressIdReader); + ReadStringOrIntValue(reference, referenceRequest.EntryEndpointName, EntryServiceReader, EntryServiceIdReader); + ReadStringOrIntValue(reference, referenceRequest.ParentEndpointName, ParentServiceReader, ParentServiceIdReader); + + return reference; + } + + private static LogMessage MapToLogMessage(LogDataRequest request) + { + var logMessage = new LogMessage {Time = request.Timestamp}; + logMessage.Data.AddRange(request.Data.Select(x => new KeyWithStringValue {Key = x.Key, Value = x.Value}).ToArray()); + return logMessage; + } + + private static void ReadStringOrIntValue(T instance, Surging.Core.CPlatform.Diagnostics.StringOrIntValue stringOrIntValue, Action stringValueReader, Action intValueReader) + { + if (stringOrIntValue.HasStringValue) + { + stringValueReader.Invoke(instance, stringOrIntValue.GetStringValue()); + } + else if (stringOrIntValue.HasIntValue) + { + intValueReader.Invoke(instance, stringOrIntValue.GetIntValue()); + } + } + + private static readonly Action ComponentReader = (s, val) => s.Component = val; + private static readonly Action ComponentIdReader = (s, val) => s.ComponentId = val; + private static readonly Action OperationNameReader = (s, val) => s.OperationName = val; + private static readonly Action OperationNameIdReader = (s, val) => s.OperationNameId = val; + private static readonly Action PeerReader = (s, val) => s.Peer = val; + private static readonly Action PeerIdReader = (s, val) => s.PeerId = val; + private static readonly Action NetworkAddressReader = (s, val) => s.NetworkAddress = val; + private static readonly Action NetworkAddressIdReader = (s, val) => s.NetworkAddressId = val; + private static readonly Action EntryServiceReader = (s, val) => s.EntryServiceName = val; + private static readonly Action EntryServiceIdReader = (s, val) => s.EntryServiceId = val; + private static readonly Action ParentServiceReader = (s, val) => s.ParentServiceName = val; + private static readonly Action ParentServiceIdReader = (s, val) => s.ParentServiceId = val; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/SegmentV6Helpers.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/SegmentV6Helpers.cs new file mode 100644 index 000000000..8b4873048 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/Common/SegmentV6Helpers.cs @@ -0,0 +1,150 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Linq; +using Google.Protobuf; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Transport.Grpc.Common +{ + internal static class SegmentV6Helpers + { + public static UpstreamSegment Map(SegmentRequest request) + { + var upstreamSegment = new UpstreamSegment(); + + upstreamSegment.GlobalTraceIds.AddRange(request.UniqueIds.Select(MapToUniqueId).ToArray()); + + var traceSegment = new SegmentObject + { + TraceSegmentId = MapToUniqueId(request.Segment.SegmentId), + ServiceId = request.Segment.ServiceId, + ServiceInstanceId = request.Segment.ServiceInstanceId, + IsSizeLimited = false + }; + + traceSegment.Spans.Add(request.Segment.Spans.Select(MapToSpan).ToArray()); + + upstreamSegment.Segment = traceSegment.ToByteString(); + return upstreamSegment; + } + + private static UniqueId MapToUniqueId(UniqueIdRequest uniqueIdRequest) + { + var uniqueId = new UniqueId(); + uniqueId.IdParts.Add(uniqueIdRequest.Part1); + uniqueId.IdParts.Add(uniqueIdRequest.Part2); + uniqueId.IdParts.Add(uniqueIdRequest.Part3); + return uniqueId; + } + + private static SpanObjectV2 MapToSpan(SpanRequest request) + { + var spanObject = new SpanObjectV2 + { + SpanId = request.SpanId, + ParentSpanId = request.ParentSpanId, + StartTime = request.StartTime, + EndTime = request.EndTime, + SpanType = (SpanType) request.SpanType, + SpanLayer = (SpanLayer) request.SpanLayer, + IsError = request.IsError + }; + + ReadStringOrIntValue(spanObject, request.Component, ComponentReader, ComponentIdReader); + ReadStringOrIntValue(spanObject, request.OperationName, OperationNameReader, OperationNameIdReader); + ReadStringOrIntValue(spanObject, request.Peer, PeerReader, PeerIdReader); + + spanObject.Tags.Add(request.Tags.Select(x => new KeyStringValuePair {Key = x.Key, Value = x.Value})); + spanObject.Refs.AddRange(request.References.Select(MapToSegmentReference).ToArray()); + spanObject.Logs.AddRange(request.Logs.Select(MapToLogMessage).ToArray()); + + return spanObject; + } + + private static SegmentReference MapToSegmentReference(SegmentReferenceRequest referenceRequest) + { + var reference = new SegmentReference + { + ParentServiceInstanceId = referenceRequest.ParentServiceInstanceId, + EntryServiceInstanceId = referenceRequest.EntryServiceInstanceId, + ParentSpanId = referenceRequest.ParentSpanId, + RefType = (RefType) referenceRequest.RefType, + ParentTraceSegmentId = MapToUniqueId(referenceRequest.ParentSegmentId) + }; + + ReadStringOrIntValue(reference, referenceRequest.NetworkAddress, NetworkAddressReader, + NetworkAddressIdReader); + ReadStringOrIntValue(reference, referenceRequest.EntryEndpointName, EntryEndpointReader, + EntryEndpointIdReader); + ReadStringOrIntValue(reference, referenceRequest.ParentEndpointName, ParentEndpointReader, + ParentEndpointIdReader); + + return reference; + } + + private static Log MapToLogMessage(LogDataRequest request) + { + var logMessage = new Log {Time = request.Timestamp}; + logMessage.Data.AddRange(request.Data.Select(x => new KeyStringValuePair {Key = x.Key, Value = x.Value}) + .ToArray()); + return logMessage; + } + + private static void ReadStringOrIntValue(T instance, Surging.Core.CPlatform.Diagnostics.StringOrIntValue stringOrIntValue, + Action stringValueReader, Action intValueReader) + { + if (stringOrIntValue.HasStringValue) + { + stringValueReader.Invoke(instance, stringOrIntValue.GetStringValue()); + } + else if (stringOrIntValue.HasIntValue) + { + intValueReader.Invoke(instance, stringOrIntValue.GetIntValue()); + } + } + + private static readonly Action ComponentReader = (s, val) => s.Component = val; + private static readonly Action ComponentIdReader = (s, val) => s.ComponentId = val; + private static readonly Action OperationNameReader = (s, val) => s.OperationName = val; + private static readonly Action OperationNameIdReader = (s, val) => s.OperationNameId = val; + private static readonly Action PeerReader = (s, val) => s.Peer = val; + private static readonly Action PeerIdReader = (s, val) => s.PeerId = val; + + private static readonly Action NetworkAddressReader = + (s, val) => s.NetworkAddress = val; + + private static readonly Action NetworkAddressIdReader = + (s, val) => s.NetworkAddressId = val; + + private static readonly Action + EntryEndpointReader = (s, val) => s.EntryEndpoint = val; + + private static readonly Action EntryEndpointIdReader = + (s, val) => s.EntryEndpointId = val; + + private static readonly Action ParentEndpointReader = + (s, val) => s.ParentEndpoint = val; + + private static readonly Action ParentEndpointIdReader = + (s, val) => s.ParentEndpointId = val; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/ConnectionManager.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/ConnectionManager.cs new file mode 100644 index 000000000..45879e5ab --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/ConnectionManager.cs @@ -0,0 +1,148 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Linq; +using System.Threading.Tasks; +using Grpc.Core; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Transport.Grpc.Common; + +namespace Surging.Apm.Skywalking.Transport.Grpc +{ + public class ConnectionManager + { + private readonly Random _random = new Random(); + private readonly AsyncLock _lock = new AsyncLock(); + + private readonly ILogger _logger; + private readonly GrpcConfig _config; + + private volatile Channel _channel; + private volatile ConnectionState _state; + private volatile string _server; + + public bool Ready => _channel != null && _state == ConnectionState.Connected && _channel.State == ChannelState.Ready; + + public ConnectionManager(ILoggerFactory loggerFactory, IConfigAccessor configAccessor) + { + _logger = loggerFactory.CreateLogger(typeof(ConnectionManager)); + _config = configAccessor.Get(); + } + + public async Task ConnectAsync() + { + using (await _lock.LockAsync()) + { + if (Ready) + { + return; + } + + if (_channel != null) + { + await ShutdownAsync(); + } + + EnsureServerAddress(); + + _channel = new Channel(_server, ChannelCredentials.Insecure); + + try + { + await _channel.ConnectAsync(_config.GetConnectTimeout()); + _state = ConnectionState.Connected; + _logger.LogInformation($"Connected server[{_channel.Target}]."); + } + catch (TaskCanceledException ex) + { + _state = ConnectionState.Failure; + _logger.LogError($"Connect server timeout.", ex); + } + catch (Exception ex) + { + _state = ConnectionState.Failure; + _logger.LogError($"Connect server fail.", ex); + } + } + } + + public async Task ShutdownAsync() + { + try + { + await _channel?.ShutdownAsync(); + _logger.LogInformation($"Shutdown connection[{_channel.Target}]."); + } + catch (Exception e) + { + _logger.LogError($"Shutdown connection fail.", e); + } + finally + { + _state = ConnectionState.Failure; + } + } + + public void Failure(Exception exception) + { + var currentState = _state; + + if (ConnectionState.Connected == currentState) + { + _logger.LogWarning($"Connection state changed. {_state} -> {_channel.State} . {exception.Message}"); + } + + _state = ConnectionState.Failure; + } + + public Channel GetConnection() + { + if (Ready) return _channel; + _logger.LogDebug("Not found available gRPC connection."); + return null; + } + + private void EnsureServerAddress() + { + var servers = _config.Servers.Split(',').ToArray(); + if (servers.Length == 1) + { + _server = servers[0]; + return; + } + + if (_server != null) + { + servers = servers.Where(x => x != _server).ToArray(); + } + + var index = _random.Next() % servers.Length; + _server = servers[index]; + } + } + + public enum ConnectionState + { + Idle, + Connecting, + Connected, + Failure + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/GrpcConfig.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/GrpcConfig.cs new file mode 100644 index 000000000..b1c34c3d2 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/GrpcConfig.cs @@ -0,0 +1,64 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using Grpc.Core; +using Surging.Apm.Skywalking.Abstractions.Config; + +namespace Surging.Apm.Skywalking.Transport.Grpc +{ + [Config("SkyWalking", "Transport", "gRPC")] + public class GrpcConfig + { + public string Servers { get; set; } + + public int ConnectTimeout { get; set; } + + public int Timeout { get; set; } + + public int ReportTimeout { get; set; } + + public string Authentication { get; set; } + } + + public static class GrpcConfigExtensions + { + public static DateTime GetTimeout(this GrpcConfig config) + { + return DateTime.UtcNow.AddMilliseconds(config.Timeout); + } + + public static DateTime GetConnectTimeout(this GrpcConfig config) + { + return DateTime.UtcNow.AddMilliseconds(config.ConnectTimeout); + } + + public static DateTime GetReportTimeout(this GrpcConfig config) + { + return DateTime.UtcNow.AddMilliseconds(config.ReportTimeout); + } + public static Metadata GetMeta(this GrpcConfig config) + { + if (string.IsNullOrEmpty(config.Authentication)) + { + return null; + } + return new Metadata { new Metadata.Entry("Authentication", config.Authentication) }; + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/SegmentReporter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/SegmentReporter.cs new file mode 100644 index 000000000..8b1366602 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/SegmentReporter.cs @@ -0,0 +1,53 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using SegmentReporterV5 = Surging.Apm.Skywalking.Transport.Grpc.V5.SegmentReporter; +using SegmentReporterV6 = Surging.Apm.Skywalking.Transport.Grpc.V6.SegmentReporter; + +namespace Surging.Apm.Skywalking.Transport.Grpc +{ + public class SegmentReporter : ISegmentReporter + { + private readonly ISegmentReporter _segmentReporterV5; + private readonly ISegmentReporter _segmentReporterV6; + private readonly TransportConfig _transportConfig; + + public SegmentReporter(ConnectionManager connectionManager, IConfigAccessor configAccessor, + ILoggerFactory loggerFactory) + { + _transportConfig = configAccessor.Get(); + _segmentReporterV5 = new V5.SegmentReporter(connectionManager, configAccessor, loggerFactory); + _segmentReporterV6 = new V6.SegmentReporter(connectionManager, configAccessor, loggerFactory); + } + + public async Task ReportAsync(IReadOnlyCollection segmentRequests, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (_transportConfig.ProtocolVersion == ProtocolVersions.V6) + await _segmentReporterV6.ReportAsync(segmentRequests, cancellationToken); + if (_transportConfig.ProtocolVersion == ProtocolVersions.V5) + await _segmentReporterV5.ReportAsync(segmentRequests, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V5/SegmentReporter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V5/SegmentReporter.cs new file mode 100644 index 000000000..65c796e20 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V5/SegmentReporter.cs @@ -0,0 +1,79 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Transport.Grpc.Common; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V5 +{ + internal class SegmentReporter : ISegmentReporter + { + private readonly ConnectionManager _connectionManager; + private readonly ILogger _logger; + private readonly GrpcConfig _config; + + public SegmentReporter(ConnectionManager connectionManager, IConfigAccessor configAccessor, + ILoggerFactory loggerFactory) + { + _connectionManager = connectionManager; + _config = configAccessor.Get(); + _logger = loggerFactory.CreateLogger(typeof(SegmentReporter)); + } + + public async Task ReportAsync(IReadOnlyCollection segmentRequests, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return; + } + + var connection = _connectionManager.GetConnection(); + + try + { + var stopwatch = Stopwatch.StartNew(); + var client = new TraceSegmentService.TraceSegmentServiceClient(connection); + using (var asyncClientStreamingCall = + client.collect(_config.GetMeta(), _config.GetReportTimeout(), cancellationToken)) + { + foreach (var segment in segmentRequests) + await asyncClientStreamingCall.RequestStream.WriteAsync(SegmentV5Helpers.Map(segment)); + await asyncClientStreamingCall.RequestStream.CompleteAsync(); + await asyncClientStreamingCall.ResponseAsync; + } + + stopwatch.Stop(); + _logger.LogInformation($"Report {segmentRequests.Count} trace segment. cost: {stopwatch.Elapsed}s"); + } + catch (Exception ex) + { + _logger.LogError("Report trace segment fail.", ex); + _connectionManager.Failure(ex); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V5/SkyApmClientV5.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V5/SkyApmClientV5.cs new file mode 100644 index 000000000..232fe9346 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V5/SkyApmClientV5.cs @@ -0,0 +1,129 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Transport.Grpc.Common; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V5 +{ + public class SkyApmClientV5 : ISkyApmClientV5 + { + private readonly ConnectionManager _connectionManager; + private readonly ILogger _logger; + private readonly GrpcConfig _config; + + public SkyApmClientV5(ConnectionManager connectionManager, IConfigAccessor configAccessor, + ILoggerFactory loggerFactory) + { + _connectionManager = connectionManager; + _config = configAccessor.Get(); + _logger = loggerFactory.CreateLogger(typeof(SkyApmClientV5)); + } + + public async Task RegisterApplicationAsync(string applicationCode, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return NullableValue.Null; + } + + var connection = _connectionManager.GetConnection(); + + var client = new ApplicationRegisterService.ApplicationRegisterServiceClient(connection); + + return await new Call(_logger, _connectionManager).Execute(async () => + { + var applicationMapping = await client.applicationCodeRegisterAsync( + new Application {ApplicationCode = applicationCode}, + _config.GetMeta(), _config.GetTimeout(), cancellationToken); + + return new NullableValue(applicationMapping?.Application?.Value ?? 0); + }, + () => NullableValue.Null, + () => ExceptionHelpers.RegisterApplicationError); + } + + public async Task RegisterApplicationInstanceAsync(int applicationId, Guid agentUUID, + long registerTime, AgentOsInfoRequest osInfoRequest, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return NullableValue.Null; + } + + var connection = _connectionManager.GetConnection(); + + var client = new InstanceDiscoveryService.InstanceDiscoveryServiceClient(connection); + + var applicationInstance = new ApplicationInstance + { + ApplicationId = applicationId, + AgentUUID = agentUUID.ToString("N"), + RegisterTime = registerTime, + Osinfo = new OSInfo + { + OsName = osInfoRequest.OsName, + Hostname = osInfoRequest.HostName, + ProcessNo = osInfoRequest.ProcessNo + } + }; + + applicationInstance.Osinfo.Ipv4S.AddRange(osInfoRequest.IpAddress); + + return await new Call(_logger, _connectionManager).Execute(async () => + { + var applicationInstanceMapping = await client.registerInstanceAsync(applicationInstance, null, + _config.GetTimeout(), cancellationToken); + return new NullableValue(applicationInstanceMapping?.ApplicationInstanceId ?? 0); + }, + () => NullableValue.Null, + () => ExceptionHelpers.RegisterApplicationInstanceError); + } + + public async Task HeartbeatAsync(int applicationInstance, long heartbeatTime, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return; + } + + var connection = _connectionManager.GetConnection(); + + var client = new InstanceDiscoveryService.InstanceDiscoveryServiceClient(connection); + + var heartbeat = new ApplicationInstanceHeartbeat + { + ApplicationInstanceId = applicationInstance, + HeartbeatTime = heartbeatTime + }; + await new Call(_logger, _connectionManager).Execute( + async () => await client.heartbeatAsync(heartbeat, _config.GetMeta(), _config.GetTimeout(), cancellationToken), + () => ExceptionHelpers.HeartbeatError); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/CLRStatsReporter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/CLRStatsReporter.cs new file mode 100644 index 000000000..07a02813f --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/CLRStatsReporter.cs @@ -0,0 +1,94 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V6 +{ + public class CLRStatsReporter : ICLRStatsReporter + { + private readonly ConnectionManager _connectionManager; + private readonly ILogger _logger; + private readonly GrpcConfig _config; + private readonly IRuntimeEnvironment _runtimeEnvironment; + + public CLRStatsReporter(ConnectionManager connectionManager, ILoggerFactory loggerFactory, + IConfigAccessor configAccessor, IRuntimeEnvironment runtimeEnvironment) + { + _connectionManager = connectionManager; + _logger = loggerFactory.CreateLogger(typeof(CLRStatsReporter)); + _config = configAccessor.Get(); + _runtimeEnvironment = runtimeEnvironment; + } + + public async Task ReportAsync(CLRStatsRequest statsRequest, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return; + } + + var connection = _connectionManager.GetConnection(); + + try + { + var request = new CLRMetricCollection + { + ServiceInstanceId = _runtimeEnvironment.ServiceInstanceId.Value + }; + var metric = new CLRMetric + { + Cpu = new CPU + { + UsagePercent = statsRequest.CPU.UsagePercent + }, + Gc = new ClrGC + { + Gen0CollectCount = statsRequest.GC.Gen0CollectCount, + Gen1CollectCount = statsRequest.GC.Gen1CollectCount, + Gen2CollectCount = statsRequest.GC.Gen2CollectCount, + HeapMemory = statsRequest.GC.HeapMemory + }, + Thread = new ClrThread + { + AvailableWorkerThreads = statsRequest.Thread.MaxWorkerThreads, + AvailableCompletionPortThreads = statsRequest.Thread.MaxCompletionPortThreads, + MaxWorkerThreads = statsRequest.Thread.MaxWorkerThreads, + MaxCompletionPortThreads = statsRequest.Thread.MaxCompletionPortThreads + }, + Time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + request.Metrics.Add(metric); + var client = new CLRMetricReportService.CLRMetricReportServiceClient(connection); + await client.collectAsync(request, _config.GetMeta(), _config.GetTimeout(), cancellationToken); + } + catch (Exception e) + { + _logger.LogWarning("Report CLR Stats error. " + e); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/ConnectService.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/ConnectService.cs new file mode 100644 index 000000000..36691659b --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/ConnectService.cs @@ -0,0 +1,51 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using Microsoft.Extensions.Logging; +using Surging.Apm.Skywalking.Abstractions; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V6 +{ + public class ConnectService: ExecutionService + { + private readonly ConnectionManager _connectionManager; + + public ConnectService(ConnectionManager connectionManager, + IRuntimeEnvironment runtimeEnvironment, + ILoggerFactory loggerFactory) : base(runtimeEnvironment, loggerFactory) + { + _connectionManager = connectionManager; + } + + protected override TimeSpan DueTime { get; } = TimeSpan.Zero; + protected override TimeSpan Period { get; } = TimeSpan.FromSeconds(15); + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + if (!_connectionManager.Ready) + { + await _connectionManager.ConnectAsync(); + } + } + + protected override bool CanExecute() => !_connectionManager.Ready; + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/PingCaller.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/PingCaller.cs new file mode 100644 index 000000000..19738be44 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/PingCaller.cs @@ -0,0 +1,65 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Transport.Grpc.Common; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V6 +{ + public class PingCaller : IPingCaller + { + private readonly ConnectionManager _connectionManager; + private readonly ILogger _logger; + private readonly GrpcConfig _config; + + public PingCaller(ConnectionManager connectionManager, ILoggerFactory loggerFactory, + IConfigAccessor configAccessor) + { + _connectionManager = connectionManager; + _config = configAccessor.Get(); + _logger = loggerFactory.CreateLogger(typeof(PingCaller)); + } + + public Task PingAsync(PingRequest request, CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return Task.CompletedTask; + } + + var connection = _connectionManager.GetConnection(); + return new Call(_logger, _connectionManager).Execute(async () => + { + var client = new ServiceInstancePing.ServiceInstancePingClient(connection); + await client.doPingAsync(new ServiceInstancePingPkg + { + ServiceInstanceId = request.ServiceInstanceId, + ServiceInstanceUUID = request.InstanceId, + Time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }, _config.GetMeta(), _config.GetTimeout(), cancellationToken); + }, + () => ExceptionHelpers.PingError); + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/SegmentReporter.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/SegmentReporter.cs new file mode 100644 index 000000000..21b5b44a7 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/SegmentReporter.cs @@ -0,0 +1,79 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Transport.Grpc.Common; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V6 +{ + internal class SegmentReporter : ISegmentReporter + { + private readonly ConnectionManager _connectionManager; + private readonly ILogger _logger; + private readonly GrpcConfig _config; + + public SegmentReporter(ConnectionManager connectionManager, IConfigAccessor configAccessor, + ILoggerFactory loggerFactory) + { + _connectionManager = connectionManager; + _config = configAccessor.Get(); + _logger = loggerFactory.CreateLogger(typeof(SegmentReporter)); + } + + public async Task ReportAsync(IReadOnlyCollection segmentRequests, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return; + } + + var connection = _connectionManager.GetConnection(); + + try + { + var stopwatch = Stopwatch.StartNew(); + var client = new TraceSegmentReportService.TraceSegmentReportServiceClient(connection); + using (var asyncClientStreamingCall = + client.collect(_config.GetMeta(), _config.GetReportTimeout(), cancellationToken)) + { + foreach (var segment in segmentRequests) + await asyncClientStreamingCall.RequestStream.WriteAsync(SegmentV6Helpers.Map(segment)); + await asyncClientStreamingCall.RequestStream.CompleteAsync(); + await asyncClientStreamingCall.ResponseAsync; + } + + stopwatch.Stop(); + _logger.LogInformation($"Report {segmentRequests.Count} trace segment. cost: {stopwatch.Elapsed}s"); + } + catch (Exception ex) + { + _logger.LogError("Report trace segment fail.", ex); + _connectionManager.Failure(ex); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/ServiceRegister.cs b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/ServiceRegister.cs new file mode 100644 index 000000000..a756b61b7 --- /dev/null +++ b/src/Surging.Apm/Surging.Apm.Skywalking/Transport/Grpc/V6/ServiceRegister.cs @@ -0,0 +1,123 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using SkyWalking.NetworkProtocol; +using Surging.Apm.Skywalking.Abstractions.Common; +using Surging.Apm.Skywalking.Abstractions.Config; +using Surging.Apm.Skywalking.Abstractions.Transport; +using Surging.Apm.Skywalking.Transport.Grpc.Common; + +namespace Surging.Apm.Skywalking.Transport.Grpc.V6 +{ + public class ServiceRegister : IServiceRegister + { + private const string OS_NAME = "os_name"; + private const string HOST_NAME = "host_name"; + private const string IPV4 = "ipv4"; + private const string PROCESS_NO = "process_no"; + private const string LANGUAGE = "language"; + + private readonly ConnectionManager _connectionManager; + private readonly ILogger _logger; + private readonly GrpcConfig _config; + + public ServiceRegister(ConnectionManager connectionManager, IConfigAccessor configAccessor, + ILoggerFactory loggerFactory) + { + _connectionManager = connectionManager; + _config = configAccessor.Get(); + _logger = loggerFactory.CreateLogger(typeof(ServiceRegister)); + } + + public async Task RegisterServiceAsync(ServiceRequest serviceRequest, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return NullableValue.Null; + } + + var connection = _connectionManager.GetConnection(); + return await new Call(_logger, _connectionManager).Execute(async () => + { + var client = new Register.RegisterClient(connection); + var services = new Services(); + services.Services_.Add(new Service + { + ServiceName = serviceRequest.ServiceName + }); + var mapping = await client.doServiceRegisterAsync(services, + _config.GetMeta(), _config.GetTimeout(), cancellationToken); + foreach (var service in mapping.Services) + if (service.Key == serviceRequest.ServiceName) + return new NullableValue(service.Value); + return NullableValue.Null; + }, + () => NullableValue.Null, + () => ExceptionHelpers.RegisterServiceError); + } + + public async Task RegisterServiceInstanceAsync(ServiceInstanceRequest serviceInstanceRequest, + CancellationToken cancellationToken = default(CancellationToken)) + { + if (!_connectionManager.Ready) + { + return NullableValue.Null; + } + + var connection = _connectionManager.GetConnection(); + return await new Call(_logger, _connectionManager).Execute(async () => + { + var client = new Register.RegisterClient(connection); + var instance = new ServiceInstance + { + ServiceId = serviceInstanceRequest.ServiceId, + InstanceUUID = serviceInstanceRequest.InstanceUUID, + Time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + + instance.Properties.Add(new KeyStringValuePair + {Key = OS_NAME, Value = serviceInstanceRequest.Properties.OsName}); + instance.Properties.Add(new KeyStringValuePair + {Key = HOST_NAME, Value = serviceInstanceRequest.Properties.HostName}); + instance.Properties.Add(new KeyStringValuePair + {Key = PROCESS_NO, Value = serviceInstanceRequest.Properties.ProcessNo.ToString()}); + instance.Properties.Add(new KeyStringValuePair + {Key = LANGUAGE, Value = serviceInstanceRequest.Properties.Language}); + foreach (var ip in serviceInstanceRequest.Properties.IpAddress) + instance.Properties.Add(new KeyStringValuePair + {Key = IPV4, Value = ip}); + + var serviceInstances = new ServiceInstances(); + serviceInstances.Instances.Add(instance); + var mapping = await client.doServiceInstanceRegisterAsync(serviceInstances, + _config.GetMeta(), _config.GetTimeout(), cancellationToken); + foreach (var serviceInstance in mapping.ServiceInstances) + if (serviceInstance.Key == serviceInstanceRequest.InstanceUUID) + return new NullableValue(serviceInstance.Value); + return NullableValue.Null; + }, + () => NullableValue.Null, + () => ExceptionHelpers.RegisterServiceInstanceError); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Abp/AbpModule.cs b/src/Surging.Core/Surging.Core.Abp/AbpModule.cs new file mode 100644 index 000000000..ebf557889 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Abp/AbpModule.cs @@ -0,0 +1,139 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyModel; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.KestrelHttpServer; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using Volo.Abp.Configuration; +using VoloAbpModule = Volo.Abp.Modularity; +using Microsoft.Extensions.Configuration; +using Volo.Abp.DependencyInjection; +using VoloAbp= Volo.Abp; + + +namespace Surging.Core.Abp +{ + [ExposeServices] + public class AbpModule : KestrelHttpModule + { + private ILogger _logger; + private List _providers=new List(); + public override void Initialize(AppModuleContext context) + { + _logger = context.ServiceProvoider.GetInstances>(); + } + + public override void Initialize(ApplicationInitializationContext context) + { + _providers.ForEach(p => p.Initialize(context.Builder.ApplicationServices)); + } + + public override void Dispose() + { + base.Dispose(); + _providers = null; + } + + public override void RegisterBuilder(ConfigurationContext context) + { + context.Services.AddSingleton(new DefaultConfigurationAccessor(context.Configuration)); + var referenceAssemblies = GetAssemblies(context.VirtualPaths).Concat(GetAssemblies()); + foreach (var moduleAssembly in referenceAssemblies) + { + GetAbstractModules(moduleAssembly).ForEach(p => + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"已初始化加载Abp模块,类型:{p.GetType().FullName}模块名:{p.GetType().Name}。"); + var application = VoloAbp.AbpApplicationFactory.Create(p.GetType(), context.Services); + _providers.Add(application); + }); + } + } + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + + } + + private static List GetAbstractModules(Assembly assembly) + { + var abstractModules = new List(); + Type[] abpModule = assembly.GetTypes().Where( + t => t.IsSubclassOf(typeof(VoloAbpModule.AbpModule))).ToArray(); + foreach (var moduleType in abpModule) + { + var abstractModule = (VoloAbpModule.AbpModule)Activator.CreateInstance(moduleType); + abstractModules.Add(abstractModule); + } + return abstractModules; + } + + private List GetAssemblies(params string[] virtualPaths) + { + var referenceAssemblies = new List(); + if (virtualPaths.Any()) + { + referenceAssemblies = GetReferenceAssembly(virtualPaths); + } + else + { + string[] assemblyNames = DependencyContext + .Default.GetDefaultAssemblyNames().Select(p => p.Name).ToArray(); + assemblyNames = GetFilterAssemblies(assemblyNames); + foreach (var name in assemblyNames) + referenceAssemblies.Add(Assembly.Load(name)); + } + return referenceAssemblies; + } + + private List GetReferenceAssembly(params string[] virtualPaths) + { + var refAssemblies = new List(); + var rootPath = AppContext.BaseDirectory; + var existsPath = virtualPaths.Any(); + if (existsPath && !string.IsNullOrEmpty(AppConfig.ServerOptions.RootPath)) + rootPath = AppConfig.ServerOptions.RootPath; + var paths = virtualPaths.Select(m => Path.Combine(rootPath, m)).ToList(); + if (!existsPath) paths.Add(rootPath); + paths.ForEach(path => + { + var assemblyFiles = GetAllAssemblyFiles(path); + + foreach (var referencedAssemblyFile in assemblyFiles) + { + var referencedAssembly = Assembly.LoadFrom(referencedAssemblyFile); + refAssemblies.Add(referencedAssembly); + } + }); + return refAssemblies; + } + + private List GetAllAssemblyFiles(string parentDir) + { + var pattern = string.Format("^Volo.Abp.\\w*"); + Regex relatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + return + Directory.GetFiles(parentDir, "*.dll").Select(Path.GetFullPath).Where( + a => relatedRegex.IsMatch(a)).ToList(); + } + + private string[] GetFilterAssemblies(string[] assemblyNames) + { + var pattern = string.Format("^Volo.Abp.\\w*"); + Regex relatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + return + assemblyNames.Where( + name => relatedRegex.IsMatch(name)).ToArray(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Abp/Surging.Core.Abp.csproj b/src/Surging.Core/Surging.Core.Abp/Surging.Core.Abp.csproj new file mode 100644 index 000000000..6040ec552 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Abp/Surging.Core.Abp.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/Aggregation/ServicePartProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/Aggregation/ServicePartProvider.cs index 9597f4c30..fbe1c4906 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/Aggregation/ServicePartProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/Aggregation/ServicePartProvider.cs @@ -10,6 +10,9 @@ namespace Surging.Core.ApiGateWay.Aggregation { + /// + /// 服务部件提供者 + /// public class ServicePartProvider : IServicePartProvider { private readonly IServiceProxyProvider _serviceProxyProvider; diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ApiGeteWayModule.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ApiGeteWayModule.cs new file mode 100644 index 000000000..027ca495b --- /dev/null +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ApiGeteWayModule.cs @@ -0,0 +1,45 @@ +using Autofac; +using Surging.Core.ApiGateWay.Aggregation; +using Surging.Core.ApiGateWay.OAuth; +using Surging.Core.ApiGateWay.ServiceDiscovery; +using Surging.Core.ApiGateWay.ServiceDiscovery.Implementation; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks.Implementation; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ApiGateWay +{ + public class ApiGeteWayModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + + builder.Register(provider => + { + var serviceProxyProvider = provider.Resolve(); + var serviceRouteProvider = provider.Resolve(); + var serviceProvider = provider.Resolve(); + return new AuthorizationServerProvider(serviceProxyProvider, serviceRouteProvider, serviceProvider); + }).As().SingleInstance(); + } + } + +} diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/AppConfig.cs b/src/Surging.Core/Surging.Core.ApiGateWay/AppConfig.cs index 92659c9f3..174963f6f 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/AppConfig.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/AppConfig.cs @@ -18,9 +18,11 @@ public static string AuthorizationServiceKey { get { + if (Configuration == null) + return _authorizationServiceKey; return Configuration["AuthorizationServiceKey"] ?? _authorizationServiceKey; } - internal set + set { _authorizationServiceKey = value; @@ -32,9 +34,11 @@ public static string AuthorizationRoutePath { get { + if (Configuration == null) + return _authorizationRoutePath; return Configuration["AuthorizationRoutePath"] ?? _authorizationRoutePath; } - internal set + set { _authorizationRoutePath = value; @@ -46,6 +50,8 @@ public static TimeSpan AccessTokenExpireTimeSpan { get { + if (Configuration == null) + return _accessTokenExpireTimeSpan; int tokenExpireTime; if (Configuration["AccessTokenExpireTimeSpan"] != null && int.TryParse(Configuration["AccessTokenExpireTimeSpan"], out tokenExpireTime)) { @@ -53,7 +59,7 @@ public static TimeSpan AccessTokenExpireTimeSpan } return _accessTokenExpireTimeSpan; } - internal set + set { _accessTokenExpireTimeSpan = value; } @@ -65,9 +71,11 @@ public static string TokenEndpointPath { get { + if (Configuration == null) + return _tokenEndpointPath; return Configuration["TokenEndpointPath"] ?? _tokenEndpointPath; } - internal set + set { _tokenEndpointPath = value; } @@ -104,7 +112,7 @@ public static AccessPolicy Policy { var result = new AccessPolicy(); var section = Configuration.GetSection("AccessPolicy"); - if (section != null) + if (section.Exists() ) result = section.Get(); return result; } @@ -116,8 +124,15 @@ public static string CacheMode { get { + if (Configuration == null) + return _cacheMode; + return Configuration["CacheMode"] ?? _cacheMode; } + set + { + _cacheMode = value; + } } } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ContainerBuilderExtensions.cs index a348b16d2..6f89401ef 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ContainerBuilderExtensions.cs @@ -16,12 +16,19 @@ namespace Surging.Core.ApiGateWay { public static class ContainerBuilderExtensions { + /// + /// 添加网关中间件 + /// + /// 服务构建者 + /// + /// 服务构建者 public static IServiceBuilder AddApiGateWay(this IServiceBuilder builder, ConfigInfo config=null) { var services = builder.Services; services.RegisterType().As().SingleInstance(); services.RegisterType().As().SingleInstance(); services.RegisterType().As().SingleInstance(); + services.RegisterType().As().SingleInstance(); services.RegisterType().As().SingleInstance(); services.RegisterType().As().SingleInstance(); services.RegisterType().As().SingleInstance(); @@ -36,7 +43,7 @@ public static IServiceBuilder AddApiGateWay(this IServiceBuilder builder, Config var serviceProxyProvider = provider.Resolve(); var serviceRouteProvider = provider.Resolve(); var serviceProvider = provider.Resolve(); - return new AuthorizationServerProvider(config, serviceProxyProvider, serviceRouteProvider, serviceProvider); + return new AuthorizationServerProvider(serviceProxyProvider, serviceRouteProvider, serviceProvider); }).As().SingleInstance(); return builder; } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/IAuthorizationServerProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/IAuthorizationServerProvider.cs index d61fe3523..bfadd300b 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/IAuthorizationServerProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/IAuthorizationServerProvider.cs @@ -11,6 +11,8 @@ public interface IAuthorizationServerProvider Task ValidateClientAuthentication(string token); + Task RefreshToken(string token); + string GetPayloadString(string token); } } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/AuthorizationServerProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/AuthorizationServerProvider.cs index c49a3a5c5..eb7bf3d71 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/AuthorizationServerProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/AuthorizationServerProvider.cs @@ -14,13 +14,16 @@ namespace Surging.Core.ApiGateWay.OAuth { + /// + /// 授权服务提供者 + /// public class AuthorizationServerProvider: IAuthorizationServerProvider { private readonly IServiceProxyProvider _serviceProxyProvider; private readonly IServiceRouteProvider _serviceRouteProvider; private readonly CPlatformContainer _serviceProvider; private readonly ICacheProvider _cacheProvider; - public AuthorizationServerProvider(ConfigInfo configInfo, IServiceProxyProvider serviceProxyProvider + public AuthorizationServerProvider(IServiceProxyProvider serviceProxyProvider ,IServiceRouteProvider serviceRouteProvider , CPlatformContainer serviceProvider) { @@ -70,6 +73,22 @@ public async Task ValidateClientAuthentication(string token) return isSuccess; } + public async Task RefreshToken(string token) + { + bool isSuccess = false; + var jwtToken = token.Split('.'); + if (jwtToken.Length == 3) + { + var value = await _cacheProvider.GetAsync(jwtToken[1]); + if (!string.IsNullOrEmpty(value)) + { + _cacheProvider.Add(jwtToken[1], value, AppConfig.AccessTokenExpireTimeSpan); + isSuccess = true; + } + } + return isSuccess; + } + private string ConverBase64String(string str) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(str)); diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/Configurations/ConfigInfo.cs b/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/Configurations/ConfigInfo.cs index eab2077ac..dc2a64073 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/Configurations/ConfigInfo.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/OAuth/Implementation/Configurations/ConfigInfo.cs @@ -18,7 +18,13 @@ public ConfigInfo(string authorizationRoutePath,string authorizationServiceKey, AccessTokenExpireTimeSpan = accessTokenExpireTimeSpan; } public string AuthorizationServiceKey { get; set; } + /// + /// 授权服务路由地址 + /// public string AuthorizationRoutePath { get; set; } + /// + /// token 有效期 + /// public TimeSpan AccessTokenExpireTimeSpan { get; set; } = TimeSpan.FromMinutes(30); }; } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/IServiceRegisterProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/IServiceRegisterProvider.cs new file mode 100644 index 000000000..417ff1ad0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/IServiceRegisterProvider.cs @@ -0,0 +1,14 @@ +using Surging.Core.ApiGateWay.ServiceDiscovery.Implementation; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.ApiGateWay.ServiceDiscovery +{ + public interface IServiceRegisterProvider + { + + Task> GetAddressAsync(string condition = null); + } +} diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/FaultTolerantProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/FaultTolerantProvider.cs index 88a590c7c..35bcc1a46 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/FaultTolerantProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/FaultTolerantProvider.cs @@ -3,27 +3,30 @@ using System.Text; using System.Threading.Tasks; using Surging.Core.CPlatform.Support; -using Surging.Core.System; using System.Linq; +using Surging.Core.CPlatform.Utilities; namespace Surging.Core.ApiGateWay.ServiceDiscovery.Implementation { - public class FaultTolerantProvider : ServiceBase, IFaultTolerantProvider + /// + /// 容错机制提供者 + /// + public class FaultTolerantProvider : IFaultTolerantProvider { public async Task> GetCommandDescriptor(params string[] serviceIds) { - return await GetService().GetServiceCommandsAsync(serviceIds); + return await ServiceLocator.GetService().GetServiceCommandsAsync(serviceIds); } public async Task> GetCommandDescriptorByAddress(string address) { - var services = await GetService().GetServiceDescriptorAsync(address); - return await GetService().GetServiceCommandsAsync(services.Select(p=>p.Id).ToArray()); + var services = await ServiceLocator.GetService().GetServiceDescriptorAsync(address); + return await ServiceLocator.GetService().GetServiceCommandsAsync(services.Select(p=>p.Id).ToArray()); } public async Task SetCommandDescriptorByAddress(ServiceCommandDescriptor model) { - await GetService().SetServiceCommandsAsync(new ServiceCommandDescriptor[] { model }); + await ServiceLocator.GetService().SetServiceCommandsAsync(new ServiceCommandDescriptor[] { model }); } } } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceCacheProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceCacheProvider.cs index 69169b123..32cd590b2 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceCacheProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceCacheProvider.cs @@ -5,11 +5,14 @@ using System.Threading.Tasks; using Surging.Core.CPlatform.Cache; using Surging.Core.CPlatform.Serialization; -using Surging.Core.System; +using Surging.Core.CPlatform.Utilities; namespace Surging.Core.ApiGateWay.ServiceDiscovery.Implementation { - public class ServiceCacheProvider : ServiceBase, IServiceCacheProvider + /// + /// 服务缓存提供者 + /// + public class ServiceCacheProvider : IServiceCacheProvider { private readonly ISerializer _serializer; public ServiceCacheProvider(ISerializer serializer) @@ -18,22 +21,22 @@ public ServiceCacheProvider(ISerializer serializer) } public async Task> GetServiceDescriptorAsync() { - return await GetService().GetCacheDescriptorAsync(); + return await ServiceLocator.GetService().GetCacheDescriptorAsync(); } public async Task> GetCacheEndpointAsync(string cacheId) { - return await GetService().GetCacheEndpointAsync(cacheId); + return await ServiceLocator.GetService().GetCacheEndpointAsync(cacheId); } public async Task GetCacheEndpointAsync(string cacheId, string endpoint) { - return await GetService().GetCacheEndpointAsync(cacheId, endpoint); + return await ServiceLocator.GetService().GetCacheEndpointAsync(cacheId, endpoint); } public async Task SetCacheEndpointByEndpoint(string cacheId, string endpoint, CacheEndpoint cacheEndpoint) { - var model = await GetService().GetAsync(cacheId); + var model = await ServiceLocator.GetService().GetAsync(cacheId); var cacheEndpoints = model.CacheEndpoint.Where(p => p.ToString() != cacheEndpoint.ToString()).ToList(); cacheEndpoints.Add(cacheEndpoint); @@ -48,13 +51,13 @@ public async Task SetCacheEndpointByEndpoint(string cacheId, string endpoint, Ca }) ?? Enumerable.Empty(), CacheDescriptor = cache.CacheDescriptor }); - await GetService().SetCachesAsync(descriptors); + await ServiceLocator.GetService().SetCachesAsync(descriptors); } public async Task DelCacheEndpointAsync(string cacheId, string endpoint) { - var model = await GetService().GetAsync(cacheId); + var model = await ServiceLocator.GetService().GetAsync(cacheId); var cacheEndpoints = model.CacheEndpoint.Where(p => p.ToString() != endpoint).ToList(); model.CacheEndpoint = cacheEndpoints; var caches = new ServiceCache[] { model }; @@ -67,7 +70,7 @@ public async Task DelCacheEndpointAsync(string cacheId, string endpoint) }) ?? Enumerable.Empty(), CacheDescriptor = cache.CacheDescriptor }); - await GetService().SetCachesAsync(descriptors); + await ServiceLocator.GetService().SetCachesAsync(descriptors); } } } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceDiscoveryProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceDiscoveryProvider.cs index cb1c5c03b..735d6aa89 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceDiscoveryProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceDiscoveryProvider.cs @@ -2,15 +2,18 @@ using System.Collections.Generic; using Surging.Core.CPlatform.Routing; using System.Threading.Tasks; -using Surging.Core.System; using Surging.Core.CPlatform.Runtime.Client.HealthChecks; using Surging.Core.CPlatform; using Surging.Core.CPlatform.Address; using System.Linq; +using Surging.Core.CPlatform.Utilities; namespace Surging.Core.ApiGateWay.ServiceDiscovery.Implementation { - public class ServiceDiscoveryProvider : ServiceBase, IServiceDiscoveryProvider + /// + /// 服务发现提供者 + /// + public class ServiceDiscoveryProvider : IServiceDiscoveryProvider { public ServiceDiscoveryProvider() { @@ -19,13 +22,13 @@ public ServiceDiscoveryProvider() public async Task> GetAddressAsync(string condition = null) { var result = new List(); - var addresses = await GetService().GetAddressAsync(condition); + var addresses = await ServiceLocator.GetService().GetAddressAsync(condition); foreach (var address in addresses) { result.Add(new ServiceAddressModel { Address = address, - IsHealth = await GetService().IsHealth(address) + IsHealth = await ServiceLocator.GetService().IsHealth(address) }); } return result; @@ -33,12 +36,12 @@ public async Task> GetAddressAsync(string condi public async Task> GetServiceDescriptorAsync(string address, string condition = null) { - return await GetService().GetServiceDescriptorAsync(address, condition); + return await ServiceLocator.GetService().GetServiceDescriptorAsync(address, condition); } public async Task EditServiceToken(AddressModel address) { - var routes = await GetService().GetRoutesAsync(address.ToString()); + var routes = await ServiceLocator.GetService().GetRoutesAsync(address.ToString()); routes = routes.ToList(); List serviceRoutes = new List(); routes.ToList().ForEach(route => @@ -51,8 +54,8 @@ public async Task EditServiceToken(AddressModel address) Address = addresses }); }); - await GetService().ClearAsync(); - await GetService().SetRoutesAsync(serviceRoutes); + await ServiceLocator.GetService().ClearAsync(); + await ServiceLocator.GetService().SetRoutesAsync(serviceRoutes); } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceRegisterProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceRegisterProvider.cs new file mode 100644 index 000000000..2a0a2ac03 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceRegisterProvider.cs @@ -0,0 +1,65 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.ApiGateWay.ServiceDiscovery.Implementation +{ + /// + /// 服务注册 + /// + public class ServiceRegisterProvider : IServiceRegisterProvider + { + public async Task> GetAddressAsync(string condition = null) + { + var result = new List(); + var registerConfig = AppConfig.Register; + var addresses = registerConfig.Address.Split(","); + if (addresses.Length > 1) + { + foreach (var address in addresses) + { + + var addr = ConvertAddressModel(address); + result.Add(new ServiceAddressModel + { + Address = addr, + IsHealth = await ServiceLocator.GetService().IsHealth(addr) + }); + + } + } + else + { + var address = ConvertAddressModel(registerConfig.Address); + if (address != null) + { + var ipAddress = address as IpAddressModel; + + result.Add(new ServiceAddressModel + { + Address = ipAddress, + IsHealth = await ServiceLocator.GetService().IsHealth(ipAddress) + }); + } + } + return result; + } + + public AddressModel ConvertAddressModel(string connection) + { + var address = connection.Split(":"); + if (address.Length > 1) + { + int port; + int.TryParse(address[1], out port); + return new IpAddressModel(address[0], port); + } + return null; + } + } +} diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceSubscribeProvider.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceSubscribeProvider.cs index 70d3dfc97..cdce11d6c 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceSubscribeProvider.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceDiscovery/Implementation/ServiceSubscribeProvider.cs @@ -1,19 +1,23 @@ -using Surging.Core.System; + using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Surging.Core.CPlatform.Runtime.Client; using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Utilities; namespace Surging.Core.ApiGateWay.ServiceDiscovery.Implementation { - public class ServiceSubscribeProvider : ServiceBase, IServiceSubscribeProvider + /// + /// 服务订阅提供者 + /// + public class ServiceSubscribeProvider :IServiceSubscribeProvider { public async Task> GetAddressAsync(string condition = null) { var result = new List(); - var addresses = await GetService().GetAddressAsync(condition); + var addresses = await ServiceLocator.GetService().GetAddressAsync(condition); foreach (var address in addresses) { result.Add(new ServiceAddressModel @@ -26,7 +30,7 @@ public async Task> GetAddressAsync(string condi public async Task> GetServiceDescriptorAsync(string address, string condition = null) { - return await GetService().GetServiceDescriptorAsync(address, condition); + return await ServiceLocator.GetService().GetServiceDescriptorAsync(address, condition); } } } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceStatusCode.cs b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceStatusCode.cs index 0d8f40cc9..1b0a5627a 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/ServiceStatusCode.cs +++ b/src/Surging.Core/Surging.Core.ApiGateWay/ServiceStatusCode.cs @@ -9,5 +9,6 @@ public enum ServiceStatusCode Success=200, RequestError =400, AuthorizationFailed=401, + Http405Endpoint=405 } } diff --git a/src/Surging.Core/Surging.Core.ApiGateWay/Surging.Core.ApiGateWay.csproj b/src/Surging.Core/Surging.Core.ApiGateWay/Surging.Core.ApiGateWay.csproj index 24ab38787..d7775cfc2 100644 --- a/src/Surging.Core/Surging.Core.ApiGateWay/Surging.Core.ApiGateWay.csproj +++ b/src/Surging.Core/Surging.Core.ApiGateWay/Surging.Core.ApiGateWay.csproj @@ -1,8 +1,8 @@ - netcoreapp2.1 - 0.6.6 + net6.0 + 1.0.0.0 fanly surging Micro Service Framework @@ -11,26 +11,15 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 1.Fix does not support multiple interceptors -2.Fix NLog file path configuration (Download Surging.Core.Nlog V0.6.6) -3.Optimize zookeeper connection(Download Surging.Core.Zookeeper V0.6.6) -4. Consul,zookeeper add reloadOnChange configuration(Download Surging.Core.Zookeeper or -Surging.Core.Consul V0.6.6) -5.Fix Service Router heartbeat registration failed(Download Surging.Core.Zookeeper or -Surging.Core.Consul V0.6.6) -6.add Exception Filter(Download Surging.Core.Zookeeper 0.6.6) -7.Upgrade netty version to repair transmission of big data(Download Surging.Core.DotNetty 0.6.6) - 0.6.6.0 - 0.6.6.0 + 1.Fix bug + 1.0.0.0 + 1.0.0.0 - - - - + - + diff --git a/src/Surging.Core/Surging.Core.AutoMapper/AppConfig.cs b/src/Surging.Core/Surging.Core.AutoMapper/AppConfig.cs new file mode 100644 index 000000000..893220630 --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/AppConfig.cs @@ -0,0 +1,159 @@ +using AutoMapper; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Engines; +using Surging.Core.CPlatform.Engines.Implementation; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using CPlatformAppConfig = Surging.Core.CPlatform.AppConfig; + +namespace Surging.Core.AutoMapper +{ + public class AppConfig + { + + public static IEnumerable Assemblies + { + get + { + var assemblies = new List(); + var referenceAssemblies = GetAllReferenceAssemblies(); + foreach (var assembiyString in AssembliesStrings) + { + assemblies.AddRange(referenceAssemblies.Where(p => p.FullName == assembiyString || Regex.IsMatch(p.FullName, assembiyString))); + } + return assemblies; + } + } + + public static IEnumerable Profiles + { + get + { + var logger = ServiceLocator.GetService>(); + var profiles = new List(); + var referenceAssemblies = GetAllReferenceAssemblies(); + foreach (var assembly in referenceAssemblies) + { + var profileTypes = assembly.DefinedTypes.Select(p => p.AsType()).Where(p => typeof(Profile).IsAssignableFrom(p) && !p.IsAbstract).ToList(); + if (profileTypes.Any()) + { + foreach (var profileType in profileTypes) + { + try + { + var profile = Activator.CreateInstance(profileType) as Profile; + profiles.Add(profile); + } + catch (Exception e) + { + if (logger.IsEnabled(LogLevel.Warning)) + logger.LogWarning($"构建profile失败,profile类型为{profileType.FullName}"); + } + + } + } + } + return profiles; + } + } + + private static IEnumerable GetAllReferenceAssemblies() + { + var serviceEngine = ServiceLocator.GetService() as VirtualPathProviderServiceEngine; + string[] paths = null; + if (serviceEngine != null) + { + if (serviceEngine.ModuleServiceLocationFormats != null) + { + paths = GetPaths(serviceEngine.ModuleServiceLocationFormats); + } + } + var referenceAssemblies = paths == null ? GetReferenceAssembly() : GetReferenceAssembly(paths); + return referenceAssemblies; + } + + private static List _referenceAssembly = new List(); + + public static IEnumerable AssembliesStrings { get; internal set; } + + private static List GetReferenceAssembly(params string[] virtualPaths) + { + var refAssemblies = new List();//Assembly 通过此类能够载入操纵一个程序集,并获取程序集内部信息 + var rootPath = AppContext.BaseDirectory; + var existsPath = virtualPaths.Any();//判断是否有数据 + if (existsPath && !string.IsNullOrEmpty(CPlatformAppConfig.ServerOptions.RootPath)) + rootPath = CPlatformAppConfig.ServerOptions.RootPath; + var result = _referenceAssembly; + if (!result.Any() || existsPath) + { + var paths = virtualPaths.Select(m => Path.Combine(rootPath, m)).ToList(); + if (!existsPath) paths.Add(rootPath); + paths.ForEach(path => + { + var assemblyFiles = GetAllAssemblyFiles(path); + + foreach (var referencedAssemblyFile in assemblyFiles) + { + var referencedAssembly = Assembly.LoadFrom(referencedAssemblyFile); + if (!_referenceAssembly.Contains(referencedAssembly)) + _referenceAssembly.Add(referencedAssembly); + refAssemblies.Add(referencedAssembly); + } + result = existsPath ? refAssemblies : _referenceAssembly; + }); + } + return result; + } + + private static List GetAllAssemblyFiles(string parentDir) + { + var notRelatedFile = CPlatformAppConfig.ServerOptions.NotRelatedAssemblyFiles; + var relatedFile = CPlatformAppConfig.ServerOptions.RelatedAssemblyFiles; + var pattern = string.Format("^Microsoft.\\w*|^System.\\w*|^Netty.\\w*|^Autofac.\\w*{0}", + string.IsNullOrEmpty(notRelatedFile) ? "" : $"|{notRelatedFile}"); + Regex notRelatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + Regex relatedRegex = new Regex(relatedFile, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + if (!string.IsNullOrEmpty(relatedFile)) + { + return + Directory.GetFiles(parentDir, "*.dll").Select(Path.GetFullPath).Where( + a => !notRelatedRegex.IsMatch(a) && relatedRegex.IsMatch(a)).ToList(); + } + else + { + return + Directory.GetFiles(parentDir, "*.dll").Select(Path.GetFullPath).Where( + a => !notRelatedRegex.IsMatch(a)).ToList(); + } + } + + private static string[] GetPaths(params string[] virtualPaths) + { + var directories = new List(virtualPaths.Where(p => !string.IsNullOrEmpty(p))); + string rootPath = string.IsNullOrEmpty(CPlatformAppConfig.ServerOptions.RootPath) ? + AppContext.BaseDirectory : CPlatformAppConfig.ServerOptions.RootPath; + var virPaths = virtualPaths; + foreach (var virtualPath in virtualPaths) + { + var path = Path.Combine(rootPath, virtualPath); + if (Directory.Exists(path)) + { + var dirs = Directory.GetDirectories(path); + directories.AddRange(dirs.Select(dir => Path.Combine(virtualPath, new DirectoryInfo(dir).Name))); + } + else + { + directories.Remove(virtualPath); + virPaths = null; + } + } + return directories.Any() ? directories.Distinct().ToArray() : virPaths; + } + + } +} diff --git a/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/AutoMapperBootstrap.cs b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/AutoMapperBootstrap.cs new file mode 100644 index 000000000..e8d8362ad --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/AutoMapperBootstrap.cs @@ -0,0 +1,37 @@ +using AutoMapper; +using AutoMapper.Attributes; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Utilities; +using System.Linq; + +namespace Surging.Core.AutoMapper +{ + public class AutoMapperBootstrap : IAutoMapperBootstrap + { + public void Initialize() + { + var logger = ServiceLocator.GetService>(); + Mapper.Initialize(config => { + if (AppConfig.Assemblies.Any()) + { + foreach (var assembly in AppConfig.Assemblies) + { + assembly.MapTypes(config); + } + } + + var profiles = AppConfig.Profiles; + if (profiles.Any()) + { + foreach (var profile in profiles) + { + logger.LogDebug($"解析到{profile.GetType().FullName}映射关系"); + config.AddProfile(profile); + } + } + + }); + } + + } +} diff --git a/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/IAutoMapperBootstrap.cs b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/IAutoMapperBootstrap.cs new file mode 100644 index 000000000..d2678015b --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/IAutoMapperBootstrap.cs @@ -0,0 +1,7 @@ +namespace Surging.Core.AutoMapper +{ + public interface IAutoMapperBootstrap + { + void Initialize(); + } +} diff --git a/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/MapperExtensions.cs b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/MapperExtensions.cs new file mode 100644 index 000000000..86201636a --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapper/MapperExtensions.cs @@ -0,0 +1,17 @@ +using AutoMapper; + +namespace Surging.Core.AutoMapper +{ + public static class MapperExtensions + { + public static T MapTo(this object obj) where T : class + { + return Mapper.Map(obj); + } + + public static TDestination MapTo(this TSource obj, TDestination entity) where TSource : class where TDestination : class + { + return Mapper.Map(obj, entity); + } + } +} diff --git a/src/Surging.Core/Surging.Core.AutoMapper/AutoMapperModule.cs b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapperModule.cs new file mode 100644 index 000000000..c757f9021 --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/AutoMapperModule.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.Configuration; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using CPlatformAppConfig = Surging.Core.CPlatform.AppConfig; + +namespace Surging.Core.AutoMapper +{ + public class AutoMapperModule : EnginePartModule + { + + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + context.ServiceProvoider.GetInstances().Initialize(); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + var configAssembliesStr = CPlatformAppConfig.GetSection("Automapper:Assemblies").Get(); + if (!string.IsNullOrEmpty(configAssembliesStr)) + { + AppConfig.AssembliesStrings = configAssembliesStr.Split(";"); + } + builder.RegisterType().As(); + } + + + } +} diff --git a/src/Surging.Core/Surging.Core.AutoMapper/ServiceHostBuilderExtensions.cs b/src/Surging.Core/Surging.Core.AutoMapper/ServiceHostBuilderExtensions.cs new file mode 100644 index 000000000..514e5dd25 --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/ServiceHostBuilderExtensions.cs @@ -0,0 +1,17 @@ +using Autofac; +using Surging.Core.ServiceHosting.Internal; + +namespace Surging.Core.AutoMapper +{ + public static class ServiceHostBuilderExtensions + { + public static IServiceHostBuilder UseAutoMapper(this IServiceHostBuilder hostBuilder) + { + return hostBuilder.MapServices(mapper => + { + var autoMapperBootstrap = mapper.Resolve(); + autoMapperBootstrap.Initialize(); + }); + } + } +} diff --git a/src/Surging.Core/Surging.Core.AutoMapper/Surging.Core.AutoMapper.csproj b/src/Surging.Core/Surging.Core.AutoMapper/Surging.Core.AutoMapper.csproj new file mode 100644 index 000000000..fa5664335 --- /dev/null +++ b/src/Surging.Core/Surging.Core.AutoMapper/Surging.Core.AutoMapper.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + 通过AutoMapper组件实现Dto对象和实体对象之间的相互转换 + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.CPlatform/Address/AddressHelper.cs b/src/Surging.Core/Surging.Core.CPlatform/Address/AddressHelper.cs new file mode 100644 index 000000000..0e96ae8cd --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Address/AddressHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; + +namespace Surging.Core.CPlatform.Address +{ + public class AddressHelper + { + public static string GetIpFromAddress(string address) + { + if (IsValidIp(address)) + { + return address; + } + var ips = Dns.GetHostAddresses(address); + return ips[0].ToString(); + } + + public static bool IsValidIp(string address) + { + if (Regex.IsMatch(address, "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}")) + { + string[] ips = address.Split('.'); + if (ips.Length == 4 || ips.Length == 6) + { + if (int.Parse(ips[0]) < 256 && int.Parse(ips[1]) < 256 && int.Parse(ips[2]) < 256 && int.Parse(ips[3]) < 256) + { + return true; + } + } + return false; + } + return false; + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Address/AddressModel.cs b/src/Surging.Core/Surging.Core.CPlatform/Address/AddressModel.cs index d140f5c4f..db147134b 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Address/AddressModel.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Address/AddressModel.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json; +using System; using System.Net; namespace Surging.Core.CPlatform.Address @@ -13,8 +14,15 @@ public abstract class AddressModel /// /// public abstract EndPoint CreateEndPoint(); - + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public decimal ProcessorTime { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, PropertyName="Wt")] + public int Weight { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, PropertyName = "Tp")] + public long Timestamp { get; set; } /// /// 重写后的标识。 /// diff --git a/src/Surging.Core/Surging.Core.CPlatform/Address/IpAddressModel.cs b/src/Surging.Core/Surging.Core.CPlatform/Address/IpAddressModel.cs index a4d2144c1..709a0217e 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Address/IpAddressModel.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Address/IpAddressModel.cs @@ -1,3 +1,4 @@ +using Newtonsoft.Json; using System; using System.Net; using System.Text; @@ -43,6 +44,18 @@ public IpAddressModel(string ip, int port) /// public int Port { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string WanIp { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? WsPort { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? MqttPort { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? HttpPort { get; set; } + #endregion Property #region Overrides of AddressModel @@ -59,7 +72,7 @@ public override EndPoint CreateEndPoint() public override string ToString() { - return string.Concat(new string[] {Ip,":" , Port.ToString() }); + return string.Concat(new string[] { Ip, ":", Port.ToString() }); } #endregion Overrides of AddressModel diff --git a/src/Surging.Core/Surging.Core.CPlatform/AppConfig.cs b/src/Surging.Core/Surging.Core.CPlatform/AppConfig.cs index aaafb7d8e..4ec322756 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/AppConfig.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/AppConfig.cs @@ -12,22 +12,25 @@ namespace Surging.Core.CPlatform { - public class AppConfig + public class AppConfig { #region 字段 - private static AddressSelectorMode _loadBalanceMode=AddressSelectorMode.Polling; - private static SurgingServerOptions _serverOptions=new SurgingServerOptions(); + private static AddressSelectorMode _loadBalanceMode = AddressSelectorMode.Polling; + private static SurgingServerOptions _serverOptions = new SurgingServerOptions(); #endregion - internal static IConfigurationRoot Configuration { get; set; } + public static IConfigurationRoot Configuration { get; internal set; } + /// + /// 负载均衡模式 + /// public static AddressSelectorMode LoadBalanceMode { get { AddressSelectorMode mode = _loadBalanceMode; ; - if(Configuration !=null - && Configuration["AccessTokenExpireTimeSpan"]!=null + if (Configuration != null + && Configuration["AccessTokenExpireTimeSpan"] != null && !Enum.TryParse(Configuration["AccessTokenExpireTimeSpan"], out mode)) { mode = _loadBalanceMode; diff --git a/src/Surging.Core/Surging.Core.CPlatform/CPlatformContainer.cs b/src/Surging.Core/Surging.Core.CPlatform/CPlatformContainer.cs index 944300098..0c0c20266 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/CPlatformContainer.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/CPlatformContainer.cs @@ -4,6 +4,9 @@ namespace Surging.Core.CPlatform { + /// + /// 平台容器 + /// public class CPlatformContainer { private IComponentContext _container; @@ -64,6 +67,11 @@ public T GetInstances(Type type) where T : class return _container.Resolve(type) as T; } + public object GetInstancePerLifetimeScope(string name, Type type) + { + return string.IsNullOrEmpty(name) ? GetInstances(type) : _container.ResolveKeyed(name, type); + } + public object GetInstances(string name,Type type) { // var appConfig = AppConfig.DefaultInstance; diff --git a/src/Surging.Core/Surging.Core.CPlatform/CommunicationProtocol.cs b/src/Surging.Core/Surging.Core.CPlatform/CommunicationProtocol.cs index 8403135b5..f61bcc9b5 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/CommunicationProtocol.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/CommunicationProtocol.cs @@ -9,6 +9,9 @@ public enum CommunicationProtocol None, Tcp, Http, - WS + WS, + Mqtt, + Dns, + Udp } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationExtensions.cs index 35b53ba8a..0442b6abd 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationExtensions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationExtensions.cs @@ -12,20 +12,25 @@ public static class CacheConfigurationExtensionsstatic { public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder builder, string path) { - return AddCPlatformFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + return AddCPlatformFile(builder, provider: null, path: path,basePath: null, optional: false, reloadOnChange: false); } public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder builder, string path, bool optional) { - return AddCPlatformFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + return AddCPlatformFile(builder, provider: null, path: path,basePath: null, optional: optional, reloadOnChange: false); } public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { - return AddCPlatformFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + return AddCPlatformFile(builder, provider: null, path: path, basePath:null, optional: optional, reloadOnChange: reloadOnChange); } - public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder builder, string path, string basePath, bool optional, bool reloadOnChange) + { + return AddCPlatformFile(builder, provider: null, path: path, basePath:basePath, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder builder, IFileProvider provider, string path,string basePath, bool optional, bool reloadOnChange) { Check.NotNull(builder, "builder"); Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); @@ -36,7 +41,7 @@ public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder { provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); path = Path.GetFileName(path); - } + } var source = new CPlatformConfigurationSource { FileProvider = provider, @@ -44,7 +49,10 @@ public static IConfigurationBuilder AddCPlatformFile(this IConfigurationBuilder Optional = optional, ReloadOnChange = reloadOnChange }; + builder.Add(source); + if (!string.IsNullOrEmpty(basePath)) + builder.SetBasePath(basePath); AppConfig.Configuration = builder.Build(); AppConfig.ServerOptions = AppConfig.Configuration.Get(); var section = AppConfig.Configuration.GetSection("Surging"); diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationProvider.cs index e805a6817..a45528373 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationProvider.cs @@ -1,13 +1,10 @@ using Microsoft.Extensions.Configuration; using Surging.Core.CPlatform.Configurations.Remote; -using System; -using System.Collections.Generic; using System.IO; -using System.Text; namespace Surging.Core.CPlatform.Configurations { - public class CPlatformConfigurationProvider : FileConfigurationProvider + public class CPlatformConfigurationProvider : FileConfigurationProvider { public CPlatformConfigurationProvider(CPlatformConfigurationSource source) : base(source) { } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationSource.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationSource.cs index 0983f6238..4a6413edc 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationSource.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/CPlatformConfigurationSource.cs @@ -1,7 +1,4 @@ using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Text; namespace Surging.Core.CPlatform.Configurations { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/DockerDeployMode.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/DockerDeployMode.cs new file mode 100644 index 000000000..ae89ea007 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/DockerDeployMode.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Configurations +{ + /// + /// Docker容器部署模式 + /// + public enum DockerDeployMode + { + /// + /// 正常模式 + /// + Standard, + + /// + /// Swarm集群模式 + /// + Swarm + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/IConfigurationWatchManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/IConfigurationWatchManager.cs index 32dc9e494..74c99ffcd 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/IConfigurationWatchManager.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/IConfigurationWatchManager.cs @@ -1,7 +1,4 @@ using Surging.Core.CPlatform.Configurations.Watch; -using System; -using System.Collections.Generic; -using System.Text; namespace Surging.Core.CPlatform.Configurations { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/ModulePackage.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/ModulePackage.cs index b139fe6f9..13b2414f9 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/ModulePackage.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/ModulePackage.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Surging.Core.CPlatform.Configurations +namespace Surging.Core.CPlatform.Configurations { public class ModulePackage { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/ProtocolPortOptions.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/ProtocolPortOptions.cs index db1a5b3de..15541d6e9 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/ProtocolPortOptions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/ProtocolPortOptions.cs @@ -1,15 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Surging.Core.CPlatform.Configurations +namespace Surging.Core.CPlatform.Configurations { - public class ProtocolPortOptions + public class ProtocolPortOptions { - public int MQTTPort { get; set; } = 97; + public int MQTTPort { get; set; } + + public int? HttpPort { get; set; } + + public int WSPort { get; set; } + + public int GrpcPort { get; set; } - public int HttpPort { get; set; } = 80; + public int UdpPort { get; set; } - public int WSPort { get; set; } = 96; + public int TcpPort { get; set; } } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/RuntimeEnvironment.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/RuntimeEnvironment.cs new file mode 100644 index 000000000..fdc85ad79 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/RuntimeEnvironment.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Configurations +{ + public enum RuntimeEnvironment + { + Development = 0, + + Test, + + Staging, + + Production, + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/SurgingServerOptions.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/SurgingServerOptions.cs index 379d5f448..1eb1139c6 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/SurgingServerOptions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/SurgingServerOptions.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Net; -using System.Text; namespace Surging.Core.CPlatform.Configurations { @@ -14,17 +13,43 @@ public partial class SurgingServerOptions: ServiceCommand public int MappingPort { get; set; } + public string WanIp { get; set; } + + public bool IsModulePerLifetimeScope { get; set; } + public double WatchInterval { get; set; } = 20d; + public int DisconnTimeInterval { get; set; } = 60; + + public bool Libuv { get; set; } = false; + + public DockerDeployMode DockerDeployMode { get; set; } = DockerDeployMode.Standard; + + public int SoBacklog { get; set; } = 8192; + + public int Weight { get; set; } + + public bool EnableRouteWatch { get; set; } + public IPEndPoint IpEndpoint { get; set; } + public bool EnableObjectConvert { get; set; } = true; + public List Packages { get; set; } = new List(); public CommunicationProtocol Protocol { get; set; } public string RootPath { get; set; } + public string WebRootPath { get; set; } = AppContext.BaseDirectory; + public int Port { get; set; } + public bool DisableServiceRegistration { get; set; } + + public bool DisableDiagnostic { get; set; } + + public bool ReloadOnChange { get; set; } = false; + public ProtocolPortOptions Ports { get; set; } = new ProtocolPortOptions(); public string Token { get; set; } = "True"; diff --git a/src/Surging.Core/Surging.Core.CPlatform/Configurations/Watch/ConfigurationWatchManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Configurations/Watch/ConfigurationWatchManager.cs index 4d6ffbad0..c0eecd38a 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Configurations/Watch/ConfigurationWatchManager.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Configurations/Watch/ConfigurationWatchManager.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Collections.Generic; using System.Text; using System.Threading; @@ -11,9 +12,11 @@ public class ConfigurationWatchManager: IConfigurationWatchManager internal HashSet dataWatches = new HashSet(); private readonly Timer _timer; + private readonly ILogger _logger; - public ConfigurationWatchManager() + public ConfigurationWatchManager(ILogger logger) { + _logger = logger; var timeSpan = TimeSpan.FromSeconds(AppConfig.ServerOptions.WatchInterval); _timer = new Timer(async s => { @@ -21,7 +24,7 @@ public ConfigurationWatchManager() }, null, timeSpan, timeSpan); } - public HashSet DataWatches + public HashSet DataWatches { get { @@ -46,7 +49,19 @@ private async Task Watching() { foreach (var watch in dataWatches) { - await watch.Process(); + try + { + var task= watch.Process(); + if (!task.IsCompletedSuccessfully) + await task; + else + task.GetAwaiter().GetResult(); + } + catch(Exception ex) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"message:{ex.Message},Source:{ex.Source},Trace:{ex.StackTrace}"); + } } } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/ContainerBuilderExtensions.cs index e1108ecd2..225a9da9f 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/ContainerBuilderExtensions.cs @@ -1,5 +1,6 @@ using Autofac; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.Logging; using Surging.Core.CPlatform.Cache; using Surging.Core.CPlatform.Configurations; @@ -16,6 +17,7 @@ using Surging.Core.CPlatform.Ids.Implementation; using Surging.Core.CPlatform.Ioc; using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Mqtt; using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Routing.Implementation; using Surging.Core.CPlatform.Runtime.Client; @@ -38,6 +40,8 @@ using Surging.Core.CPlatform.Transport.Codec; using Surging.Core.CPlatform.Transport.Codec.Implementation; using Surging.Core.CPlatform.Utilities; +using Surging.Core.CPlatform.Validation; +using Surging.Core.CPlatform.Validation.Implementation; using System; using System.Collections.Generic; using System.IO; @@ -85,6 +89,7 @@ public static class ContainerBuilderExtensions { private static List _referenceAssembly = new List(); private static List _modules = new List(); + /// /// 添加Json序列化支持。 /// @@ -172,6 +177,18 @@ public static IServiceBuilder UseRouteManager(this IServiceBuilder builder, ISer return builder; } + /// + /// 设置mqtt服务路由管理者。 + /// + /// mqtt服务构建者。 + /// mqtt服务路由管理者实例工厂。 + /// 服务构建者。 + public static IServiceBuilder UseMqttRouteManager(this IServiceBuilder builder, Func factory) + { + builder.Services.RegisterAdapter(factory).InstancePerLifetimeScope(); + return builder; + } + #endregion RouteManager /// @@ -249,6 +266,19 @@ public static IServiceBuilder UseRandomAddressSelector(this IServiceBuilder buil return builder; } + + /// + /// 使用权重轮询选择器。 + /// + /// 服务构建者。 + /// 服务构建者。 + public static IServiceBuilder UseRoundRobinAddressSelector(this IServiceBuilder builder) + { + builder.Services.RegisterType(typeof(RoundRobinAddressSelector)) + .Named(AddressSelectorMode.RoundRobin.ToString(), typeof(IAddressSelector)).SingleInstance(); + return builder; + } + /// /// 设置服务地址选择器。 /// @@ -257,13 +287,18 @@ public static IServiceBuilder UseRandomAddressSelector(this IServiceBuilder buil /// 服务构建者。 public static IServiceBuilder UseAddressSelector(this IServiceBuilder builder) { - return builder.UseRandomAddressSelector().UsePollingAddressSelector().UseFairPollingAddressSelector().UseHashAlgorithmAddressSelector(); + return builder.UseRandomAddressSelector().UsePollingAddressSelector().UseFairPollingAddressSelector().UseHashAlgorithmAddressSelector().UseRoundRobinAddressSelector(); } #endregion AddressSelector #region Configuration Watch + /// + /// Configuration Watch + /// + /// + /// 服务构建者 public static IServiceBuilder AddConfigurationWatch(this IServiceBuilder builder) { var services = builder.Services; @@ -364,8 +399,13 @@ public static IServiceBuilder AddFilter(this IServiceBuilder builder, IFilter fi } else if (typeof(IAuthorizationFilter).IsAssignableFrom(filter.GetType())) { - var exceptionFilter = filter as IAuthorizationFilter; - services.Register(p => exceptionFilter).As(typeof(IAuthorizationFilter)).SingleInstance(); + var authorizationFilter = filter as IAuthorizationFilter; + services.Register(p => authorizationFilter).As(typeof(IAuthorizationFilter)).SingleInstance(); + } + else if (typeof(IActionFilter).IsAssignableFrom(filter.GetType())) + { + var authorizationFilter = filter as IActionFilter; + services.Register(p => authorizationFilter).As(typeof(IActionFilter)).SingleInstance(); } return builder; } @@ -389,7 +429,7 @@ public static IServiceBuilder AddServiceRuntime(this IServiceBuilder builder) builder.Services.RegisterType(typeof(DefaultServiceExecutor)).As(typeof(IServiceExecutor)) .Named(CommunicationProtocol.Tcp.ToString()).SingleInstance(); - return builder.RegisterServices().RegisterRepositories().RegisterServiceBus().RegisterModules().AddRuntime(); + return builder.RegisterServices().RegisterRepositories().RegisterServiceBus().RegisterModules().RegisterInstanceByConstraint().AddRuntime(); } /// @@ -414,24 +454,58 @@ public static IServiceBuilder AddRelateServiceRuntime(this IServiceBuilder build public static IServiceBuilder AddCoreService(this ContainerBuilder services) { Check.NotNull(services, "services"); + //注册服务ID生成实例 services.RegisterType().As().SingleInstance(); services.Register(p => new CPlatformContainer(p)); + //注册默认的类型转换 services.RegisterType(typeof(DefaultTypeConvertibleProvider)).As(typeof(ITypeConvertibleProvider)).SingleInstance(); + //注册默认的类型转换服务 services.RegisterType(typeof(DefaultTypeConvertibleService)).As(typeof(ITypeConvertibleService)).SingleInstance(); + //注册权限过滤 services.RegisterType(typeof(AuthorizationAttribute)).As(typeof(IAuthorizationFilter)).SingleInstance(); + services.RegisterType(typeof(ActionFilterAttribute)).As(typeof(IActionFilter)).SingleInstance(); + services.RegisterType(typeof(ActionFilterAttribute)).As(typeof(IFilter)).SingleInstance(); + //注册基本过滤 services.RegisterType(typeof(AuthorizationAttribute)).As(typeof(IFilter)).SingleInstance(); + //注册默认校验处理器 + services.RegisterType(typeof(DefaultValidationProcessor)).As(typeof(IValidationProcessor)).SingleInstance(); + //注册服务器路由接口 services.RegisterType(typeof(DefaultServiceRouteProvider)).As(typeof(IServiceRouteProvider)).SingleInstance(); + //注册服务路由工厂 services.RegisterType(typeof(DefaultServiceRouteFactory)).As(typeof(IServiceRouteFactory)).SingleInstance(); + //注册服务订阅工厂 services.RegisterType(typeof(DefaultServiceSubscriberFactory)).As(typeof(IServiceSubscriberFactory)).SingleInstance(); + //注册服务token生成接口 services.RegisterType(typeof(ServiceTokenGenerator)).As(typeof(IServiceTokenGenerator)).SingleInstance(); + //注册哈希一致性算法 services.RegisterType(typeof(HashAlgorithm)).As(typeof(IHashAlgorithm)).SingleInstance(); + //注册组件生命周期接口 services.RegisterType(typeof(ServiceEngineLifetime)).As(typeof(IServiceEngineLifetime)).SingleInstance(); + //注册服务心跳管理 + services.RegisterType(typeof(DefaultServiceHeartbeatManager)).As(typeof(IServiceHeartbeatManager)).SingleInstance(); return new ServiceBuilder(services) .AddJsonSerialization() .UseJsonCodec(); } + public static IServiceBuilder RegisterInstanceByConstraint(this IServiceBuilder builder, params string[] virtualPaths) + { + var services = builder.Services; + var referenceAssemblies = GetReferenceAssembly(virtualPaths); + + foreach (var assembly in referenceAssemblies) + { + services.RegisterAssemblyTypes(assembly) + .Where(t => typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(t)).AsImplementedInterfaces().AsSelf().SingleInstance(); + + services.RegisterAssemblyTypes(assembly) + .Where(t => typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(t)).AsImplementedInterfaces().AsSelf().InstancePerDependency(); + } + return builder; + + } + private static IServiceBuilder AddRuntime(this IServiceBuilder builder) { var services = builder.Services; @@ -451,11 +525,16 @@ private static IServiceBuilder AddRuntime(this IServiceBuilder builder) { builder = null; } - }).As(); + }).As().SingleInstance(); builder.Services.RegisterType(typeof(DefaultServiceEntryManager)).As(typeof(IServiceEntryManager)).SingleInstance(); return builder; } + /// + /// 添加微服务 + /// + /// + /// public static void AddMicroService(this ContainerBuilder builder, Action option) { option.Invoke(builder.AddCoreService()); @@ -471,19 +550,28 @@ public static IServiceBuilder RegisterServices(this IServiceBuilder builder, par try { var services = builder.Services; - var referenceAssemblies = GetReferenceAssembly(virtualPaths); + var referenceAssemblies = GetAssemblies(virtualPaths); foreach (var assembly in referenceAssemblies) { services.RegisterAssemblyTypes(assembly) + //注入继承IServiceKey接口的所有接口 .Where(t => typeof(IServiceKey).GetTypeInfo().IsAssignableFrom(t) && t.IsInterface) .AsImplementedInterfaces(); services.RegisterAssemblyTypes(assembly) - .Where(t => typeof(IServiceBehavior).GetTypeInfo().IsAssignableFrom(t) && t.GetTypeInfo().GetCustomAttribute() == null).AsImplementedInterfaces(); + //注入实现IServiceBehavior接口并ModuleName为空的类,作为接口实现类 + .Where(t => !typeof(ISingleInstance).GetTypeInfo().IsAssignableFrom(t) && + typeof(IServiceBehavior).GetTypeInfo().IsAssignableFrom(t) && t.GetTypeInfo().GetCustomAttribute() == null).AsImplementedInterfaces(); + + services.RegisterAssemblyTypes(assembly) + //注入实现IServiceBehavior接口并ModuleName为空的类,作为接口实现类 + .Where(t => typeof(ISingleInstance).GetTypeInfo().IsAssignableFrom(t) && + typeof(IServiceBehavior).GetTypeInfo().IsAssignableFrom(t) && t.GetTypeInfo().GetCustomAttribute() == null).SingleInstance().AsImplementedInterfaces(); var types = assembly.GetTypes().Where(t => typeof(IServiceBehavior).GetTypeInfo().IsAssignableFrom(t) && t.GetTypeInfo().GetCustomAttribute() != null); foreach (var type in types) { var module = type.GetTypeInfo().GetCustomAttribute(); + //对ModuleName不为空的对象,找到第一个继承IServiceKey的接口并注入接口及实现 var interfaceObj = type.GetInterfaces() .FirstOrDefault(t => typeof(IServiceKey).GetTypeInfo().IsAssignableFrom(t)); if (interfaceObj != null) @@ -508,32 +596,38 @@ public static IServiceBuilder RegisterServices(this IServiceBuilder builder, par } } + /// + /// 依赖注入事件总线模块程序集 + /// + /// + /// + /// 返回注册模块信息 public static IServiceBuilder RegisterServiceBus (this IServiceBuilder builder, params string[] virtualPaths) { var services = builder.Services; - var referenceAssemblies = GetReferenceAssembly(virtualPaths); + var referenceAssemblies = GetAssemblies(virtualPaths); foreach (var assembly in referenceAssemblies) { services.RegisterAssemblyTypes(assembly) .Where(t => typeof(IIntegrationEventHandler).GetTypeInfo().IsAssignableFrom(t)).AsImplementedInterfaces().SingleInstance(); services.RegisterAssemblyTypes(assembly) - .Where(t => typeof(IIntegrationEventHandler).IsAssignableFrom(t)).SingleInstance(); + .Where(t => typeof(IIntegrationEventHandler).IsAssignableFrom(t)).SingleInstance(); } return builder; } - /// - ///依赖注入仓储模块程序集 - /// - /// IOC容器 + /// + /// 依赖注入仓储模块程序集 + /// + /// IOC容器 + /// 虚拟路径 /// 返回注册模块信息 - public static IServiceBuilder RegisterRepositories - (this IServiceBuilder builder, params string[] virtualPaths) + public static IServiceBuilder RegisterRepositories(this IServiceBuilder builder, params string[] virtualPaths) { var services = builder.Services; - var referenceAssemblies = GetReferenceAssembly(virtualPaths); + var referenceAssemblies = GetAssemblies(virtualPaths); foreach (var assembly in referenceAssemblies) { @@ -543,40 +637,48 @@ public static IServiceBuilder RegisterRepositories return builder; } - public static IServiceBuilder RegisterModules( - this IServiceBuilder builder, params string[] virtualPaths) + /// + /// 依赖注入组件模块程序集 + /// + /// + /// + /// 返回注册模块信息 + public static IServiceBuilder RegisterModules(this IServiceBuilder builder, params string[] virtualPaths) { var services = builder.Services; - var referenceAssemblies = GetReferenceAssembly(virtualPaths); + var referenceAssemblies = GetAssemblies(virtualPaths); if (builder == null) throw new ArgumentNullException("builder"); + //从surgingSettings.json取到packages var packages = ConvertDictionary(AppConfig.ServerOptions.Packages); foreach (var moduleAssembly in referenceAssemblies) { GetAbstractModules(moduleAssembly).ForEach(p => { - services.RegisterModule(p); - if (packages.ContainsKey(p.TypeName)) + if (!_modules.Any(m => p.ModuleName == m.ModuleName)) { - var useModules = packages[p.TypeName]; - if (useModules.AsSpan().IndexOf(p.ModuleName) >= 0) - p.Enable = true; - else - p.Enable = false; + services.RegisterModule(p); + if (packages.ContainsKey(p.TypeName)) + { + var useModules = packages[p.TypeName]; + if (useModules.AsSpan().IndexOf(p.ModuleName) >= 0) + p.Enable = true; + else + p.Enable = false; + } + _modules.Add(p); } - - _modules.Add(p); }); } builder.Services.Register(provider => new ModuleProvider( - _modules,provider.Resolve>(), provider.Resolve() + _modules, virtualPaths, provider.Resolve>(), provider.Resolve() )).As().SingleInstance(); return builder; } - public static List GetInterfaceService(this IServiceBuilder builder) + public static List GetInterfaceService(this IServiceBuilder builder, params string[] virtualPaths) { var types = new List(); - var referenceAssemblies = GetReferenceAssembly(); + var referenceAssemblies = GetReferenceAssembly(virtualPaths); referenceAssemblies.ForEach(p => { types.AddRange(p.GetTypes().Where(t => typeof(IServiceKey).GetTypeInfo().IsAssignableFrom(t) && t.IsInterface)); @@ -584,20 +686,25 @@ public static List GetInterfaceService(this IServiceBuilder builder) return types; } - public static IEnumerable GetDataContractName(this IServiceBuilder builder) + public static IEnumerable GetDataContractName(this IServiceBuilder builder, params string[] virtualPaths) { var namespaces = new List(); - var referenceAssemblies = builder.GetInterfaceService(); - referenceAssemblies.ForEach(p => + var assemblies = builder.GetInterfaceService(virtualPaths) + .Select(p => p.Assembly) + .Union(GetSystemModules()) + .Distinct() + .ToList(); + + assemblies.ForEach(assembly => { - namespaces.AddRange(p.Assembly.GetTypes().Where(t => t.GetCustomAttribute() != null).Select(n => n.Namespace)); + namespaces.AddRange(assembly.GetTypes().Where(t => t.GetCustomAttribute() != null).Select(n => n.Namespace)); }); - return namespaces.Distinct(); + return namespaces; } private static IDictionary ConvertDictionary(List list) { - var result = new Dictionary(); + var result = new Dictionary(); list.ForEach(p => { result.Add(p.TypeName, p.Using); @@ -620,7 +727,7 @@ private static List GetReferenceAssembly(params string[] virtualPaths) paths.ForEach(path => { var assemblyFiles = GetAllAssemblyFiles(path); - + foreach (var referencedAssemblyFile in assemblyFiles) { var referencedAssembly = Assembly.LoadFrom(referencedAssemblyFile); @@ -628,12 +735,51 @@ private static List GetReferenceAssembly(params string[] virtualPaths) _referenceAssembly.Add(referencedAssembly); refAssemblies.Add(referencedAssembly); } - result = existsPath ? refAssemblies: _referenceAssembly; + result = existsPath ? refAssemblies : _referenceAssembly; }); } return result; } - + + private static List GetSystemModules() + { + var assemblies = new List(); + var referenceAssemblies = GetReferenceAssembly(); + foreach (var referenceAssembly in referenceAssemblies) + { + var abstractModules = GetAbstractModules(referenceAssembly); + if (abstractModules.Any(p => p.GetType().IsSubclassOf(typeof(SystemModule)))) + { + assemblies.Add(referenceAssembly); + } + } + return assemblies; + } + + private static List GetAssemblies(params string[] virtualPaths) + { + var referenceAssemblies = new List(); + if (virtualPaths.Any()) + { + referenceAssemblies = GetReferenceAssembly(virtualPaths); + } + else + { + string[] assemblyNames = DependencyContext + .Default.GetDefaultAssemblyNames().Select(p => p.Name).ToArray(); + assemblyNames = GetFilterAssemblies(assemblyNames); + foreach (var name in assemblyNames) + referenceAssemblies.Add(Assembly.Load(name)); + _referenceAssembly.AddRange(referenceAssemblies.Except(_referenceAssembly)); + } + return referenceAssemblies; + } + + /// + /// 获取抽象模块(查找继承AbstractModule类的对象并创建实例) + /// + /// + /// private static List GetAbstractModules(Assembly assembly) { var abstractModules = new List(); @@ -648,6 +794,28 @@ private static List GetAbstractModules(Assembly assembly) return abstractModules; } + private static string[] GetFilterAssemblies(string[] assemblyNames) + { + var notRelatedFile = AppConfig.ServerOptions.NotRelatedAssemblyFiles; + var relatedFile = AppConfig.ServerOptions.RelatedAssemblyFiles; + var pattern = string.Format("^Microsoft.\\w*|^System.\\w*|^DotNetty.\\w*|^runtime.\\w*|^ZooKeeperNetEx\\w*|^StackExchange.Redis\\w*|^Consul\\w*|^Newtonsoft.Json.\\w*|^Autofac.\\w*{0}", + string.IsNullOrEmpty(notRelatedFile) ? "" : $"|{notRelatedFile}"); + Regex notRelatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + Regex relatedRegex = new Regex(relatedFile, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + if (!string.IsNullOrEmpty(relatedFile)) + { + return + assemblyNames.Where( + name => !notRelatedRegex.IsMatch(name) && relatedRegex.IsMatch(name)).ToArray(); + } + else + { + return + assemblyNames.Where( + name => !notRelatedRegex.IsMatch(name)).ToArray(); + } + } + private static List GetAllAssemblyFiles(string parentDir) { var notRelatedFile = AppConfig.ServerOptions.NotRelatedAssemblyFiles; @@ -666,8 +834,8 @@ private static List GetAllAssemblyFiles(string parentDir) { return Directory.GetFiles(parentDir, "*.dll").Select(Path.GetFullPath).Where( - a => !notRelatedRegex.IsMatch(a)).ToList(); + a => !notRelatedRegex.IsMatch(Path.GetFileName(a))).ToList(); } } } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Convertibles/Implementation/DefaultTypeConvertibleProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Convertibles/Implementation/DefaultTypeConvertibleProvider.cs index c33152467..8ace5e1ce 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Convertibles/Implementation/DefaultTypeConvertibleProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Convertibles/Implementation/DefaultTypeConvertibleProvider.cs @@ -26,8 +26,13 @@ public DefaultTypeConvertibleProvider(ISerializer serializer) /// 类型转换器集合。 public IEnumerable GetConverters() { + //枚举转换器 yield return EnumTypeConvert; + //简单类型 yield return SimpleTypeConvert; + //guid转换器 + yield return GuidTypeConvert; + //复杂类型 yield return ComplexTypeConvert; } @@ -35,6 +40,12 @@ public IEnumerable GetConverters() #region Private Method + /// + /// 枚举类型转换器 + /// + /// + /// + /// private static object EnumTypeConvert(object instance, Type conversionType) { if (instance == null || !conversionType.GetTypeInfo().IsEnum) @@ -42,6 +53,12 @@ private static object EnumTypeConvert(object instance, Type conversionType) return Enum.Parse(conversionType, instance.ToString()); } + /// + /// 简单类型转换器 + /// + /// + /// + /// private static object SimpleTypeConvert(object instance, Type conversionType) { if (instance is IConvertible && UtilityType.ConvertibleType.GetTypeInfo().IsAssignableFrom(conversionType)) @@ -49,9 +66,36 @@ private static object SimpleTypeConvert(object instance, Type conversionType) return null; } + /// + /// 复杂类型转换器 + /// + /// + /// + /// private object ComplexTypeConvert(object instance, Type conversionType) { - return _serializer.Deserialize(instance, conversionType); + try + { + return _serializer.Deserialize(instance, conversionType); + } + catch + { + return null; + } + } + + /// + /// GUID转换器 + /// + /// + /// + /// + private static object GuidTypeConvert(object instance, Type conversionType) + { + if (instance == null || conversionType != typeof(Guid)) + return null; + Guid.TryParse(instance.ToString(), out Guid result); + return result; } #endregion Private Method diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/Components.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/Components.cs new file mode 100644 index 000000000..bc3204168 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/Components.cs @@ -0,0 +1,30 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Core.CPlatform.Diagnostics +{ + public static class Components + { + public static readonly StringOrIntValue RpcTransport = new StringOrIntValue("RPCTransport"); + + public static readonly StringOrIntValue CacheIntercept = new StringOrIntValue("CacheIntercept"); + + public static readonly StringOrIntValue Intercept = new StringOrIntValue("Intercept"); + } + +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticListenerExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticListenerExtensions.cs new file mode 100644 index 000000000..d470dfc0d --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticListenerExtensions.cs @@ -0,0 +1,47 @@ +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public static class DiagnosticListenerExtensions + { + public const string DiagnosticListenerName = "SurgingDiagnosticListener"; + public const string Prefix = "Surging.Core."; + public const string SurgingBeforeTransport = Prefix +".{0}."+ nameof(WriteTransportBefore); + public const string SurgingAfterTransport= Prefix + ".{0}." + nameof(WriteTransportAfter); + public const string SurgingErrorTransport = Prefix + ".{0}." + nameof(WriteTransportError); + + public static void WriteTransportBefore(this DiagnosticListener diagnosticListener,TransportType transportType, TransportEventData eventData) + { + + if (diagnosticListener.IsEnabled(SurgingBeforeTransport)) + { + eventData.Headers = new TracingHeaders(); + diagnosticListener.Write(string.Format(SurgingBeforeTransport,transportType), eventData); + + } + } + + public static void WriteTransportAfter(this DiagnosticListener diagnosticListener, TransportType transportType, ReceiveEventData eventData) + { + if (diagnosticListener.IsEnabled(SurgingAfterTransport)) + { + eventData.Headers = new TracingHeaders(); + diagnosticListener.Write(string.Format(SurgingAfterTransport, transportType), eventData); + } + } + + public static void WriteTransportError(this DiagnosticListener diagnosticListener, TransportType transportType, TransportErrorEventData eventData) + { + if (diagnosticListener.IsEnabled(SurgingErrorTransport)) + { + eventData.Headers = new TracingHeaders(); + diagnosticListener.Write(string.Format(SurgingErrorTransport, transportType), eventData); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticMessage.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticMessage.cs new file mode 100644 index 000000000..6e5e9d1c6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticMessage.cs @@ -0,0 +1,12 @@ +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class DiagnosticMessage: TransportMessage + { + public string MessageName { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticName.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticName.cs new file mode 100644 index 000000000..678984a20 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticName.cs @@ -0,0 +1,38 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class DiagnosticName : Attribute + { + public string Name { get; } + + public DiagnosticName(string name) + { + Name = name; + } + + public DiagnosticName(string name,TransportType type) + { + Name = string.Format(name,type); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticParameters.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticParameters.cs new file mode 100644 index 000000000..fa7fdee2a --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/DiagnosticParameters.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class DiagnosticParameters + { + public const string PREFIX = "Surging.Core."; + + public const string DiagnosticListenerName = "SurgingDiagnosticListener"; + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/EventData.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/EventData.cs new file mode 100644 index 000000000..b6f290e29 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/EventData.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class EventData + { + public EventData(Guid operationId) + { + OperationId = operationId; + } + + public Guid OperationId { get; set; } + + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ICarrierHeaderCollection.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ICarrierHeaderCollection.cs new file mode 100644 index 000000000..2fde72835 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ICarrierHeaderCollection.cs @@ -0,0 +1,28 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System.Collections.Generic; + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface ICarrierHeaderCollection : IEnumerable> + { + void Add(string key, string value); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IEntrySegmentContextAccessor.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IEntrySegmentContextAccessor.cs new file mode 100644 index 000000000..71600f84e --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IEntrySegmentContextAccessor.cs @@ -0,0 +1,26 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface IEntrySegmentContextAccessor + { + SegmentContext Context { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IExitSegmentContextAccessor.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IExitSegmentContextAccessor.cs new file mode 100644 index 000000000..5c0f3d533 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IExitSegmentContextAccessor.cs @@ -0,0 +1,26 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface IExitSegmentContextAccessor + { + SegmentContext Context { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ILocalSegmentContextAccessor.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ILocalSegmentContextAccessor.cs new file mode 100644 index 000000000..e76d751e3 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ILocalSegmentContextAccessor.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface ILocalSegmentContextAccessor + { + SegmentContext Context { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IParameterResolver.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IParameterResolver.cs new file mode 100644 index 000000000..fbc5f9b6d --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/IParameterResolver.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface IParameterResolver + { + object Resolve(object value); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ITracingContext.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ITracingContext.cs new file mode 100644 index 000000000..c2ebd5819 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ITracingContext.cs @@ -0,0 +1,32 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface ITracingContext + { + SegmentContext CreateEntrySegmentContext(string operationName, ICarrierHeaderCollection carrierHeader); + + SegmentContext CreateLocalSegmentContext(string operationName); + + SegmentContext CreateExitSegmentContext(string operationName, string networkAddress, + ICarrierHeaderCollection carrierHeader = default(ICarrierHeaderCollection)); + + void Release(SegmentContext segmentContext); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ITracingDiagnosticProcessor.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ITracingDiagnosticProcessor.cs new file mode 100644 index 000000000..a44af3bbd --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ITracingDiagnosticProcessor.cs @@ -0,0 +1,26 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public interface ITracingDiagnosticProcessor + { + string ListenerName { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ObjectAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ObjectAttribute.cs new file mode 100644 index 000000000..d7a8bae21 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ObjectAttribute.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class ObjectAttribute: ParameterBinder + { + public Type TargetType { get; set; } + + public override object Resolve(object value) + { + if (TargetType == null || value == null) + { + return value; + } + + if (TargetType == value.GetType()) + { + return value; + } + + if (TargetType.IsInstanceOfType(value)) + { + return value; + } + + return null; + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ParameterBinder.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ParameterBinder.cs new file mode 100644 index 000000000..833fba95c --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ParameterBinder.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public abstract class ParameterBinder : Attribute, IParameterResolver + { + public abstract object Resolve(object value); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ReceiveEventData.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ReceiveEventData.cs new file mode 100644 index 000000000..3777d1d99 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/ReceiveEventData.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class ReceiveEventData : EventData + { + public ReceiveEventData(DiagnosticMessage message): base(Guid.Parse(message.Id)) + { + Message = message; + } + + public TracingHeaders Headers { get; set; } + + public DiagnosticMessage Message { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/RpcMethod.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/RpcMethod.cs new file mode 100644 index 000000000..4f1b3be6a --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/RpcMethod.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public enum RpcMethod + { + Proxy_Rpc, + Json_Rpc + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentContext.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentContext.cs new file mode 100644 index 000000000..5f46b3205 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentContext.cs @@ -0,0 +1,51 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class SegmentContext + { + public UniqueId SegmentId { get;} + + public UniqueId TraceId { get; set; } + + public SegmentSpan Span { get; } + + public int ServiceId { get; } + + public int ServiceInstanceId { get; } + + public bool Sampled { get; } + + public bool IsSizeLimited { get; } = false; + + public SegmentReferenceCollection References { get; } = new SegmentReferenceCollection(); + + public SegmentContext(UniqueId traceId, UniqueId segmentId, bool sampled, int serviceId, int serviceInstanceId, + string operationName, SpanType spanType) + { + TraceId = traceId; + Sampled = sampled; + SegmentId = segmentId; + ServiceId = serviceId; + ServiceInstanceId = serviceInstanceId; + Span = new SegmentSpan(operationName, spanType); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentReference.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentReference.cs new file mode 100644 index 000000000..2a32cf007 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentReference.cs @@ -0,0 +1,71 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +using System.Collections; +using System.Collections.Generic; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class SegmentReference + { + public Reference Reference { get; set; } + + public UniqueId ParentSegmentId { get; set; } + + public int ParentSpanId { get; set; } + + public int ParentServiceInstanceId { get; set; } + + public int EntryServiceInstanceId { get; set; } + + public StringOrIntValue NetworkAddress { get; set; } + + public StringOrIntValue EntryEndpoint { get; set; } + + public StringOrIntValue ParentEndpoint { get; set; } + } + + public enum Reference + { + CrossProcess = 0, + CrossThread = 1 + } + + public class SegmentReferenceCollection : IEnumerable + { + private readonly HashSet _references = new HashSet(); + + public bool Add(SegmentReference reference) + { + return _references.Add(reference); + } + + public IEnumerator GetEnumerator() + { + return _references.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _references.GetEnumerator(); + } + + public int Count => _references.Count; + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentSpan.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentSpan.cs new file mode 100644 index 000000000..541750eb2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentSpan.cs @@ -0,0 +1,190 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class SegmentSpan + { + public int SpanId { get; } = 0; + + public int ParentSpanId { get; } = -1; + + public long StartTime { get; } = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + public long EndTime { get; private set; } + + public StringOrIntValue OperationName { get; } + + public StringOrIntValue Peer { get; set; } + + public SpanType SpanType { get; } + + public SpanLayer SpanLayer { get; set; } + + /// Limiting values. Please see or see + public StringOrIntValue Component { get; set; } + public bool IsError { get; set; } + public TagCollection Tags { get; } = new TagCollection(); + + public LogCollection Logs { get; } = new LogCollection(); + + public SegmentSpan(string operationName, SpanType spanType) + { + OperationName = new StringOrIntValue(operationName); + SpanType = spanType; + } + + public SegmentSpan AddTag(string key, string value) + { + Tags.AddTag(key, value); + return this; + } + + public SegmentSpan AddTag(string key, long value) + { + Tags.AddTag(key, value.ToString()); + return this; + } + + public SegmentSpan AddTag(string key, bool value) + { + Tags.AddTag(key, value.ToString()); + return this; + } + + public void AddLog(params LogEvent[] events) + { + var log = new SpanLog(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), events); + Logs.AddLog(log); + } + + public void Finish() + { + EndTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + } + } + + public class TagCollection : IEnumerable> + { + private readonly Dictionary tags = new Dictionary(); + + internal void AddTag(string key, string value) + { + tags[key] = value; + } + + public IEnumerator> GetEnumerator() + { + return tags.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return tags.GetEnumerator(); + } + } + + public enum SpanType + { + Entry = 0, + Exit = 1, + Local = 2 + } + + public enum SpanLayer + { + DB = 1, + RPC_FRAMEWORK = 2, + HTTP = 3, + MQ = 4, + CACHE = 5 + } + + public class LogCollection : IEnumerable + { + private readonly List _logs = new List(); + + internal void AddLog(SpanLog log) + { + _logs.Add(log); + } + + public IEnumerator GetEnumerator() + { + return _logs.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _logs.GetEnumerator(); + } + } + + public class SpanLog + { + private static readonly Dictionary Empty = new Dictionary(); + public long Timestamp { get; } + + public IReadOnlyDictionary Data { get; } + + public SpanLog(long timestamp, params LogEvent[] events) + { + Timestamp = timestamp; + Data = events?.ToDictionary(x => x.Key, x => x.Value) ?? Empty; + } + } + + public class LogEvent + { + public string Key { get; } + + public string Value { get; } + + public LogEvent(string key, string value) + { + Key = key; + Value = value; + } + + public static LogEvent Event(string value) + { + return new LogEvent("event", value); + } + + public static LogEvent Message(string value) + { + return new LogEvent("message", value); + } + + public static LogEvent ErrorKind(string value) + { + return new LogEvent("error.kind", value); + } + + public static LogEvent ErrorStack(string value) + { + return new LogEvent("stack", value); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentSpanExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentSpanExtensions.cs new file mode 100644 index 000000000..216b0b62c --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/SegmentSpanExtensions.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public static class SegmentSpanExtensions + { + public static void ErrorOccurred(this SegmentSpan span, Exception exception = null) + { + if (span == null) + { + return; + } + + span.IsError = true; + if (exception != null) + { + span.AddLog(LogEvent.Event("error"), + LogEvent.ErrorKind(exception.GetType().FullName), + LogEvent.Message(exception.Message), + LogEvent.ErrorStack(exception.StackTrace)); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/StringOrIntValue.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/StringOrIntValue.cs new file mode 100644 index 000000000..3c1a44846 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/StringOrIntValue.cs @@ -0,0 +1,69 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public struct StringOrIntValue + { + private readonly int _intValue; + private readonly string _stringValue; + + public StringOrIntValue(int value) + { + _intValue = value; + _stringValue = null; + } + + public bool HasValue => HasIntValue || HasStringValue; + + public bool HasIntValue => _intValue != 0; + + public bool HasStringValue => _stringValue != null; + + public StringOrIntValue(string value) + { + _intValue = 0; + _stringValue = value; + } + + public StringOrIntValue(int intValue, string stringValue) + { + _intValue = intValue; + _stringValue = stringValue; + } + + public int GetIntValue() => _intValue; + + public string GetStringValue() => _stringValue; + + public (string, int) GetValue() + { + return (_stringValue, _intValue); + } + + public override string ToString() + { + if (HasIntValue) return _intValue.ToString(); + return _stringValue; + } + + public static implicit operator StringOrIntValue(string value) => new StringOrIntValue(value); + public static implicit operator StringOrIntValue(int value) => new StringOrIntValue(value); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/Tags.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/Tags.cs new file mode 100644 index 000000000..af6eddf61 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/Tags.cs @@ -0,0 +1,34 @@ +/* + * Licensed to the Surging.Apm.Skywalking.Abstractions under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The Surging.Apm.Skywalking.Abstractions licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Surging.Core.CPlatform.Diagnostics +{ + public static class Tags + { + public static readonly string RPC_METHOD = "rpc.method"; + public static readonly string RPC_PARAMETERS = "rpc.parameters"; + public static readonly string RPC_LOCAL_ADDRESS = "rpc.local.address"; + public static readonly string REST_METHOD = "rest.method"; + public static readonly string REST_PARAMETERS = "rpc.parameters"; + public static readonly string REST_LOCAL_ADDRESS = "rest.local.address"; + public static readonly string MQTT_METHOD = "method"; + public static readonly string MQTT_CLIENT_ID = "mqtt.client.id"; + public static readonly string MQTT_PARAMETERS = "mqtt.parameters"; + public static readonly string MQTT_BROKER_ADDRESS = "mqtt.broker.address"; + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TracingHeaders.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TracingHeaders.cs new file mode 100644 index 000000000..3084de90f --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TracingHeaders.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class TracingHeaders : IEnumerable> + { + private List> _dataStore = new List>(); + + public IEnumerator> GetEnumerator() + { + return _dataStore.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(string name, string value) + { + _dataStore.Add(new KeyValuePair(name, value)); + } + + public bool Contains(string name) + { + return _dataStore != null && _dataStore.Any(x => x.Key == name); + } + + public void Remove(string name) + { + _dataStore?.RemoveAll(x => x.Key == name); + } + + public void Cleaar() + { + _dataStore?.Clear(); + } + } +} + + \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportErrorEventData.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportErrorEventData.cs new file mode 100644 index 000000000..97764a39e --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportErrorEventData.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class TransportErrorEventData : EventData + { + public TransportErrorEventData(DiagnosticMessage message,Exception ex) + : base(Guid.Parse(message.Id)) + { + Message = message; + Exception = ex; + } + + + public Exception Exception { get; set; } + + public TracingHeaders Headers { get; set; } + + public DiagnosticMessage Message { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportEventData.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportEventData.cs new file mode 100644 index 000000000..af5cae558 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportEventData.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public class TransportEventData : EventData + { + public TransportEventData(DiagnosticMessage message, string method, string traceId, string address) + : base(Guid.Parse(message.Id)) + { + Message = message; + RemoteAddress = address; + Method = method; + TraceId = traceId; + } + + public string TraceId { get; set; } + + public string Method { get; set; } + + public string RemoteAddress { get; set; } + + public TracingHeaders Headers { get; set; } + + public DiagnosticMessage Message { get; set; } + + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportType.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportType.cs new file mode 100644 index 000000000..c553a73ab --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/TransportType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Diagnostics +{ + public enum TransportType + { + Rpc, + Rest, + Mqtt, + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/UniqueId.cs b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/UniqueId.cs new file mode 100644 index 000000000..7085f5714 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Diagnostics/UniqueId.cs @@ -0,0 +1,63 @@ +/* + * Licensed to the SkyAPM under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The SkyAPM licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; + + +namespace Surging.Core.CPlatform.Diagnostics +{ + public struct UniqueId : IEquatable + { + public long Part1 { get; } + + public long Part2 { get; } + + public long Part3 { get; } + + public UniqueId(long part1, long part2, long part3) + { + Part1 = part1; + Part2 = part2; + Part3 = part3; + } + + public override string ToString() => $"{Part1}.{Part2}.{Part3}"; + + public bool Equals(UniqueId other) => + Part1 == other.Part1 && Part2 == other.Part2 && Part3 == other.Part3; + + public override bool Equals(object obj) => + obj is UniqueId other && Equals(other); + + public override int GetHashCode() + { + unchecked + { + var hashCode = Part1.GetHashCode(); + hashCode = (hashCode * 397) ^ Part2.GetHashCode(); + hashCode = (hashCode * 397) ^ Part3.GetHashCode(); + return hashCode; + } + } + + public static bool operator ==(UniqueId left, UniqueId right) => left.Equals(right); + + public static bool operator !=(UniqueId left, UniqueId right) => !left.Equals(right); + } +} + diff --git a/src/Surging.Core/Surging.Core.CPlatform/Engines/IServiceEngineBuilder.cs b/src/Surging.Core/Surging.Core.CPlatform/Engines/IServiceEngineBuilder.cs index f00c74071..ce84c879a 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Engines/IServiceEngineBuilder.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Engines/IServiceEngineBuilder.cs @@ -8,5 +8,7 @@ namespace Surging.Core.CPlatform.Engines public interface IServiceEngineBuilder { void Build(ContainerBuilder serviceContainer); + + ValueTuple,IEnumerable>? ReBuild(ContainerBuilder serviceContainer); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Engines/Implementation/DefaultServiceEngineBuilder.cs b/src/Surging.Core/Surging.Core.CPlatform/Engines/Implementation/DefaultServiceEngineBuilder.cs index 12732d591..b4dd38421 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Engines/Implementation/DefaultServiceEngineBuilder.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Engines/Implementation/DefaultServiceEngineBuilder.cs @@ -5,6 +5,7 @@ using System.Text; using System.Linq; using Microsoft.Extensions.Logging; +using System.Reflection; namespace Surging.Core.CPlatform.Engines.Implementation { @@ -12,6 +13,8 @@ public class DefaultServiceEngineBuilder : IServiceEngineBuilder { private readonly VirtualPathProviderServiceEngine _serviceEngine; private readonly ILogger _logger; + private readonly Dictionary _dic = new Dictionary(); + private DateTime _lastBuildTime=DateTime.Now; public DefaultServiceEngineBuilder(IServiceEngine serviceEngine, ILogger logger) { _serviceEngine = serviceEngine as VirtualPathProviderServiceEngine; @@ -33,6 +36,7 @@ public void Build(ContainerBuilder serviceContainer) serviceBuilder.RegisterServices(paths); serviceBuilder.RegisterRepositories(paths); serviceBuilder.RegisterServiceBus(paths); + serviceBuilder.RegisterInstanceByConstraint(paths); } if (_serviceEngine.ComponentServiceLocationFormats != null) { @@ -42,9 +46,49 @@ public void Build(ContainerBuilder serviceContainer) _logger.LogDebug($"准备加载路径${string.Join(',', paths)}下的组件模块。"); serviceBuilder.RegisterModules(paths); } + _lastBuildTime = DateTime.Now; } } + public ValueTuple, IEnumerable>? ReBuild(ContainerBuilder serviceContainer) + { + ValueTuple, IEnumerable>? result = null ; + var serviceBuilder = new ServiceBuilder(serviceContainer); + var virtualPaths = new List(); + string rootPath = string.IsNullOrEmpty(AppConfig.ServerOptions.RootPath) ? + AppContext.BaseDirectory : AppConfig.ServerOptions.RootPath; + if (_serviceEngine != null) + { + if (_serviceEngine.ModuleServiceLocationFormats != null) + { + var paths = GetPaths(_serviceEngine.ModuleServiceLocationFormats); + paths = paths?.Where(p => (Directory.GetLastWriteTime(Path.Combine(rootPath,p)) - _lastBuildTime).TotalSeconds > 0).ToArray(); + if (paths == null || paths.Length==0) return null; + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备加载路径${string.Join(',', paths)}下的业务模块。"); + + + serviceBuilder.RegisterServices(paths); + serviceBuilder.RegisterRepositories(paths); + serviceBuilder.RegisterServiceBus(paths); + result = new ValueTuple, IEnumerable>(serviceBuilder.GetInterfaceService(paths), serviceBuilder.GetDataContractName(paths)); + } + if (_serviceEngine.ComponentServiceLocationFormats != null) + { + var paths = GetPaths(_serviceEngine.ComponentServiceLocationFormats); + paths = paths?.Where(p => (Directory.GetLastWriteTime(p) - _lastBuildTime).TotalSeconds > 0).ToArray(); + if (paths != null && paths.Length > 0) + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备加载路径${string.Join(',', paths)}下的组件模块。"); + serviceBuilder.RegisterModules(paths); + } + } + _lastBuildTime = DateTime.Now; + } + return result; + } + private string [] GetPaths(params string [] virtualPaths) { var directories = new List(virtualPaths.Where(p=>!string.IsNullOrEmpty(p))) ; diff --git a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/EventContext.cs b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/EventContext.cs new file mode 100644 index 000000000..298a9177b --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/EventContext.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.EventBus.Events +{ + public class EventContext: IntegrationEvent + { + + public object Content { get; set; } + + public long Count { get; set; } + + public string Type { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IIntegrationEventHandler.cs b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IIntegrationEventHandler.cs index 9924b41f4..2ded3a2fd 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IIntegrationEventHandler.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IIntegrationEventHandler.cs @@ -10,6 +10,16 @@ public interface IIntegrationEventHandler : IIntegrationEv Task Handle(TIntegrationEvent @event); } + public abstract class BaseIntegrationEventHandler : IIntegrationEventHandler + { + public abstract Task Handle(TIntegrationEvent @event); + + public virtual async Task Handled(EventContext context) + { + await Task.CompletedTask; + } + } + public interface IIntegrationEventHandler { } diff --git a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IntegrationEvent.cs b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IntegrationEvent.cs index b0aff10b9..4cdf6b9d7 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IntegrationEvent.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Events/IntegrationEvent.cs @@ -12,6 +12,12 @@ public IntegrationEvent() CreationDate = DateTime.UtcNow; } + public IntegrationEvent(IntegrationEvent integrationEvent) + { + Id = integrationEvent.Id; + CreationDate = integrationEvent.CreationDate; + } + public Guid Id { get; } public DateTime CreationDate { get; } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/EventBus/ISubscriptionAdapt.cs b/src/Surging.Core/Surging.Core.CPlatform/EventBus/ISubscriptionAdapt.cs index c01896cd6..f7adefd76 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/EventBus/ISubscriptionAdapt.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/EventBus/ISubscriptionAdapt.cs @@ -7,5 +7,7 @@ namespace Surging.Core.CPlatform.EventBus public interface ISubscriptionAdapt { void SubscribeAt(); + + void Unsubscribe(); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Implementation/IEventBus.cs b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Implementation/IEventBus.cs index b182df949..005fd765d 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/EventBus/Implementation/IEventBus.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/EventBus/Implementation/IEventBus.cs @@ -13,5 +13,7 @@ void Unsubscribe() where TH : IIntegrationEventHandler; void Publish(IntegrationEvent @event); + + event EventHandler OnShutdown; } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/EventBus/InMemoryEventBusSubscriptionsManager.cs b/src/Surging.Core/Surging.Core.CPlatform/EventBus/InMemoryEventBusSubscriptionsManager.cs index 83266580f..fdb930561 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/EventBus/InMemoryEventBusSubscriptionsManager.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/EventBus/InMemoryEventBusSubscriptionsManager.cs @@ -74,7 +74,7 @@ private void RaiseOnEventRemoved(string eventName,string consumerName) var handler = OnEventRemoved; if (handler != null) { - OnEventRemoved(this,new ValueTuple(consumerName, eventName)); + handler(this,new ValueTuple(consumerName, eventName)); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Exceptions/RegisterConnectionException.cs b/src/Surging.Core/Surging.Core.CPlatform/Exceptions/RegisterConnectionException.cs new file mode 100644 index 000000000..f677ef482 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Exceptions/RegisterConnectionException.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Exceptions +{ + public class RegisterConnectionException : CPlatformException + { + public RegisterConnectionException(string message, Exception innerException = null) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Exceptions/ValidateException.cs b/src/Surging.Core/Surging.Core.CPlatform/Exceptions/ValidateException.cs new file mode 100644 index 000000000..64ce5f3ac --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Exceptions/ValidateException.cs @@ -0,0 +1,19 @@ +using System; + +namespace Surging.Core.CPlatform.Exceptions +{ + /// + /// Model、DTO等对象校验异常 + /// + public class ValidateException : CPlatformException + { + /// + /// 初始构造函数 + /// + /// 异常信息 + /// 内部异常 + public ValidateException(string message, Exception innerException = null) : base(message, innerException) + { + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Filters/IActionFilter.cs b/src/Surging.Core/Surging.Core.CPlatform/Filters/IActionFilter.cs new file mode 100644 index 000000000..fa0c47a47 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Filters/IActionFilter.cs @@ -0,0 +1,16 @@ +using Surging.Core.CPlatform.Filters.Implementation; +using Surging.Core.CPlatform.Routing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Filters +{ + public interface IActionFilter : IFilter + { + Task OnActionExecutingAsync(ServiceRouteContext actionExecutedContext, CancellationToken cancellationToken); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Filters/Implementation/ActionFilterAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Filters/Implementation/ActionFilterAttribute.cs new file mode 100644 index 000000000..65ebf8871 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Filters/Implementation/ActionFilterAttribute.cs @@ -0,0 +1,18 @@ +using Surging.Core.CPlatform.Routing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Filters.Implementation +{ + public class ActionFilterAttribute : BaseActionFilterAttribute + { + public override Task OnActionExecutingAsync(ServiceRouteContext actionExecutedContext, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Filters/Implementation/BaseActionFilterAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Filters/Implementation/BaseActionFilterAttribute.cs new file mode 100644 index 000000000..fdbc5f927 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Filters/Implementation/BaseActionFilterAttribute.cs @@ -0,0 +1,16 @@ +using Surging.Core.CPlatform.Routing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Filters.Implementation +{ + public abstract class BaseActionFilterAttribute : FilterAttribute, IActionFilter, IFilter + { + public abstract Task OnActionExecutingAsync(ServiceRouteContext actionExecutedContext, CancellationToken cancellationToken); + + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/HashAlgorithms/ConsistentHash.cs b/src/Surging.Core/Surging.Core.CPlatform/HashAlgorithms/ConsistentHash.cs index 5576384df..ea8574321 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/HashAlgorithms/ConsistentHash.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/HashAlgorithms/ConsistentHash.cs @@ -45,23 +45,7 @@ public int VirtualNodeReplicationFactor get { return _virtualNodeReplicationFactor; } } #endregion - - /// - /// 初始化节点服务器 - /// - /// 节点 - /// - /// 创建:范亮 - /// 日期:2016/4/2 - /// - public void Initialize(IEnumerable nodes) - { - foreach (var node in nodes) - { - AddNode(node); - } - _nodeKeysInRing = _ring.Keys.ToArray(); - } + /// /// 添加节点 @@ -71,9 +55,9 @@ public void Initialize(IEnumerable nodes) /// 创建:范亮 /// 日期:2016/4/2 /// - public void Add(T node) + public void Add(T node,string value) { - AddNode(node); + AddNode(node,value); _nodeKeysInRing = _ring.Keys.ToArray(); } @@ -85,7 +69,7 @@ public void Add(T node) /// 创建:范亮 /// 日期:2016/4/2 /// - public void Remove(T node) + public void Remove(string node) { RemoveNode(node); _nodeKeysInRing = _ring.Keys.ToArray(); @@ -115,11 +99,11 @@ public T GetItemNode(string item) /// 创建:范亮 /// 日期:2016/4/2 /// - private void AddNode(T node) + private void AddNode(T node,string value) { for (var i = 0; i < _virtualNodeReplicationFactor; i++) { - var hashOfVirtualNode = _hashAlgorithm.Hash(node.GetHashCode().ToString(CultureInfo.InvariantCulture) + i); + var hashOfVirtualNode = _hashAlgorithm.Hash(value.ToString(CultureInfo.InvariantCulture) + i); _ring[hashOfVirtualNode] = node; } } @@ -132,11 +116,11 @@ private void AddNode(T node) /// 创建:范亮 /// 日期:2016/4/2 /// - private void RemoveNode(T node) + private void RemoveNode(string value) { for (var i = 0; i < _virtualNodeReplicationFactor; i++) { - var hashOfVirtualNode = _hashAlgorithm.Hash(node.GetHashCode().ToString() + i); + var hashOfVirtualNode = _hashAlgorithm.Hash(value.ToString() + i); _ring.Remove(hashOfVirtualNode); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Ioc/IServiceBehavior.cs b/src/Surging.Core/Surging.Core.CPlatform/Ioc/IServiceBehavior.cs index 1e85b50cf..6a9492e01 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Ioc/IServiceBehavior.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Ioc/IServiceBehavior.cs @@ -1,10 +1,15 @@ -using System; +using Surging.Core.CPlatform.Messages; +using System; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace Surging.Core.CPlatform.Ioc { - public interface IServiceBehavior + public delegate Task ServerReceivedDelegate(TransportMessage message); + public interface IServiceBehavior { + public string MessageId { get; } + event ServerReceivedDelegate Received; } } diff --git a/samples/Common/DTO.Core/BaseSearchCriteriaDto.cs b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ISingleInstance.cs similarity index 52% rename from samples/Common/DTO.Core/BaseSearchCriteriaDto.cs rename to src/Surging.Core/Surging.Core.CPlatform/Ioc/ISingleInstance.cs index a9e983098..624f33439 100644 --- a/samples/Common/DTO.Core/BaseSearchCriteriaDto.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ISingleInstance.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace DTO.Core +namespace Surging.Core.CPlatform.Ioc { - public abstract class BaseSearchCriteriaDto : BaseDto + public interface ISingleInstance { - } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Ioc/ISingletonDependency.cs b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ISingletonDependency.cs new file mode 100644 index 000000000..db67b9ca0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ISingletonDependency.cs @@ -0,0 +1,7 @@ + +namespace Surging.Core.CPlatform.Ioc +{ + public interface ISingletonDependency + { + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Ioc/ITransientDependency.cs b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ITransientDependency.cs new file mode 100644 index 000000000..507ac5440 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ITransientDependency.cs @@ -0,0 +1,7 @@ + +namespace Surging.Core.CPlatform.Ioc +{ + public interface ITransientDependency + { + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Ioc/ServiceBase.cs b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ServiceBase.cs index 937910c29..978eb75c1 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Ioc/ServiceBase.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Ioc/ServiceBase.cs @@ -1,12 +1,44 @@ -using Surging.Core.CPlatform.Utilities; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Utilities; using System; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace Surging.Core.CPlatform.Ioc { public abstract class ServiceBase: IServiceBehavior { + private ServerReceivedDelegate received; + public event ServerReceivedDelegate Received + { + add + { + if (received == null) + { + received += value; + } + } + remove + { + received -= value; + } + } + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await received(message); + } public virtual T GetService() where T : class { return ServiceLocator.GetService(); diff --git a/src/Surging.Core/Surging.Core.CPlatform/Logging/ConsoleLogger.cs b/src/Surging.Core/Surging.Core.CPlatform/Logging/ConsoleLogger.cs deleted file mode 100644 index 2e2c8a124..000000000 --- a/src/Surging.Core/Surging.Core.CPlatform/Logging/ConsoleLogger.cs +++ /dev/null @@ -1,75 +0,0 @@ -/*using System; - -namespace Surging.Core.CPlatform.Logging -{ - public class ConsoleLogger : ConsoleLogger, ILogger - { - } - - public class ConsoleLogger : ILogger - { - #region Implementation of ILogger - - /// - /// 判断日志记录器是否开启。 - /// - /// 日志等级。 - /// 如果开启返回true,否则返回false。 - public bool IsEnabled(LogLevel level) - { - return (int)level > 2; - } - - /// - /// 记录日志。 - /// - /// 日志等级。 - /// 消息。 - /// 异常。 - /// 任务。 - public void Log(LogLevel level, string message, Exception exception = null) - { - Console.ResetColor(); - var color = Console.ForegroundColor; - - switch (level) - { - case LogLevel.Trace: - color = ConsoleColor.DarkGray; - break; - - case LogLevel.Debug: - color = ConsoleColor.Gray; - break; - - case LogLevel.Information: - color = ConsoleColor.DarkBlue; - break; - - case LogLevel.Warning: - color = ConsoleColor.Yellow; - break; - - case LogLevel.Error: - color = ConsoleColor.DarkRed; - break; - - case LogLevel.Fatal: - color = ConsoleColor.Red; - break; - } - - Console.ForegroundColor = color; - - Console.WriteLine($"level:{level}"); - Console.WriteLine($"message:{message}"); - if (exception != null) - Console.WriteLine($"exception:{exception}"); - Console.WriteLine("========================================"); - - Console.ResetColor(); - } - - #endregion Implementation of ILogger - } -}*/ \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Logging/ILogger.cs b/src/Surging.Core/Surging.Core.CPlatform/Logging/ILogger.cs deleted file mode 100644 index 285fb38b0..000000000 --- a/src/Surging.Core/Surging.Core.CPlatform/Logging/ILogger.cs +++ /dev/null @@ -1,142 +0,0 @@ -/*using System; - -namespace Surging.Core.CPlatform.Logging -{ - /// - /// 日志等级。 - /// - public enum LogLevel - { - /// - /// 追踪。 - /// - Trace = 0, - - /// - /// 调试。 - /// - Debug = 1, - - /// - /// 信息。 - /// - Information = 2, - - /// - /// 警告。 - /// - Warning = 3, - - /// - /// 错误。 - /// - Error = 4, - - /// - /// 致命错误。 - /// - Fatal = 5 - } - - /// - /// 一个抽象的日志记录器。 - /// - /// 日志记录器类型。 - public interface ILogger : ILogger - { - } - - /// - /// 一个抽象的日志记录器。 - /// - public interface ILogger - { - /// - /// 判断日志记录器是否开启。 - /// - /// 日志等级。 - /// 如果开启返回true,否则返回false。 - bool IsEnabled(LogLevel level); - - /// - /// 记录日志。 - /// - /// 日志等级。 - /// 消息。 - /// 异常。 - /// 任务。 - void Log(LogLevel level, string message, Exception exception = null); - } - - /// - /// 日志记录器扩展。 - /// - public static class LoggerExtensions - { - /// - /// 追踪。 - /// - /// 日志记录器。 - /// 消息。 - /// 异常信息。 - public static void Trace(this ILogger logger, string message, Exception exception = null) - { - logger.Log(LogLevel.Trace, message, exception); - } - - /// - /// 调试。 - /// - /// 日志记录器。 - /// 消息。 - /// 异常信息。 - public static void Debug(this ILogger logger, string message, Exception exception = null) - { - logger.Log(LogLevel.Debug, message, exception); - } - - /// - /// 信息。 - /// - /// 日志记录器。 - /// 消息。 - /// 异常信息。 - public static void Information(this ILogger logger, string message, Exception exception = null) - { - logger.Log(LogLevel.Information, message, exception); - } - - /// - /// 警告。 - /// - /// 日志记录器。 - /// 消息。 - /// 异常信息。 - public static void Warning(this ILogger logger, string message, Exception exception = null) - { - logger.Log(LogLevel.Warning, message, exception); - } - - /// - /// 错误。 - /// - /// 日志记录器。 - /// 消息。 - /// 异常信息。 - public static void Error(this ILogger logger, string message, Exception exception = null) - { - logger.Log(LogLevel.Error, message, exception); - } - - /// - /// 失败。 - /// - /// 日志记录器。 - /// 消息。 - /// 异常信息。 - public static void Fatal(this ILogger logger, string message, Exception exception = null) - { - logger.Log(LogLevel.Fatal, message, exception); - } - } -}*/ \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Messages/HttpMessage.cs b/src/Surging.Core/Surging.Core.CPlatform/Messages/HttpMessage.cs index 90fd57de8..29bc708bb 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Messages/HttpMessage.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Messages/HttpMessage.cs @@ -7,10 +7,13 @@ namespace Surging.Core.CPlatform.Messages public class HttpMessage { public string RoutePath { get; set; } - + + public string ServiceKey { get; set; } public IDictionary Parameters { get; set; } + + public IDictionary Attachments { get; set; } } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Messages/MessagePackTransportMessageType.cs b/src/Surging.Core/Surging.Core.CPlatform/Messages/MessagePackTransportMessageType.cs index 99dc9b30a..bf2ae6498 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Messages/MessagePackTransportMessageType.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Messages/MessagePackTransportMessageType.cs @@ -14,5 +14,7 @@ public class MessagePackTransportMessageType public static string httpMessageTypeName = typeof(HttpMessage).FullName; public static string httpResultMessageTypeName = typeof(HttpResultMessage).FullName; + + public static string reactiveResultMessageTypeName = typeof(ReactiveResultMessage).FullName; } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Messages/ReactiveResultMessage.cs b/src/Surging.Core/Surging.Core.CPlatform/Messages/ReactiveResultMessage.cs new file mode 100644 index 000000000..fb31c25b6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Messages/ReactiveResultMessage.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Messages +{ + public class ReactiveResultMessage + { + /// + /// 异常消息。 + /// + public string ExceptionMessage { get; set; } + + /// + /// 状态码 + /// + public int StatusCode { get; set; } = 200; + /// + /// 结果内容。 + /// + public object Result { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Messages/TransportMessage.cs b/src/Surging.Core/Surging.Core.CPlatform/Messages/TransportMessage.cs index 8c4eccc7e..8c896c19d 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Messages/TransportMessage.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Messages/TransportMessage.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace Surging.Core.CPlatform.Messages { @@ -11,7 +12,7 @@ public class TransportMessage public TransportMessage() { } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public TransportMessage(object content) { if (content == null) @@ -21,6 +22,18 @@ public TransportMessage(object content) ContentType = content.GetType().FullName; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TransportMessage(string id, object content) + { + if (content == null) + throw new ArgumentNullException(nameof(content)); + + Id = id; + Content = content; + ContentType = content.GetType().FullName; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public TransportMessage(object content, string fullName) { if (content == null) @@ -49,6 +62,7 @@ public TransportMessage(object content, string fullName) /// 是否调用消息。 /// /// 如果是则返回true,否则返回false。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsInvokeMessage() { return ContentType == MessagePackTransportMessageType.remoteInvokeMessageTypeName; @@ -58,16 +72,25 @@ public bool IsInvokeMessage() /// 是否是调用结果消息。 /// /// 如果是则返回true,否则返回false。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsInvokeResultMessage() { return ContentType == MessagePackTransportMessageType.remoteInvokeResultMessageTypeName; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsReactiveMessage() + { + return ContentType == MessagePackTransportMessageType.reactiveResultMessageTypeName; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsHttpMessage() { return ContentType == MessagePackTransportMessageType.httpMessageTypeName; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsHttpResultMessage() { return ContentType == MessagePackTransportMessageType.httpResultMessageTypeName; @@ -77,7 +100,8 @@ public bool IsHttpResultMessage() /// 获取内容。 /// /// 内容类型。 - /// 内容实例。 + /// 内容实例。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public T GetContent() { return (T)Content; @@ -87,7 +111,7 @@ public T GetContent() /// 创建一个调用传输消息。 /// /// 调用实例。 - /// 调用传输消息。 + /// 调用传输消息。 public static TransportMessage CreateInvokeMessage(RemoteInvokeMessage invokeMessage) { return new TransportMessage(invokeMessage, MessagePackTransportMessageType.remoteInvokeMessageTypeName) @@ -101,7 +125,7 @@ public static TransportMessage CreateInvokeMessage(RemoteInvokeMessage invokeMes /// /// 消息Id。 /// 调用结果实例。 - /// 调用结果传输消息。 + /// 调用结果传输消息。 public static TransportMessage CreateInvokeResultMessage(string id, RemoteInvokeResultMessage invokeResultMessage) { return new TransportMessage(invokeResultMessage, MessagePackTransportMessageType.remoteInvokeResultMessageTypeName) diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/AbstractModule.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/AbstractModule.cs index 887d8df3b..0a2bdac68 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/AbstractModule.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/AbstractModule.cs @@ -10,29 +10,47 @@ namespace Surging.Core.CPlatform.Module { - public abstract class AbstractModule : Autofac.Module + public abstract class AbstractModule : Autofac.Module,IDisposable { #region 实例属性 - + /// + /// 容器创建包装属性 + /// public ContainerBuilderWrapper Builder { get; set; } + /// + /// 唯一标识guid + /// public Guid Identifier { get; set; } - + /// + /// 模块名 + /// public string ModuleName { get; set; } - + /// + /// 类型名 + /// public string TypeName { get; set; } - + /// + /// 标题 + /// public string Title { get; set; } - + /// + /// 是否可用(控制模块是否加载) + /// public bool Enable { get; set; } = true; - + /// + /// 描述 + /// public string Description { get; set; } + /// + /// 组件 + /// public List Components { get; set; } #endregion @@ -47,19 +65,26 @@ public AbstractModule() #region 实例方法 - public virtual void Initialize(CPlatformContainer serviceProvider) + public virtual void Initialize(AppModuleContext serviceProvider) { + Dispose(); } - + /// + /// 重写autofac load方法 + /// 判断组件是否可用,并注册模块组件 + /// + /// protected override void Load(ContainerBuilder builder) { try { base.Load(builder); Builder = new ContainerBuilderWrapper(builder); - if (Enable) + if (Enable)//如果可用 { + //注册创建容器 RegisterBuilder(Builder); + //注册组件 RegisterComponents(Builder); } @@ -82,13 +107,19 @@ internal virtual void RegisterComponents(ContainerBuilderWrapper builder) { Components.ForEach(component => { + //服务类型 Type serviceType = Type.GetType(component.ServiceType, true); + //实现类型 Type implementType = Type.GetType(component.ImplementType, true); + //组件生命周期 switch (component.LifetimeScope) { + //依赖创建 case LifetimeScope.InstancePerDependency: + //如果是泛型 if (serviceType.GetTypeInfo().IsGenericType || implementType.GetTypeInfo().IsGenericType) { + //注册泛型 builder.RegisterGeneric(implementType).As(serviceType).InstancePerDependency(); } else @@ -96,7 +127,7 @@ internal virtual void RegisterComponents(ContainerBuilderWrapper builder) builder.RegisterType(implementType).As(serviceType).InstancePerDependency(); } break; - case LifetimeScope.SingleInstance: + case LifetimeScope.SingleInstance://单例 if (serviceType.GetTypeInfo().IsGenericType || implementType.GetTypeInfo().IsGenericType) { builder.RegisterGeneric(implementType).As(serviceType).SingleInstance(); @@ -106,7 +137,7 @@ internal virtual void RegisterComponents(ContainerBuilderWrapper builder) builder.RegisterType(implementType).As(serviceType).SingleInstance(); } break; - default: + default://默认依赖创建 if (serviceType.GetTypeInfo().IsGenericType || implementType.GetTypeInfo().IsGenericType) { builder.RegisterGeneric(implementType).As(serviceType).InstancePerDependency(); @@ -121,7 +152,9 @@ internal virtual void RegisterComponents(ContainerBuilderWrapper builder) }); } } - + /// + /// 验证模块 + /// public virtual void ValidateModule() { if (this.Identifier == Guid.Empty || string.IsNullOrEmpty(this.ModuleName) || string.IsNullOrEmpty(this.TypeName) @@ -159,6 +192,10 @@ public override string ToString() return sb.ToString(); } + public virtual void Dispose() + { + } + #endregion } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/AppModuleContext.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/AppModuleContext.cs new file mode 100644 index 000000000..2f584b55b --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/AppModuleContext.cs @@ -0,0 +1,25 @@ +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Module +{ + public class AppModuleContext + { + public AppModuleContext(List modules, + string[] virtualPaths, + CPlatformContainer serviceProvoider) + { + Modules = Check.NotNull(modules, nameof(modules)); + VirtualPaths = Check.NotNull(virtualPaths, nameof(virtualPaths)); + ServiceProvoider = Check.NotNull(serviceProvoider, nameof(serviceProvoider)); + } + + public List Modules { get; } + + public string[] VirtualPaths { get; } + + public CPlatformContainer ServiceProvoider { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/BusinessModule.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/BusinessModule.cs index 7be719570..2bfa9b726 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/BusinessModule.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/BusinessModule.cs @@ -9,7 +9,7 @@ namespace Surging.Core.CPlatform.Module /// public class BusinessModule : AbstractModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext serviceProvider) { base.Initialize(serviceProvider); } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/EchoService.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/EchoService.cs index 134fcf0da..c819b8484 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/EchoService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/EchoService.cs @@ -2,6 +2,7 @@ using Surging.Core.CPlatform.HashAlgorithms; using Surging.Core.CPlatform.Ioc; using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Runtime.Client; using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors; using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation; using System.Threading.Tasks; @@ -13,14 +14,19 @@ public class EchoService : ServiceBase, IEchoService private readonly IHashAlgorithm _hashAlgorithm; private readonly IAddressSelector _addressSelector; private readonly IServiceRouteProvider _serviceRouteProvider; - public EchoService(IHashAlgorithm hashAlgorithm, IServiceRouteProvider serviceRouteProvider, CPlatformContainer container) + private readonly IServiceHeartbeatManager _serviceHeartbeatManager; + + public EchoService(IHashAlgorithm hashAlgorithm, IServiceRouteProvider serviceRouteProvider, + CPlatformContainer container, IServiceHeartbeatManager serviceHeartbeatManager) { _hashAlgorithm = hashAlgorithm; _addressSelector =container.GetInstances(AddressSelectorMode.HashAlgorithm.ToString()); _serviceRouteProvider = serviceRouteProvider; + + _serviceHeartbeatManager = serviceHeartbeatManager; } - public async Task Locate(string routePath,string key) + public async Task Locate(string key,string routePath) { var route= await _serviceRouteProvider.SearchRoute(routePath); AddressModel result = new IpAddressModel(); @@ -30,10 +36,12 @@ public async Task Locate(string routePath,string key) { Address = route.Address, Descriptor = route.ServiceDescriptor, - HashCode = _hashAlgorithm.Hash(key) + Item = key, }); - } - return result.ToString(); + _serviceHeartbeatManager.AddWhitelist(route.ServiceDescriptor.Id); + } + var ipAddress = result as IpAddressModel; + return ipAddress; } } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/EnginePartModule.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/EnginePartModule.cs index 740ea9f3e..d034dfe5a 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/EnginePartModule.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/EnginePartModule.cs @@ -7,11 +7,16 @@ namespace Surging.Core.CPlatform.Module { public class EnginePartModule : AbstractModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } - + + public override void Dispose() + { + base.Dispose(); + } + protected virtual void RegisterServiceBuilder(IServiceBuilder builder) { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/IEchoService.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/IEchoService.cs index 48008d7a4..175b0d258 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/IEchoService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/IEchoService.cs @@ -1,5 +1,8 @@ -using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation; using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using Surging.Core.CPlatform.Support.Attributes; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Module @@ -7,6 +10,7 @@ namespace Surging.Core.CPlatform.Module [ServiceBundle("")] public interface IEchoService: IServiceKey { - Task Locate(string routePath, string key); + [Command(ShuntStrategy = AddressSelectorMode.HashAlgorithm)] + Task Locate(string key,string routePath); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/IModuleProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/IModuleProvider.cs index 09c77f293..a6608077a 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/IModuleProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/IModuleProvider.cs @@ -6,6 +6,9 @@ namespace Surging.Core.CPlatform.Module { public interface IModuleProvider { + List Modules { get; } + + string[] VirtualPaths { get; } void Initialize(); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/ModuleProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/ModuleProvider.cs index 1e66fd73b..d2c9e6d31 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/ModuleProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/ModuleProvider.cs @@ -2,31 +2,55 @@ using Surging.Core.CPlatform.Engines; using System; using System.Collections.Generic; -using System.Text; +using System.Linq; namespace Surging.Core.CPlatform.Module { public class ModuleProvider: IModuleProvider { private readonly List _modules; + private readonly string[] _virtualPaths; private readonly CPlatformContainer _serviceProvoider; private readonly ILogger _logger; + /// + /// 模块提供器 + /// + /// + /// + /// public ModuleProvider(List modules, + string[] virtualPaths, ILogger logger, CPlatformContainer serviceProvoider) { _modules = modules; + _virtualPaths = virtualPaths; _serviceProvoider = serviceProvoider; _logger = logger; } - public void Initialize() + public List Modules { get => _modules; } + + public string[] VirtualPaths { get => _virtualPaths; } + + public virtual void Initialize() { _modules.ForEach(p => { - if (p.Enable) - p.Initialize(_serviceProvoider); + try + { + Type[] types = { typeof(SystemModule), typeof(BusinessModule), typeof(EnginePartModule), typeof(AbstractModule) }; + if (p.Enable) + p.Initialize(new AppModuleContext(_modules, _virtualPaths, _serviceProvoider)); + var type = p.GetType().BaseType; + if (types.Any(ty => ty == type)) + p.Dispose(); + } + catch(Exception ex) + { + throw ex; + } }); WriteLog(); } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/RegistrationExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/RegistrationExtensions.cs index 208c1f583..397c73396 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/RegistrationExtensions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/RegistrationExtensions.cs @@ -22,7 +22,7 @@ public static IRegistrationBuilder(@delegate); } - + public static void RegisterModule(this ContainerBuilderWrapper builder, IModule module) { builder.ContainerBuilder.RegisterModule(module); @@ -50,6 +50,11 @@ public static IRegistrationBuilder RegisterTypes(this ContainerBuilderWrapper builder, params Type [] implementationTypes) + { + return builder.ContainerBuilder.RegisterTypes(implementationTypes); + } + public static IRegistrationBuilder RegisterAssemblyTypes(this ContainerBuilderWrapper builder, params Assembly[] assemblies) { return builder.ContainerBuilder.RegisterAssemblyTypes(assemblies); diff --git a/src/Surging.Core/Surging.Core.CPlatform/Module/SystemModule.cs b/src/Surging.Core/Surging.Core.CPlatform/Module/SystemModule.cs index 096a4e776..0a202bee1 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Module/SystemModule.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Module/SystemModule.cs @@ -4,11 +4,14 @@ namespace Surging.Core.CPlatform.Module { + /// + /// 系统模块基类 + /// public class SystemModule : AbstractModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } internal override void RegisterComponents(ContainerBuilderWrapper builder) diff --git a/src/Surging.Core/Surging.Core.CPlatform/Mqtt/IMqttServiceFactory.cs b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/IMqttServiceFactory.cs new file mode 100644 index 000000000..2249cd0dc --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/IMqttServiceFactory.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Mqtt +{ + public interface IMqttServiceFactory + { + + /// + /// 根据Mqtt服务路由描述符创建Mqtt服务路由。 + /// + /// Mqtt服务路由描述符。 + /// Mqtt服务路由集合。 + Task> CreateMqttServiceRoutesAsync(IEnumerable descriptors); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Mqtt/IMqttServiceRouteManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/IMqttServiceRouteManager.cs new file mode 100644 index 000000000..27325cf6e --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/IMqttServiceRouteManager.cs @@ -0,0 +1,37 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Mqtt.Implementation; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Mqtt +{ + public interface IMqttServiceRouteManager + { + event EventHandler Created; + + event EventHandler Removed; + + event EventHandler Changed; + + Task> GetRoutesAsync(); + + /// + /// 设置服务路由。 + /// + /// 服务路由集合。 + /// 一个任务。 + Task SetRoutesAsync(IEnumerable routes); + + Task RemoveByTopicAsync(string topic, IEnumerable endpoint); + + + Task RemveAddressAsync(IEnumerable addresses); + /// + /// 清空所有的服务路由。 + /// + /// 一个任务。 + Task ClearAsync(); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Mqtt/Implementation/MqttServiceRouteManagerBase.cs b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/Implementation/MqttServiceRouteManagerBase.cs new file mode 100644 index 000000000..ab25bf068 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/Implementation/MqttServiceRouteManagerBase.cs @@ -0,0 +1,114 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Mqtt.Implementation +{ + public class MqttServiceRouteEventArgs + { + public MqttServiceRouteEventArgs(MqttServiceRoute route) + { + Route = route; + } + + public MqttServiceRoute Route { get; private set; } + } + + public class MqttServiceRouteChangedEventArgs : MqttServiceRouteEventArgs + { + public MqttServiceRouteChangedEventArgs(MqttServiceRoute route, MqttServiceRoute oldRoute) : base(route) + { + OldRoute = oldRoute; + } + + public MqttServiceRoute OldRoute { get; set; } + } + + public abstract class MqttServiceRouteManagerBase : IMqttServiceRouteManager + { + private readonly ISerializer _serializer; + private EventHandler _created; + private EventHandler _removed; + private EventHandler _changed; + + protected MqttServiceRouteManagerBase(ISerializer serializer) + { + _serializer = serializer; + } + + public event EventHandler Created + { + add { _created += value; } + remove { _created -= value; } + } + + public event EventHandler Removed + { + add { _removed += value; } + remove { _removed -= value; } + } + + public event EventHandler Changed + { + add { _changed += value; } + remove { _changed -= value; } + } + + public abstract Task ClearAsync(); + public abstract Task> GetRoutesAsync(); + + public abstract Task RemveAddressAsync(IEnumerable addresses); + + public abstract Task RemoveByTopicAsync(string topic, IEnumerable endpoint); + + + public virtual Task SetRoutesAsync(IEnumerable routes) + { + if (routes == null) + throw new ArgumentNullException(nameof(routes)); + + var descriptors = routes.Where(route => route != null).Select(route => new MqttServiceDescriptor + { + AddressDescriptors = route.MqttEndpoint?.Select(address => new MqttEndpointDescriptor + { + Type = address.GetType().FullName, + Value = _serializer.Serialize(address) + }) ?? Enumerable.Empty(), + MqttDescriptor = route.MqttDescriptor + }); + return SetRoutesAsync(descriptors); + } + protected abstract Task SetRoutesAsync(IEnumerable descriptors); + + protected void OnCreated(params MqttServiceRouteEventArgs[] args) + { + if (_created == null) + return; + + foreach (var arg in args) + _created(this, arg); + } + + protected void OnChanged(params MqttServiceRouteChangedEventArgs[] args) + { + if (_changed == null) + return; + + foreach (var arg in args) + _changed(this, arg); + } + + protected void OnRemoved(params MqttServiceRouteEventArgs[] args) + { + if (_removed == null) + return; + + foreach (var arg in args) + _removed(this, arg); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttDescriptor.cs b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttDescriptor.cs new file mode 100644 index 000000000..48693b634 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttDescriptor.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Surging.Core.CPlatform.Mqtt +{ + /// + /// 服务描述符扩展方法。 + /// + public static class MqttDescriptorExtensions + { + + } + + /// + /// 服务描述符。 + /// + [Serializable] + public class MqttDescriptor + { + /// + /// 初始化一个新的服务描述符。 + /// + public MqttDescriptor() + { + Metadatas = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + /// + /// Topic。 + /// + public string Topic { get; set; } + /// + /// 元数据。 + /// + public IDictionary Metadatas { get; set; } + + /// + /// 获取一个元数据。 + /// + /// 元数据类型。 + /// 元数据名称。 + /// 如果指定名称的元数据不存在则返回这个参数。 + /// 元数据值。 + public T GetMetadata(string name, T def = default(T)) + { + if (!Metadatas.ContainsKey(name)) + return def; + + return (T)Metadatas[name]; + } + + #region Equality members + + /// Determines whether the specified object is equal to the current object. + /// true if the specified object is equal to the current object; otherwise, false. + /// The object to compare with the current object. + public override bool Equals(object obj) + { + var model = obj as MqttDescriptor; + if (model == null) + return false; + + if (obj.GetType() != GetType()) + return false; + + if (model.Topic != Topic) + return false; + + return model.Metadatas.Count == Metadatas.Count && model.Metadatas.All(metadata => + { + object value; + if (!Metadatas.TryGetValue(metadata.Key, out value)) + return false; + + if (metadata.Value == null && value == null) + return true; + if (metadata.Value == null || value == null) + return false; + + return metadata.Value.Equals(value); + }); + } + + /// Serves as the default hash function. + /// A hash code for the current object. + public override int GetHashCode() + { + return ToString().GetHashCode(); + } + + public static bool operator ==(MqttDescriptor model1, MqttDescriptor model2) + { + return Equals(model1, model2); + } + + public static bool operator !=(MqttDescriptor model1, MqttDescriptor model2) + { + return !Equals(model1, model2); + } + + #endregion Equality members + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttServiceDescriptor.cs b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttServiceDescriptor.cs new file mode 100644 index 000000000..aac8c3063 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttServiceDescriptor.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Serialization; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Mqtt +{ + /// + /// Mqtt地址描述符。 + /// + public class MqttEndpointDescriptor + { + /// + /// 地址类型。 + /// + [JsonIgnore] + public string Type { get; set; } + + /// + /// 地址值。 + /// + public string Value { get; set; } + + /// + /// 创建一个描述符。 + /// + /// 地址模型类型。 + /// 地址模型实例。 + /// 序列化器。 + /// Mqtt地址描述符。 + public static MqttEndpointDescriptor CreateDescriptor(T address, ISerializer serializer) where T : AddressModel, new() + { + return new MqttEndpointDescriptor + { + Type = typeof(T).FullName, + Value = serializer.Serialize(address) + }; + } + } + + public class MqttServiceDescriptor + { + /// + /// Mqtt地址描述符集合。 + /// + public IEnumerable AddressDescriptors { get; set; } + + /// + /// Mqtt描述符。 + /// + public MqttDescriptor MqttDescriptor { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttServiceRoute.cs b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttServiceRoute.cs new file mode 100644 index 000000000..49e56e6fc --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Mqtt/MqttServiceRoute.cs @@ -0,0 +1,59 @@ +using Surging.Core.CPlatform.Address; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Surging.Core.CPlatform.Mqtt +{ + public class MqttServiceRoute + { + /// + /// Mqtt服务可用地址。 + /// + public IEnumerable MqttEndpoint { get; set; } + /// + /// Mqtt服务描述符。 + /// + public MqttDescriptor MqttDescriptor { get; set; } + + #region Equality members + + /// Determines whether the specified object is equal to the current object. + /// true if the specified object is equal to the current object; otherwise, false. + /// The object to compare with the current object. + public override bool Equals(object obj) + { + var model = obj as MqttServiceRoute; + if (model == null) + return false; + + if (obj.GetType() != GetType()) + return false; + + if (model.MqttDescriptor != MqttDescriptor) + return false; + + return model.MqttEndpoint.Count() == MqttEndpoint.Count() && model.MqttEndpoint.All(addressModel => MqttEndpoint.Contains(addressModel)); + } + + /// Serves as the default hash function. + /// A hash code for the current object. + public override int GetHashCode() + { + return ToString().GetHashCode(); + } + + public static bool operator ==(MqttServiceRoute model1, MqttServiceRoute model2) + { + return Equals(model1, model2); + } + + public static bool operator != (MqttServiceRoute model1, MqttServiceRoute model2) + { + return !Equals(model1, model2); + } + + #endregion Equality members + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Network/INetwork.cs b/src/Surging.Core/Surging.Core.CPlatform/Network/INetwork.cs new file mode 100644 index 000000000..94b08a324 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Network/INetwork.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Network +{ + public interface INetwork + { + + string Id { get; set; } + + Task StartAsync(); + /** + * @return 网络类型 + * @see DefaultNetworkType + */ + NetworkType GetType(); + + /** + * 关闭网络组件 + */ + void Shutdown(); + + /** + * @return 是否存活 + */ + bool IsAlive(); + + /** + * 当{@link Network#isAlive()}为false是,是否自动重新加载. + * + * @return 是否重新加载 + * @see NetworkProvider#reload(Network, Object) + */ + bool IsAutoReload(); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Network/INetworkProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Network/INetworkProvider.cs new file mode 100644 index 000000000..0a6e05212 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Network/INetworkProvider.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Network +{ + public interface INetworkProvider + { + + /** + * @return 类型 + * @see DefaultNetworkType + */ + NetworkType GetNetworkType(); + + INetwork CreateNetwork(T properties); + + /** + * 重新加载网络组件 + * + * @param network 网络组件 + * @param properties 配置信息 + */ + void Reload(INetwork network, T properties); + + + IDictionary GetConfigMetadata(); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Network/NetworkType.cs b/src/Surging.Core/Surging.Core.CPlatform/Network/NetworkType.cs new file mode 100644 index 000000000..11684a985 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Network/NetworkType.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Network +{ + public enum NetworkType + { + TcpClient,//TCP客户端 + TcpServer,//TCP服务 + MqttClient,//MQTT客户端 + MqttServer,//MQTT服务 + HttpClient,//HTTP客户端 + HttpServer,//HTTP服务 + WebSocketClient,//WebSocket客户端 + WebSocketServer,//WebSocket服务 + UDP,//UDP + CoapClient,//CoAP客户端 + CoapServer//CoAP服务 + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/RegistrationExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/RegistrationExtensions.cs new file mode 100644 index 000000000..bd77c0550 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/RegistrationExtensions.cs @@ -0,0 +1,29 @@ +using Surging.Core.CPlatform.Filters; +using Surging.Core.CPlatform.Module; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform +{ + public static class RegistrationExtensions + { + public static void AddFilter(this ContainerBuilderWrapper builder, Type filter) + { + + if (typeof(IExceptionFilter).IsAssignableFrom(filter)) + { + builder.RegisterType(filter).As().SingleInstance(); + } + else if (typeof(IAuthorizationFilter).IsAssignableFrom(filter)) + { + builder.RegisterType(filter).As().SingleInstance(); + } + else if (typeof(IActionFilter).IsAssignableFrom(filter)) + { + builder.RegisterType(filter).As().SingleInstance(); + } + } + + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Routing/IServiceRouteProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Routing/IServiceRouteProvider.cs index 9a1a4eac3..f169def77 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Routing/IServiceRouteProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Routing/IServiceRouteProvider.cs @@ -1,14 +1,43 @@ using Surging.Core.CPlatform.Routing; +using System.Collections.Generic; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Routing { + /// + /// 服务路由接口 + /// public interface IServiceRouteProvider { + /// + /// 根据服务id找到相关服务信息 + /// + /// + /// Task Locate(string serviceId); + ValueTask GetLocalRouteByPathRegex(string path); + /// + /// 根据服务路由路径获取路由信息 + /// + /// + /// ValueTask GetRouteByPath(string path); + /// + /// 根据服务路由路径找到相关服务信息 + /// + /// + /// Task SearchRoute(string path); + + /// + /// 注册路由 + /// + /// + /// + Task RegisterRoutes(decimal processorTime); + + ValueTask GetRouteByPathRegex(string path); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Routing/Implementation/DefaultServiceRouteProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Routing/Implementation/DefaultServiceRouteProvider.cs index a5f558b96..c9c94d149 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Routing/Implementation/DefaultServiceRouteProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Routing/Implementation/DefaultServiceRouteProvider.cs @@ -1,11 +1,15 @@ using Microsoft.Extensions.Logging; using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Routing.Implementation; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.CPlatform.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Routing.Implementation @@ -15,17 +19,24 @@ public class DefaultServiceRouteProvider : IServiceRouteProvider private readonly ConcurrentDictionary _concurrent = new ConcurrentDictionary(); + private readonly List _localRoutes = new List(); + private readonly ConcurrentDictionary _serviceRoute = new ConcurrentDictionary(); + private readonly IServiceEntryManager _serviceEntryManager; private readonly ILogger _logger; private readonly IServiceRouteManager _serviceRouteManager; - public DefaultServiceRouteProvider(IServiceRouteManager serviceRouteManager, ILogger logger) + private readonly IServiceTokenGenerator _serviceTokenGenerator; + public DefaultServiceRouteProvider(IServiceRouteManager serviceRouteManager, ILogger logger, + IServiceEntryManager serviceEntryManager, IServiceTokenGenerator serviceTokenGenerator) { _serviceRouteManager = serviceRouteManager; serviceRouteManager.Changed += ServiceRouteManager_Removed; serviceRouteManager.Removed += ServiceRouteManager_Removed; serviceRouteManager.Created += ServiceRouteManager_Add; + _serviceEntryManager = serviceEntryManager; + _serviceTokenGenerator = serviceTokenGenerator; _logger = logger; } @@ -47,6 +58,34 @@ public async Task Locate(string serviceId) return route; } + public ValueTask GetLocalRouteByPathRegex(string path) + { + var addess = NetUtils.GetHostAddress(); + + if (_localRoutes.Count == 0) + { + _localRoutes.AddRange( _serviceEntryManager.GetEntries().Select(i => + { + i.Descriptor.Token = _serviceTokenGenerator.GetToken(); + return new ServiceRoute + { + Address = new[] { addess }, + ServiceDescriptor = i.Descriptor + }; + }).ToList()); + } + + path = path.ToLower(); + _serviceRoute.TryGetValue(path, out ServiceRoute route); + if (route == null) + { + return new ValueTask(GetRouteByPathRegexAsync(_localRoutes, path)); + } + else + { + return new ValueTask(route); + } + } public ValueTask GetRouteByPath(string path) { @@ -61,11 +100,46 @@ public ValueTask GetRouteByPath(string path) } } + public async ValueTask GetRouteByPathRegex(string path) + { + path = path.ToLower(); + _serviceRoute.TryGetValue(path, out ServiceRoute route); + if (route == null) + { + var routes = await _serviceRouteManager.GetRoutesAsync(); + return await GetRouteByPathRegexAsync(routes,path); + } + else + { + return route; + } + } + public async Task SearchRoute(string path) { return await SearchRouteAsync(path); } + public async Task RegisterRoutes(decimal processorTime) + { + var addess = NetUtils.GetHostAddress(); + addess.ProcessorTime = processorTime; + addess.Weight = AppConfig.ServerOptions.Weight; + if(addess.Weight>0) + addess.Timestamp = DateTimeConverter.DateTimeToUnixTimestamp(DateTime.Now); + RpcContext.GetContext().SetAttachment("Host", addess); + var addressDescriptors = _serviceEntryManager.GetEntries().Select(i => + { + i.Descriptor.Token = _serviceTokenGenerator.GetToken(); + return new ServiceRoute + { + Address = new[] { addess }, + ServiceDescriptor = i.Descriptor + }; + }).ToList(); + await _serviceRouteManager.SetRoutesAsync(addressDescriptors); + } + #region 私有方法 private static string GetCacheKey(ServiceDescriptor descriptor) { @@ -90,7 +164,7 @@ private void ServiceRouteManager_Add(object sender, ServiceRouteEventArgs e) private async Task SearchRouteAsync(string path) { var routes = await _serviceRouteManager.GetRoutesAsync(); - var route = routes.FirstOrDefault(i => i.ServiceDescriptor.RoutePath.Contains(path)); + var route = routes.FirstOrDefault(i => String.Compare(i.ServiceDescriptor.RoutePath, path, true) == 0); if (route == null) { if (_logger.IsEnabled(LogLevel.Warning)) @@ -104,7 +178,7 @@ private async Task SearchRouteAsync(string path) private async Task GetRouteByPathAsync(string path) { var routes = await _serviceRouteManager.GetRoutesAsync(); - var route = routes.FirstOrDefault(i => i.ServiceDescriptor.RoutePath==path); + var route = routes.FirstOrDefault(i => String.Compare(i.ServiceDescriptor.RoutePath, path, true) == 0 && !i.ServiceDescriptor.GetMetadata("IsOverload")); if (route == null) { if (_logger.IsEnabled(LogLevel.Warning)) @@ -114,6 +188,29 @@ private async Task GetRouteByPathAsync(string path) _serviceRoute.GetOrAdd(path, route); return route; } + + private async Task GetRouteByPathRegexAsync(IEnumerable routes, string path) + { + var pattern = "/{.*?}"; + + var route = routes.FirstOrDefault(i => + { + var routePath = Regex.Replace(i.ServiceDescriptor.RoutePath, pattern, ""); + var newPath = path.Replace(routePath, ""); + return (newPath.StartsWith("/")|| newPath.Length==0) && i.ServiceDescriptor.RoutePath.Split("/").Length == path.Split("/").Length && !i.ServiceDescriptor.GetMetadata("IsOverload"); + }); + + + if (route == null) + { + if (_logger.IsEnabled(LogLevel.Warning)) + _logger.LogWarning($"根据服务路由路径:{path},找不到相关服务信息。"); + } + else + if(!Regex.IsMatch(route.ServiceDescriptor.RoutePath, pattern)) _serviceRoute.GetOrAdd(path, route); + return await Task.FromResult(route); + } + #endregion } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RoutePatternParser.cs b/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RoutePatternParser.cs index 04cd6798d..9d52ce7cb 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RoutePatternParser.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RoutePatternParser.cs @@ -12,6 +12,7 @@ public static string Parse(string routeTemplet, string service, string method) { StringBuilder result = new StringBuilder(); var parameters = routeTemplet.Split(@"/"); + bool isAppendMethod=false; foreach (var parameter in parameters) { var param = GetParameters(parameter).FirstOrDefault(); @@ -26,11 +27,19 @@ public static string Parse(string routeTemplet, string service, string method) else if (param == "Method") { result.Append(method); + isAppendMethod = true; + } + else + { + if (!isAppendMethod) result.AppendFormat("{0}/", method); + result.Append(parameter); + isAppendMethod = true; } result.Append("/"); } - - return result.Append(method).ToString().ToLower(); + result.Length = result.Length - 1; + if (!isAppendMethod) result.AppendFormat("/{0}", method); + return result.ToString().ToLower(); } public static string Parse(string routeTemplet, string service) diff --git a/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RouteTemplateSegmenter.cs b/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RouteTemplateSegmenter.cs new file mode 100644 index 000000000..0d3839247 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Routing/Template/RouteTemplateSegmenter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Surging.Core.CPlatform.Routing.Template +{ + public class RouteTemplateSegmenter + { + public static Dictionary Segment(string routePath, string path) + { + var pattern = "/{.*?}"; + var result = new Dictionary(); + if ( Regex.IsMatch(routePath, pattern)) + { + var routeTemplate= Regex.Replace(routePath, pattern, ""); + var routeSegments = routeTemplate.Split('/'); + var pathSegments = path.Split('/'); + var segments = routePath.Split("/"); + for(var i= routeSegments.Length;i< pathSegments.Length;i++) + { + result.Add(segments[i].Replace("{","").Replace("}", ""), pathSegments[i]); + } + } + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/IAddressResolver.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/IAddressResolver.cs index f4b93911c..57045a465 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/IAddressResolver.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/IAddressResolver.cs @@ -13,6 +13,6 @@ public interface IAddressResolver /// /// 服务Id。 /// 服务地址模型。 - ValueTask Resolver(string serviceId, int hashCode); + ValueTask Resolver(string serviceId, string item); } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/DefaultAddressResolver.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/DefaultAddressResolver.cs index b991700d8..023827354 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/DefaultAddressResolver.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/DefaultAddressResolver.cs @@ -15,7 +15,7 @@ namespace Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation { /// - /// 一个人默认的服务地址解析器。 + /// 默认的服务地址解析器。 /// public class DefaultAddressResolver : IAddressResolver { @@ -25,26 +25,28 @@ public class DefaultAddressResolver : IAddressResolver private readonly ILogger _logger; private readonly IHealthCheckService _healthCheckService; private readonly CPlatformContainer _container; + private readonly IServiceRouteProvider _serviceRouteProvider; private readonly ConcurrentDictionary _addressSelectors=new ConcurrentDictionary(); private readonly IServiceCommandProvider _commandProvider; private readonly ConcurrentDictionary _concurrent = new ConcurrentDictionary(); + private readonly IServiceHeartbeatManager _serviceHeartbeatManager; #endregion Field #region Constructor - public DefaultAddressResolver(IServiceCommandProvider commandProvider, IServiceRouteManager serviceRouteManager, ILogger logger, CPlatformContainer container, IHealthCheckService healthCheckService) + public DefaultAddressResolver(IServiceCommandProvider commandProvider, IServiceRouteProvider serviceRouteProvider, ILogger logger, CPlatformContainer container, + IHealthCheckService healthCheckService, + IServiceHeartbeatManager serviceHeartbeatManager) { _container = container; - _serviceRouteManager = serviceRouteManager; + _serviceRouteProvider = serviceRouteProvider; _logger = logger; LoadAddressSelectors(); _commandProvider = commandProvider; _healthCheckService = healthCheckService; - serviceRouteManager.Changed += ServiceRouteManager_Removed; - serviceRouteManager.Removed += ServiceRouteManager_Removed; - serviceRouteManager.Created += ServiceRouteManager_Add; + _serviceHeartbeatManager = serviceHeartbeatManager; } #endregion Constructor @@ -56,38 +58,38 @@ public DefaultAddressResolver(IServiceCommandProvider commandProvider, IServiceR /// /// 服务Id。 /// 服务地址模型。 - public async ValueTask Resolver(string serviceId, int hashCode) + /// 1.从字典中拿到serviceroute对象 + /// 2.从字典中拿到服务描述符集合 + /// 3.获取或添加serviceroute + /// 4.添加服务id到白名单 + /// 5.根据服务描述符得到地址并判断地址是否是可用的(地址应该是多个) + /// 6.添加到集合中 + /// 7.拿到服务命今 + /// 8.根据负载分流策略拿到一个选择器 + /// 9.返回addressmodel + public async ValueTask Resolver(string serviceId, string item) { if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"准备为服务id:{serviceId},解析可用地址。"); - _concurrent.TryGetValue(serviceId, out ServiceRoute descriptor); - if (descriptor == null) + var serviceRouteTask= _serviceRouteProvider.Locate(serviceId); + var serviceRoute = serviceRouteTask.IsCompletedSuccessfully ? serviceRouteTask.Result : await serviceRouteTask; + if (serviceRoute == null) { - var descriptors = await _serviceRouteManager.GetRoutesAsync(); - descriptor = descriptors.FirstOrDefault(i => i.ServiceDescriptor.Id == serviceId); - if (descriptor != null) - { - _concurrent.GetOrAdd(serviceId, descriptor); - } - else - { - if (descriptor == null) - { - if (_logger.IsEnabled(LogLevel.Warning)) - _logger.LogWarning($"根据服务id:{serviceId},找不到相关服务信息。"); - return null; - } - } + if (_logger.IsEnabled(LogLevel.Warning)) + _logger.LogWarning($"根据服务id:{serviceId},找不到相关服务信息。"); + return null; } - + _serviceHeartbeatManager.AddWhitelist(serviceId); var address = new List(); - foreach (var addressModel in descriptor.Address) + foreach (var addressModel in serviceRoute.Address) { _healthCheckService.Monitor(addressModel); - if (!await _healthCheckService.IsHealth(addressModel)) + var task = _healthCheckService.IsHealth(addressModel); + if (!(task.IsCompletedSuccessfully ? task.Result : await task)) + { continue; - + } address.Add(addressModel); } @@ -100,33 +102,20 @@ public async ValueTask Resolver(string serviceId, int hashCode) if (_logger.IsEnabled(LogLevel.Information)) _logger.LogInformation($"根据服务id:{serviceId},找到以下可用地址:{string.Join(",", address.Select(i => i.ToString()))}。"); - var command = await _commandProvider.GetCommand(serviceId); + var vtCommand = _commandProvider.GetCommand(serviceId); + var command = vtCommand.IsCompletedSuccessfully ? vtCommand.Result : await vtCommand; var addressSelector = _addressSelectors[command.ShuntStrategy.ToString()]; - return await addressSelector.SelectAsync(new AddressSelectContext + + var vt = addressSelector.SelectAsync(new AddressSelectContext { - Descriptor = descriptor.ServiceDescriptor, + Descriptor = serviceRoute.ServiceDescriptor, Address = address, - HashCode = hashCode + Item = item }); + return vt.IsCompletedSuccessfully ? vt.Result : await vt; } - private static string GetCacheKey(ServiceDescriptor descriptor) - { - return descriptor.Id; - } - private void ServiceRouteManager_Removed(object sender, ServiceRouteEventArgs e) - { - var key = GetCacheKey(e.Route.ServiceDescriptor); - ServiceRoute value; - _concurrent.TryRemove(key, out value); - } - - private void ServiceRouteManager_Add(object sender, ServiceRouteEventArgs e) - { - var key = GetCacheKey(e.Route.ServiceDescriptor); - _concurrent.GetOrAdd(key, e.Route); - } private void LoadAddressSelectors() { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/IAddressSelector.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/IAddressSelector.cs index 3aab76598..c96959ff2 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/IAddressSelector.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/IAddressSelector.cs @@ -1,4 +1,5 @@ using Surging.Core.CPlatform.Address; +using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -15,15 +16,15 @@ public class AddressSelectContext public ServiceDescriptor Descriptor { get; set; } /// - /// 参数的哈希值 + /// 哈希参数 /// - public int HashCode { get; set; } + public string Item { get; set; } /// /// 服务可用地址。 /// public IEnumerable Address { get; set; } } - + /// /// 一个抽象的地址选择器。 /// diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorBase.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorBase.cs index 976ac4fcc..a062600c8 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorBase.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorBase.cs @@ -1,4 +1,5 @@ using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Utilities; using System; using System.Linq; using System.Threading.Tasks; @@ -12,12 +13,56 @@ public abstract class AddressSelectorBase : IAddressSelector { #region Implementation of IAddressSelector + private const int DEFAULT_WARMUP = 10 * 60 * 1000; + + /// + /// 计算权重 + /// + /// 启动持续时间 + /// 预热时间 + /// 权重 + /// + public static int CalculateWarmupWeight(int uptime, int warmup, int weight) + { + int ww = (int)(uptime / ((float)warmup / weight)); + return ww < 1 ? 1 : (Math.Min(ww, weight)); + } + + /// + /// 获取权重 + /// + /// + /// + public static int GetWeight(AddressModel addressModel) + { + int weight; + weight = addressModel.Weight; + if (weight > 0) + { + long timestamp = addressModel.Timestamp; + if (timestamp > 0L) + { + var uptime = (System.DateTime.Now - DateTimeConverter.UnixTimestampToDateTime(timestamp)).TotalMilliseconds; + if (uptime < 0) + { + return 1; + } + if (uptime > 0 && uptime < DEFAULT_WARMUP) + { + weight = CalculateWarmupWeight((int)uptime, DEFAULT_WARMUP, weight); + } + } + } + + return Math.Max(weight, 0); + } + /// /// 选择一个地址。 /// /// 地址选择上下文。 /// 地址模型。 - ValueTask IAddressSelector.SelectAsync(AddressSelectContext context) + async ValueTask IAddressSelector.SelectAsync(AddressSelectContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -29,8 +74,16 @@ ValueTask IAddressSelector.SelectAsync(AddressSelectContext contex // var address = context.Address.ToArray(); if (context.Address.Count() == 0) throw new ArgumentException("没有任何地址信息。", nameof(context.Address)); - - return context.Address.Count() == 1 ? new ValueTask(context.Address.First()) : new ValueTask(SelectAsync(context)); + + if (context.Address.Count() == 1) + { + return context.Address.First(); + } + else + { + var vt = SelectAsync(context); + return vt.IsCompletedSuccessfully ? vt.Result : await vt; + } } #endregion Implementation of IAddressSelector @@ -40,6 +93,6 @@ ValueTask IAddressSelector.SelectAsync(AddressSelectContext contex /// /// 地址选择上下文。 /// 地址模型。 - protected abstract Task SelectAsync(AddressSelectContext context); + protected abstract ValueTask SelectAsync(AddressSelectContext context); } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorMode.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorMode.cs index 21d0dfa68..6d6b18b97 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorMode.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/AddressSelectorMode.cs @@ -4,11 +4,30 @@ namespace Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation { + /// + /// 负载均衡模式 + /// public enum AddressSelectorMode { + /// + /// Hash算法 + /// HashAlgorithm, + /// + /// 轮询 + /// Polling, + /// + /// 随机 + /// Random, + /// + /// 压力最小优先 + /// FairPolling, + /// + /// 权重轮询 + /// + RoundRobin } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/FairPollingAdrSelector.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/FairPollingAdrSelector.cs index 31bf8d53a..f91310f0e 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/FairPollingAdrSelector.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/FairPollingAdrSelector.cs @@ -38,15 +38,23 @@ private static string GetCacheKey(ServiceDescriptor descriptor) return descriptor.Id; } - protected override async Task SelectAsync(AddressSelectContext context) + protected override async ValueTask SelectAsync(AddressSelectContext context) { var key = GetCacheKey(context.Descriptor); //根据服务id缓存服务地址。 var addressEntry = _concurrent.GetOrAdd(key, k => new Lazy(() => new AddressEntry(context.Address))).Value; AddressModel addressModel; + var index = 0; + var len = context.Address.Count(); do { addressModel = addressEntry.GetAddress(); + if (len <= index) + { + addressModel = null; + break; + } + index++; } while (await _healthCheckService.IsHealth(addressModel) == false); return addressModel; } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/HashAlgorithmAdrSelector.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/HashAlgorithmAdrSelector.cs index 65143c885..5c3f293c6 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/HashAlgorithmAdrSelector.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/HashAlgorithmAdrSelector.cs @@ -1,7 +1,9 @@ using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.HashAlgorithms; using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Routing.Implementation; using Surging.Core.CPlatform.Runtime.Client.HealthChecks; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks.Implementation; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -14,8 +16,19 @@ namespace Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation { public class HashAlgorithmAdrSelector : AddressSelectorBase { - public HashAlgorithmAdrSelector() - { + private readonly IHealthCheckService _healthCheckService; + private readonly ConcurrentDictionary> _concurrent = + new ConcurrentDictionary>(); + private readonly List> _unHealths = + new List>(); + private readonly IHashAlgorithm _hashAlgorithm; + public HashAlgorithmAdrSelector(IServiceRouteManager serviceRouteManager, IHealthCheckService healthCheckService, IHashAlgorithm hashAlgorithm) + { + _healthCheckService = healthCheckService; + _hashAlgorithm = hashAlgorithm; + //路由发生变更时重建地址条目。 + serviceRouteManager.Changed += ServiceRouteManager_Removed; + serviceRouteManager.Removed += ServiceRouteManager_Removed; } #region Overrides of AddressSelectorBase @@ -24,12 +37,76 @@ public HashAlgorithmAdrSelector() /// /// 地址选择上下文。 /// 地址模型。 - protected override Task SelectAsync(AddressSelectContext context) + protected override async ValueTask SelectAsync(AddressSelectContext context) { - var address = context.Address.ToArray(); - var index = context.HashCode%address.Length; - return Task.FromResult(address[index]); + var key = GetCacheKey(context.Descriptor); + var addressEntry = _concurrent.GetOrAdd(key, k => + { + var len = context.Address.Count(); + len = len > 1 && len < 10 ? len * 10 : len; + var hash = new ConsistentHash(_hashAlgorithm, len); + foreach (var address in context.Address) + { + hash.Add(address,address.ToString()); + } + return hash; + }); + AddressModel addressModel; + var IsHealth = false; + var index = 0; + var count = context.Address.Count(); + do + { + addressModel = addressEntry.GetItemNode(context.Item); + if (count <= index) + { + addressModel = null; + break; + } + index++; + IsHealth = await _healthCheckService.IsHealth(addressModel); + if(!IsHealth) + { + addressEntry.Remove(addressModel.ToString()); + _unHealths.Add(new ValueTuple(key,addressModel)); + _healthCheckService.Changed += ItemNode_Changed; + } + } while (!IsHealth); + return addressModel; } #endregion Overrides of AddressSelectorBase + + #region Private Method + + private void ItemNode_Changed(object sender, HealthCheckEventArgs e) + { + var list= _unHealths.Where(p=>p.Item2.ToString()==e.Address.ToString()).ToList(); + foreach (var item in list) + { + if (item.Item1 != null && e.Health) + { + var addressEntry = _concurrent.GetValueOrDefault(item.Item1); + addressEntry.Add(item.Item2, item.Item2.ToString()); + _unHealths.Remove(item); + } + } + if(_unHealths.Count==0) + _healthCheckService.Changed -= ItemNode_Changed; + } + + private static string GetCacheKey(ServiceDescriptor descriptor) + { + return descriptor.Id; + } + + private void ServiceRouteManager_Removed(object sender, ServiceRouteEventArgs e) + { + var key = GetCacheKey(e.Route.ServiceDescriptor); + var item = _unHealths.Where(p => e.Route.Address.Select(addr=> addr.ToString()).Contains(p.Item2.ToString())).ToList(); + item.ForEach(p => _unHealths.Remove(p)); + _concurrent.TryRemove(key, out ConsistentHash value); + } + + #endregion } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/PollingAddressSelector.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/PollingAddressSelector.cs index 6efcd4a0f..94ebfc82c 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/PollingAddressSelector.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/PollingAddressSelector.cs @@ -36,16 +36,27 @@ public PollingAddressSelector(IServiceRouteManager serviceRouteManager, IHealthC /// /// 地址选择上下文。 /// 地址模型。 - protected override async Task SelectAsync(AddressSelectContext context) + protected override async ValueTask SelectAsync(AddressSelectContext context) { var key = GetCacheKey(context.Descriptor); //根据服务id缓存服务地址。 var addressEntry = _concurrent.GetOrAdd(key, k => new Lazy(() => new AddressEntry(context.Address))).Value; AddressModel addressModel; + var index = 0; + var len = context.Address.Count(); + ValueTask vt; do { + addressModel = addressEntry.GetAddress(); - } while (await _healthCheckService.IsHealth(addressModel) == false); + if (len <= index) + { + addressModel = null; + break; + } + index++; + vt = _healthCheckService.IsHealth(addressModel); + } while (!(vt.IsCompletedSuccessfully ? vt.Result : await vt)); return addressModel; } @@ -58,6 +69,12 @@ private static string GetCacheKey(ServiceDescriptor descriptor) return descriptor.Id; } + public async ValueTask CheckHealth(AddressModel addressModel) + { + var vt = _healthCheckService.IsHealth(addressModel); + return vt.IsCompletedSuccessfully ? vt.Result : await vt; + } + private void ServiceRouteManager_Removed(object sender, ServiceRouteEventArgs e) { var key = GetCacheKey(e.Route.ServiceDescriptor); diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RandomAddressSelector.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RandomAddressSelector.cs index 00daf9a55..3f28e7e53 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RandomAddressSelector.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RandomAddressSelector.cs @@ -48,13 +48,13 @@ public RandomAddressSelector(Func generate) /// /// 地址选择上下文。 /// 地址模型。 - protected override Task SelectAsync(AddressSelectContext context) + protected override ValueTask SelectAsync(AddressSelectContext context) { var address = context.Address.ToArray(); var length = address.Length; var index = _generate(0, length); - return Task.FromResult(address[index]); + return new ValueTask(address[index]); } #endregion Overrides of AddressSelectorBase diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RoundRobinAddressSelector.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RoundRobinAddressSelector.cs new file mode 100644 index 000000000..b832087b6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Address/Resolvers/Implementation/Selectors/Implementation/RoundRobinAddressSelector.cs @@ -0,0 +1,202 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Routing.Implementation; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation +{ + public class RoundRobinAddressSelector : AddressSelectorBase + { + private const int RECYCLE_PERIOD = 60000; + private readonly IHealthCheckService _healthCheckService; + + private readonly ConcurrentDictionary> _concurrent = + new ConcurrentDictionary>(); + + public RoundRobinAddressSelector(IServiceRouteManager serviceRouteManager, IHealthCheckService healthCheckService) + { + _healthCheckService = healthCheckService; + //路由发生变更时重建地址条目。 + serviceRouteManager.Changed += ServiceRouteManager_Removed; + serviceRouteManager.Removed += ServiceRouteManager_Removed; + } + + #region Overrides of AddressSelectorBase + + /// + /// 选择一个地址。 + /// + /// 地址选择上下文。 + /// 地址模型。 + protected override async ValueTask SelectAsync(AddressSelectContext context) + { + var key = GetCacheKey(context.Descriptor); + //根据服务id缓存服务地址。 + var addressEntry = _concurrent.GetOrAdd(key, k => new Lazy(() => new AddressEntry(context.Address))).Value; + AddressModel addressModel; + var index = 0; + var len = context.Address.Count(); + ValueTask vt; + do + { + + addressModel = addressEntry.GetAddress(); + if (len <= index) + { + addressModel = null; + break; + } + index++; + vt = _healthCheckService.IsHealth(addressModel); + } while (!(vt.IsCompletedSuccessfully ? vt.Result : await vt)); + return addressModel; + } + + #endregion Overrides of AddressSelectorBase + + #region Private Method + + private static string GetCacheKey(ServiceDescriptor descriptor) + { + return descriptor.Id; + } + + public async ValueTask CheckHealth(AddressModel addressModel) + { + var vt = _healthCheckService.IsHealth(addressModel); + return vt.IsCompletedSuccessfully ? vt.Result : await vt; + } + + private void ServiceRouteManager_Removed(object sender, ServiceRouteEventArgs e) + { + var key = GetCacheKey(e.Route.ServiceDescriptor); + var addressEntry = _concurrent.GetOrAdd(key, k => new Lazy(() => new AddressEntry(e.Route.Address))).Value; + addressEntry.SetAddresses(e.Route.Address.ToArray()); + } + + #endregion Private Method + protected class WeightedRoundRobin + { + private int _weight; + private readonly AtomicLong current = new AtomicLong(0); + private long lastUpdate; + + public int GetWeight() + { + return _weight; + } + + public void SetWeight(int weight) + { + this._weight = weight; + current.Set(0); + } + + public long IncreaseCurrent() + { + return current.AddAndGet(_weight); + } + + public void Sel(int total) + { + current.AddAndGet(-1 * total); + } + + public long GetLastUpdate() + { + return lastUpdate; + } + + public void SetLastUpdate(long lastUpdate) + { + this.lastUpdate = lastUpdate; + } + } + + #region Help Class + + protected class AddressEntry + { + #region Field + + private AddressModel[] _address; + + private readonly ConcurrentDictionary> _concurrent = + new ConcurrentDictionary>(); + #endregion Field + + #region Constructor + + public AddressEntry(IEnumerable address) + { + _address = address.ToArray(); + } + + #endregion Constructor + + #region Public Method + + public AddressModel GetAddress() + { + int totalWeight = 0; + long maxCurrent = long.MinValue; + var now = DateTimeConverter.DateTimeToUnixTimestamp(DateTime.Now); + AddressModel selectedAddr = null; + WeightedRoundRobin selectedWRR = null; + foreach (var address in _address) + { + var identifyString = address.ToString(); + int weight = GetWeight(address); + var weightedRoundRobin = _concurrent.GetOrAdd(identifyString, k => new Lazy(() => + { + WeightedRoundRobin wrr = new WeightedRoundRobin(); + wrr.SetWeight(weight); + return wrr; + })).Value; + if (weight != weightedRoundRobin.GetWeight()) + { + //weight changed + weightedRoundRobin.SetWeight(weight); + } + long cur = weightedRoundRobin.IncreaseCurrent(); + weightedRoundRobin.SetLastUpdate(now); + if (cur > maxCurrent) + { + maxCurrent = cur; + selectedAddr = address; + selectedWRR = weightedRoundRobin; + } + totalWeight += weight; + } + + if (_address.Count() != _concurrent.Count()) + { + var concurrentsToRemove = _concurrent.Where(p => (now - p.Value.Value.GetLastUpdate())*1000 > RECYCLE_PERIOD).ToList(); + concurrentsToRemove.ForEach(concurrent => _concurrent.TryRemove(concurrent.Key, out Lazy obj)); + } + if (selectedAddr != null) + { + selectedWRR.Sel(totalWeight); + return selectedAddr; + } + return _address[0]; + } + + public void SetAddresses(AddressModel[] addresses) + { + _address= addresses; + } + #endregion Public Method + } + + #endregion Help Class + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/IHealthCheckService.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/IHealthCheckService.cs index 40ee7970c..32577d4a1 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/IHealthCheckService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/IHealthCheckService.cs @@ -1,4 +1,6 @@ using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks.Implementation; +using System; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Runtime.Client.HealthChecks @@ -29,5 +31,9 @@ public interface IHealthCheckService /// 地址模型。 /// 一个任务。 Task MarkFailure(AddressModel address); + + event EventHandler Removed; + + event EventHandler Changed; } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/DefaultHealthCheckService.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/DefaultHealthCheckService.cs index 8bbe668f3..114049d5e 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/DefaultHealthCheckService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/DefaultHealthCheckService.cs @@ -11,6 +11,9 @@ namespace Surging.Core.CPlatform.Runtime.Client.HealthChecks.Implementation { + /// + /// 默认健康检查服务(每10秒会检查一次服务状态,在构造函数中添加服务管理事件) + /// public class DefaultHealthCheckService : IHealthCheckService, IDisposable { private readonly ConcurrentDictionary, MonitorEntry> _dictionary = @@ -18,15 +21,37 @@ public class DefaultHealthCheckService : IHealthCheckService, IDisposable private readonly IServiceRouteManager _serviceRouteManager; private readonly int _timeout = 30000; private readonly Timer _timer; + private EventHandler _removed; + private EventHandler _changed; + + public event EventHandler Removed + { + add { _removed += value; } + remove { _removed -= value; } + } + + public event EventHandler Changed + { + add { _changed += value; } + remove { _changed -= value; } + } + + /// + /// 默认心跳检查服务(每10秒会检查一次服务状态,在构造函数中添加服务管理事件) + /// + /// public DefaultHealthCheckService(IServiceRouteManager serviceRouteManager) { var timeSpan = TimeSpan.FromSeconds(10); _serviceRouteManager = serviceRouteManager; + //建立计时器 _timer = new Timer(async s => { + //检查服务是否可用 await Check(_dictionary.ToArray().Select(i => i.Value), _timeout); + //移除不可用的服务地址 RemoveUnhealthyAddress(_dictionary.ToArray().Select(i => i.Value).Where(m => m.UnhealthyTimes >= 6)); }, null, timeSpan, timeSpan); @@ -75,11 +100,13 @@ public void Monitor(AddressModel address) /// /// 地址模型。 /// 健康返回true,否则返回false。 - public ValueTask IsHealth(AddressModel address) + public async ValueTask IsHealth(AddressModel address) { var ipAddress = address as IpAddressModel; MonitorEntry entry; - return !_dictionary.TryGetValue(new ValueTuple(ipAddress.Ip, ipAddress.Port), out entry) ? new ValueTask(Check(address, _timeout)) : new ValueTask(entry.Health); + var isHealth= !_dictionary.TryGetValue(new ValueTuple(ipAddress.Ip, ipAddress.Port), out entry) ? await Check(address, _timeout) :entry.Health; + OnChanged(new HealthCheckEventArgs(address,isHealth)); + return isHealth; } /// @@ -97,6 +124,24 @@ public Task MarkFailure(AddressModel address) }); } + protected void OnRemoved(params HealthCheckEventArgs[] args) + { + if (_removed == null) + return; + + foreach (var arg in args) + _removed(this, arg); + } + + protected void OnChanged(params HealthCheckEventArgs[] args) + { + if (_changed == null) + return; + + foreach (var arg in args) + _changed(this, arg); + } + #endregion Implementation of IHealthCheckService #region Implementation of IDisposable @@ -135,7 +180,7 @@ private void RemoveUnhealthyAddress(IEnumerable monitorEntry) var ipAddress = p as IpAddressModel; _dictionary.TryRemove(new ValueTuple(ipAddress.Ip, ipAddress.Port), out MonitorEntry value); }); - + OnRemoved(addresses.Select(p => new HealthCheckEventArgs(p)).ToArray()); } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/HealthCheckEventArgs.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/HealthCheckEventArgs.cs new file mode 100644 index 000000000..6d5b553a7 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/HealthChecks/Implementation/HealthCheckEventArgs.cs @@ -0,0 +1,25 @@ +using Surging.Core.CPlatform.Address; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Client.HealthChecks.Implementation +{ + public class HealthCheckEventArgs + { + public HealthCheckEventArgs(AddressModel address) + { + Address = address; + } + + public HealthCheckEventArgs(AddressModel address,bool health) + { + Address = address; + Health = health; + } + + public AddressModel Address { get; private set; } + + public bool Health { get; private set; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/IServiceHeartbeatManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/IServiceHeartbeatManager.cs new file mode 100644 index 000000000..1f9bd741f --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/IServiceHeartbeatManager.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Runtime.Client +{ + public interface IServiceHeartbeatManager + { + void AddWhitelist(string serviceId); + + bool ExistsWhitelist(string serviceId); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/DefaultServiceHeartbeatManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/DefaultServiceHeartbeatManager.cs new file mode 100644 index 000000000..7a5e5a251 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/DefaultServiceHeartbeatManager.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; + +namespace Surging.Core.CPlatform.Runtime.Client.Implementation +{ + public class DefaultServiceHeartbeatManager : IServiceHeartbeatManager + { + private readonly ConcurrentBag _whitelist = new ConcurrentBag(); + + public void AddWhitelist(string serviceId) + { + if(!_whitelist.Contains(serviceId)) + _whitelist.Add(serviceId); + } + + public bool ExistsWhitelist(string serviceId) + { + return _whitelist.Contains(serviceId); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/RemoteInvokeService.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/RemoteInvokeService.cs index f1d5fc9b4..97282b18f 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/RemoteInvokeService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/Implementation/RemoteInvokeService.cs @@ -6,6 +6,7 @@ using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers; using Surging.Core.CPlatform.Runtime.Client.HealthChecks; using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Implementation; using Surging.Core.CPlatform.Utilities; using System; using System.Threading; @@ -13,6 +14,9 @@ namespace Surging.Core.CPlatform.Runtime.Client.Implementation { + /// + /// 远程调用服务 + /// public class RemoteInvokeService : IRemoteInvokeService { private readonly IAddressResolver _addressResolver; @@ -38,14 +42,17 @@ public async Task InvokeAsync(RemoteInvokeContext con public async Task InvokeAsync(RemoteInvokeContext context, CancellationToken cancellationToken) { var invokeMessage = context.InvokeMessage; - var address = await ResolverAddress(context,context.HashCode); + AddressModel address = null; + var vt = ResolverAddress(context, context.Item); + address = vt.IsCompletedSuccessfully? vt.Result: await vt; try { var endPoint = address.CreateEndPoint(); if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"使用地址:'{endPoint}'进行调用。"); - var client = _transportClientFactory.CreateClient(endPoint); - return await client.SendAsync(invokeMessage).WithCancellation(cancellationToken); + var client =await _transportClientFactory.CreateClientAsync(endPoint); + RpcContext.GetContext().SetAttachment("RemoteAddress", address.ToString()); + return await client.SendAsync(invokeMessage,cancellationToken).WithCancellation(cancellationToken); } catch (CommunicationException) { @@ -62,14 +69,21 @@ public async Task InvokeAsync(RemoteInvokeContext con public async Task InvokeAsync(RemoteInvokeContext context, int requestTimeout) { var invokeMessage = context.InvokeMessage; - var address = await ResolverAddress(context,context.HashCode); + AddressModel address = null; + var vt = ResolverAddress(context, context.Item); + address = vt.IsCompletedSuccessfully ? vt.Result : await vt; try { var endPoint = address.CreateEndPoint(); if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"使用地址:'{endPoint}'进行调用。"); - var client = _transportClientFactory.CreateClient(endPoint); - return await client.SendAsync(invokeMessage).WithCancellation(requestTimeout); + var task = _transportClientFactory.CreateClientAsync(endPoint); + var client= task.IsCompletedSuccessfully ? task.Result : await task; + RpcContext.GetContext().SetAttachment("RemoteAddress", address.ToString()); + using (var cts = new CancellationTokenSource()) + { + return await client.SendAsync(invokeMessage, cts.Token).WithCancellation(cts, requestTimeout); + } } catch (CommunicationException) { @@ -78,12 +92,12 @@ public async Task InvokeAsync(RemoteInvokeContext con } catch (Exception exception) { - _logger.LogError(exception, $"发起请求中发生了错误,服务Id:{invokeMessage.ServiceId}。"); + _logger.LogError(exception, $"发起请求中发生了错误,服务Id:{invokeMessage.ServiceId}。错误信息:{exception.Message}"); throw; } } - private async ValueTask ResolverAddress(RemoteInvokeContext context,int hashCode) + private async ValueTask ResolverAddress(RemoteInvokeContext context,string item) { if (context == null) throw new ArgumentNullException(nameof(context)); @@ -93,8 +107,11 @@ private async ValueTask ResolverAddress(RemoteInvokeContext contex if (string.IsNullOrEmpty(context.InvokeMessage.ServiceId)) throw new ArgumentException("服务Id不能为空。", nameof(context.InvokeMessage.ServiceId)); + //远程调用信息 var invokeMessage = context.InvokeMessage; - var address = await _addressResolver.Resolver(invokeMessage.ServiceId, hashCode); + //解析服务地址 + var vt = _addressResolver.Resolver(invokeMessage.ServiceId, item); + var address = vt.IsCompletedSuccessfully ? vt.Result : await vt; if (address == null) throw new CPlatformException($"无法解析服务Id:{invokeMessage.ServiceId}的地址信息。"); return address; diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/RemoteInvokeContext.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/RemoteInvokeContext.cs index 2a7cab8ee..4384f417d 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/RemoteInvokeContext.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Client/RemoteInvokeContext.cs @@ -12,6 +12,6 @@ public class RemoteInvokeContext /// public RemoteInvokeMessage InvokeMessage { get; set; } - public int HashCode { get; set; } + public string Item { get; set; } } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryManager.cs index 783d783b3..c14d20c47 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryManager.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryManager.cs @@ -12,5 +12,9 @@ public interface IServiceEntryManager /// /// 服务条目集合。 IEnumerable GetEntries(); + + void UpdateEntries(IEnumerable providers); + + IEnumerable GetAllEntries(); } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryProvider.cs index c878f37d9..b58a4976b 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/IServiceEntryProvider.cs @@ -14,6 +14,8 @@ public interface IServiceEntryProvider /// 服务条目集合。 IEnumerable GetEntries(); + IEnumerable GetALLEntries(); + IEnumerable GetTypes(); } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryLocate.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryLocate.cs index db09b7451..d4e38b30c 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryLocate.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryLocate.cs @@ -1,6 +1,7 @@ using Surging.Core.CPlatform.Messages; using System; using System.Linq; +using System.Runtime.CompilerServices; namespace Surging.Core.CPlatform.Runtime.Server.Implementation { @@ -23,19 +24,21 @@ public DefaultServiceEntryLocate(IServiceEntryManager serviceEntryManager) /// /// 远程调用消息。 /// 服务条目。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ServiceEntry Locate(RemoteInvokeMessage invokeMessage) { var serviceEntries = _serviceEntryManager.GetEntries(); return serviceEntries.SingleOrDefault(i => i.Descriptor.Id == invokeMessage.ServiceId); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ServiceEntry Locate(HttpMessage httpMessage) { string routePath = httpMessage.RoutePath; if (httpMessage.RoutePath.AsSpan().IndexOf("/") == -1) routePath = $"/{routePath}"; - var serviceEntries = _serviceEntryManager.GetEntries(); - return serviceEntries.SingleOrDefault(i => i.RoutePath == routePath); + var serviceEntries = _serviceEntryManager.GetAllEntries(); + return serviceEntries.SingleOrDefault(i => i.RoutePath == routePath && !i.Descriptor.GetMetadata("IsOverload")); } #endregion Implementation of IServiceEntryLocate diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryManager.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryManager.cs index a13e11ccc..b8b956a97 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryManager.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceEntryManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace Surging.Core.CPlatform.Runtime.Server.Implementation { @@ -11,7 +12,9 @@ public class DefaultServiceEntryManager : IServiceEntryManager { #region Field - private readonly IEnumerable _serviceEntries; + private IEnumerable _serviceEntries; + + private IEnumerable _allEntries; #endregion Field @@ -19,7 +22,17 @@ public class DefaultServiceEntryManager : IServiceEntryManager public DefaultServiceEntryManager(IEnumerable providers) { - var list = new List(); + UpdateEntries(providers); + } + + #endregion Constructor + + #region Implementation of IServiceEntryManager + + public void UpdateEntries(IEnumerable providers) + { + var list = new List(); + var allEntries = new List(); foreach (var provider in providers) { var entries = provider.GetEntries().ToArray(); @@ -29,23 +42,28 @@ public DefaultServiceEntryManager(IEnumerable providers) throw new InvalidOperationException($"本地包含多个Id为:{entry.Descriptor.Id} 的服务条目。"); } list.AddRange(entries); - } + allEntries.AddRange( provider.GetALLEntries()); + } _serviceEntries = list.ToArray(); + _allEntries = allEntries; } - #endregion Constructor - - #region Implementation of IServiceEntryManager - /// /// 获取服务条目集合。 /// /// 服务条目集合。 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public IEnumerable GetEntries() { return _serviceEntries; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IEnumerable GetAllEntries() + { + return _allEntries; + } + #endregion Implementation of IServiceEntryManager } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceExecutor.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceExecutor.cs index fbbca97bb..8c86d0155 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceExecutor.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceExecutor.cs @@ -3,11 +3,13 @@ using Surging.Core.CPlatform.Filters; using Surging.Core.CPlatform.Messages; using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Runtime.Client; using Surging.Core.CPlatform.Transport; using Surging.Core.CPlatform.Transport.Implementation; using Surging.Core.CPlatform.Utilities; using System; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -20,26 +22,26 @@ public class DefaultServiceExecutor : IServiceExecutor private readonly IServiceEntryLocate _serviceEntryLocate; private readonly ILogger _logger; private readonly IServiceRouteProvider _serviceRouteProvider; - private readonly IAuthorizationFilter _authorizationFilter; + private readonly IActionFilter _actionFilter; #endregion Field #region Constructor public DefaultServiceExecutor(IServiceEntryLocate serviceEntryLocate, IServiceRouteProvider serviceRouteProvider, - IAuthorizationFilter authorizationFilter, + IActionFilter actionFilter, ILogger logger) { _serviceEntryLocate = serviceEntryLocate; _logger = logger; _serviceRouteProvider = serviceRouteProvider; - _authorizationFilter = authorizationFilter; + _actionFilter = actionFilter; } #endregion Constructor #region Implementation of IServiceExecutor - + /// /// 执行。 /// @@ -53,7 +55,7 @@ public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) if (!message.IsInvokeMessage()) return; - + RemoteInvokeMessage remoteInvokeMessage; try { @@ -79,7 +81,6 @@ public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) foreach(var attachment in remoteInvokeMessage.Attachments) RpcContext.GetContext().SetAttachment(attachment.Key,attachment.Value); } - if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug("准备执行本地逻辑。"); @@ -110,30 +111,49 @@ await Task.Factory.StartNew(async () => #endregion Implementation of IServiceExecutor #region Private Method + private async Task ExecFilterSync(ServiceEntry entry, RemoteInvokeMessage remoteInvokeMessage, RemoteInvokeResultMessage resultMessage) + { + if (entry.IsPermission) + { + var serviceRoute = await _serviceRouteProvider.GetRouteByPath(entry.RoutePath); + CancellationTokenSource tokenSource = new CancellationTokenSource(); + await _actionFilter.OnActionExecutingAsync(new ServiceRouteContext + { + + InvokeMessage = remoteInvokeMessage, + ResultMessage = resultMessage, + Route = serviceRoute + }, tokenSource.Token); + } + } private async Task LocalExecuteAsync(ServiceEntry entry, RemoteInvokeMessage remoteInvokeMessage, RemoteInvokeResultMessage resultMessage) { try { - var cancelTokenSource = new CancellationTokenSource(); - var result = await entry.Func(remoteInvokeMessage.ServiceKey, remoteInvokeMessage.Parameters); - var task = result as Task; - - if (task == null) + await ExecFilterSync(entry, remoteInvokeMessage, resultMessage); + if (string.IsNullOrEmpty(resultMessage.ExceptionMessage)) { - resultMessage.Result = result; - } - else - { - await task; - var taskType = task.GetType().GetTypeInfo(); - if (taskType.IsGenericType) - resultMessage.Result = taskType.GetProperty("Result").GetValue(task); - } - - if (remoteInvokeMessage.DecodeJOject && !(resultMessage.Result is IConvertible && UtilityType.ConvertibleType.GetTypeInfo().IsAssignableFrom(resultMessage.Result.GetType()))) - { - resultMessage.Result = JsonConvert.SerializeObject(resultMessage.Result); + var result = await entry.Func(remoteInvokeMessage.ServiceKey, remoteInvokeMessage.Parameters); + var task = result as Task; + + if (task == null) + { + resultMessage.Result = result; + } + else + { + if (!task.IsCompletedSuccessfully) + await task; + var taskType = task.GetType().GetTypeInfo(); + if (taskType.IsGenericType) + resultMessage.Result = taskType.GetProperty("Result").GetValue(task); + } + + if (remoteInvokeMessage.DecodeJOject && !(resultMessage.Result is IConvertible && UtilityType.ConvertibleType.GetTypeInfo().IsAssignableFrom(resultMessage.Result.GetType()))) + { + resultMessage.Result = JsonConvert.SerializeObject(resultMessage.Result); + } } } catch (Exception exception) @@ -143,8 +163,12 @@ private async Task LocalExecuteAsync(ServiceEntry entry, RemoteInvokeMessage rem resultMessage.ExceptionMessage = GetExceptionMessage(exception); resultMessage.StatusCode = exception.HResult; } + finally + { + RpcContext.RemoveContext(); + } } - + private async Task SendRemoteInvokeResult(IMessageSender sender, string messageId, RemoteInvokeResultMessage resultMessage) { try @@ -161,7 +185,7 @@ private async Task SendRemoteInvokeResult(IMessageSender sender, string messageI if (_logger.IsEnabled(LogLevel.Error)) _logger.LogError(exception,"发送响应消息时候发生了异常。" ); } - } + } private static string GetExceptionMessage(Exception exception) { @@ -178,4 +202,4 @@ private static string GetExceptionMessage(Exception exception) #endregion Private Method } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceHost.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceHost.cs index 5f0954003..2b723deeb 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceHost.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/DefaultServiceHost.cs @@ -41,25 +41,19 @@ public override async Task StartAsync(EndPoint endPoint) return; _serverMessageListener = await _messageListenerFactory(endPoint); _serverMessageListener.Received += async (sender, message) => - { - await Task.Run(() => - { - MessageListener.OnReceived(sender, message); - }); + { + await MessageListener.OnReceived(sender, message); }; } - public override async Task StartAsync(string ip,int port) + public override async Task StartAsync(string ip, int port) { if (_serverMessageListener != null) return; _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), port)); _serverMessageListener.Received += async (sender, message) => { - await Task.Run(() => - { - MessageListener.OnReceived(sender, message); - }); + await MessageListener.OnReceived(sender, message); }; } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/AttributeServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/AttributeServiceEntryProvider.cs index 8fce43eba..9eea4af61 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/AttributeServiceEntryProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/AttributeServiceEntryProvider.cs @@ -55,6 +55,25 @@ public IEnumerable GetEntries() return entries; } + public IEnumerable GetALLEntries() + { + var services = _types.Where(i => + { + var typeInfo = i.GetTypeInfo(); + return typeInfo.IsInterface && typeInfo.GetCustomAttribute() != null; + }).Distinct().ToArray(); + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation($"发现了以下服务:{string.Join(",", services.Select(i => i.ToString()))}。"); + } + var entries = new List(); + foreach (var service in services) + { + entries.AddRange(_clrServiceEntryFactory.CreateServiceEntry(service)); + } + return entries; + } + public IEnumerable GetTypes() { var services = _types.Where(i => diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpDeleteAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpDeleteAttribute.cs new file mode 100644 index 000000000..b5c87960f --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpDeleteAttribute.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpDeleteAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "DELETE" }; + + public HttpDeleteAttribute() + : base(_supportedMethods) + { + } + + public HttpDeleteAttribute(bool isRegisterMetadata) + : base(_supportedMethods,isRegisterMetadata) + { + + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpGetAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpGetAttribute.cs new file mode 100644 index 000000000..165f19976 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpGetAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpGetAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "GET" }; + + public HttpGetAttribute() + : base(_supportedMethods) + { + } + + public HttpGetAttribute(bool isRegisterMetadata) + : base(_supportedMethods, isRegisterMetadata) + { + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpHeadAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpHeadAttribute.cs new file mode 100644 index 000000000..6f41a5102 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpHeadAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpHeadAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "HEAD" }; + + public HttpHeadAttribute() + : base(_supportedMethods) + { + } + + public HttpHeadAttribute(bool isRegisterMetadata) + : base(_supportedMethods, isRegisterMetadata) + { + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpMethodAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpMethodAttribute.cs new file mode 100644 index 000000000..f85b9d325 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpMethodAttribute.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public abstract class HttpMethodAttribute : Attribute + { + + public HttpMethodAttribute(IEnumerable httpMethods) + : this(httpMethods, false) + { + } + + public HttpMethodAttribute(IEnumerable httpMethods,bool isRegisterMetadata) + { + if (httpMethods == null) + { + throw new ArgumentNullException(nameof(httpMethods)); + } + + HttpMethods = httpMethods; + IsRegisterMetadata = isRegisterMetadata; + } + public IEnumerable HttpMethods { get; } + public bool IsRegisterMetadata { get; } + + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpOptionsAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpOptionsAttribute.cs new file mode 100644 index 000000000..273666452 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpOptionsAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpOptionsAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "OPTIONS" }; + + public HttpOptionsAttribute() + : base(_supportedMethods) + { + } + + public HttpOptionsAttribute(bool isRegisterMetadata) + : base(_supportedMethods, isRegisterMetadata) + { + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPatchAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPatchAttribute.cs new file mode 100644 index 000000000..3f0ac20f0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPatchAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpPatchAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "PATCH" }; + + public HttpPatchAttribute() + : base(_supportedMethods) + { + } + + public HttpPatchAttribute(bool isRegisterMetadata) + : base(_supportedMethods, isRegisterMetadata) + { + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPostAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPostAttribute.cs new file mode 100644 index 000000000..15d39d1f4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPostAttribute.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpPostAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "POST" }; + + public HttpPostAttribute() + : base(_supportedMethods) + { + } + + public HttpPostAttribute(bool isRegisterMetadata) + : base(_supportedMethods, isRegisterMetadata) + { + + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPutAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPutAttribute.cs new file mode 100644 index 000000000..673cdbdb6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/HttpPutAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class HttpPutAttribute : HttpMethodAttribute + { + private static readonly IEnumerable _supportedMethods = new[] { "PUT" }; + + public HttpPutAttribute() + : base(_supportedMethods) + { + } + + public HttpPutAttribute(bool isRegisterMetadata) + : base(_supportedMethods, isRegisterMetadata) + { + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ReactiveAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ReactiveAttribute.cs new file mode 100644 index 000000000..191db29b6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ReactiveAttribute.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class ReactiveAttribute : Attribute + { + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceBundleAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceBundleAttribute.cs index 32c82f479..8328af33b 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceBundleAttribute.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceBundleAttribute.cs @@ -8,10 +8,13 @@ namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery. [AttributeUsage(AttributeTargets.Interface)] public class ServiceBundleAttribute : Attribute { - public ServiceBundleAttribute(string routeTemplate) + public ServiceBundleAttribute(string routeTemplate,bool isPrefix=true) { RouteTemplate = routeTemplate; + IsPrefix = isPrefix; } public string RouteTemplate { get; } + + public bool IsPrefix { get; } } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceRouteAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceRouteAttribute.cs new file mode 100644 index 000000000..dd791bf0c --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Attributes/ServiceRouteAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes +{ + public class ServiceRouteAttribute: Attribute + { + public ServiceRouteAttribute(string template) + { + Template = template; + } + + public string Template { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Implementation/ClrServiceEntryFactory.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Implementation/ClrServiceEntryFactory.cs index 0957337fa..41e8c25ab 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Implementation/ClrServiceEntryFactory.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceDiscovery/Implementation/ClrServiceEntryFactory.cs @@ -9,8 +9,16 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Text; using System.Threading.Tasks; +using Surging.Core.CPlatform.Validation; using static Surging.Core.CPlatform.Utilities.FastInvoke; +using System.Threading; +using System.Runtime.CompilerServices; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Exceptions; +using System.Collections.Concurrent; +using Surging.Core.CPlatform.Ioc; namespace Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Implementation { @@ -23,14 +31,18 @@ public class ClrServiceEntryFactory : IClrServiceEntryFactory private readonly CPlatformContainer _serviceProvider; private readonly IServiceIdGenerator _serviceIdGenerator; private readonly ITypeConvertibleService _typeConvertibleService; + private readonly IValidationProcessor _validationProcessor; + private readonly ConcurrentDictionary> _resultDictionary = + new ConcurrentDictionary>(); #endregion Field #region Constructor - public ClrServiceEntryFactory(CPlatformContainer serviceProvider, IServiceIdGenerator serviceIdGenerator, ITypeConvertibleService typeConvertibleService) + public ClrServiceEntryFactory(CPlatformContainer serviceProvider, IServiceIdGenerator serviceIdGenerator, ITypeConvertibleService typeConvertibleService, IValidationProcessor validationProcessor) { _serviceProvider = serviceProvider; _serviceIdGenerator = serviceIdGenerator; _typeConvertibleService = typeConvertibleService; + _validationProcessor = validationProcessor; } #endregion Constructor @@ -45,10 +57,16 @@ public ClrServiceEntryFactory(CPlatformContainer serviceProvider, IServiceIdGene /// Ŀϡ public IEnumerable CreateServiceEntry(Type service) { - var routeTemplate = service.GetCustomAttribute() ; + var routeTemplate = service.GetCustomAttribute(); foreach (var methodInfo in service.GetTypeInfo().GetMethods()) { - yield return Create(methodInfo,service.Name, routeTemplate.RouteTemplate); + var serviceRoute = methodInfo.GetCustomAttribute(); + var routeTemplateVal = routeTemplate.RouteTemplate; + if (!routeTemplate.IsPrefix && serviceRoute != null) + routeTemplateVal = serviceRoute.Template; + else if (routeTemplate.IsPrefix && serviceRoute != null) + routeTemplateVal = $"{ routeTemplate.RouteTemplate}/{ serviceRoute.Template}"; + yield return Create(methodInfo, service.Name, routeTemplateVal); } } #endregion Implementation of IClrServiceEntryFactory @@ -64,46 +82,137 @@ private ServiceEntry Create(MethodInfo method, string serviceName, string routeT Id = serviceId, RoutePath = RoutePatternParser.Parse(routeTemplate, serviceName, method.Name) }; - var descriptorAttributes = method.GetCustomAttributes(); foreach (var descriptorAttribute in descriptorAttributes) { descriptorAttribute.Apply(serviceDescriptor); } + var httpMethodAttributes = attributes.Where(p => p is HttpMethodAttribute).Select(p => p as HttpMethodAttribute).ToList(); + var httpMethods = new List(); + StringBuilder httpMethod = new StringBuilder(); + foreach (var attribute in httpMethodAttributes) + { + httpMethods.AddRange(attribute.HttpMethods); + if (attribute.IsRegisterMetadata) + httpMethod.AppendJoin(',',attribute.HttpMethods).Append(","); + } + if (httpMethod.Length > 0) + { + httpMethod.Length = httpMethod.Length - 1; + serviceDescriptor.HttpMethod(httpMethod.ToString()); + } var authorization = attributes.Where(p => p is AuthorizationFilterAttribute).FirstOrDefault(); - if(authorization != null) - serviceDescriptor.EnableAuthorization(true); if (authorization != null) - { + serviceDescriptor.EnableAuthorization(true); + if (authorization != null) + { serviceDescriptor.AuthType(((authorization as AuthorizationAttribute)?.AuthType) ?? AuthorizationType.AppSecret); } var fastInvoker = GetHandler(serviceId, method); + + var methodValidateAttribute = attributes.Where(p => p is ValidateAttribute) + .Cast().FirstOrDefault(); + var isReactive = attributes.Any(p => p is ReactiveAttribute); return new ServiceEntry { Descriptor = serviceDescriptor, - RoutePath= serviceDescriptor.RoutePath, - MethodName=method.Name, - Type= method.DeclaringType, + RoutePath = serviceDescriptor.RoutePath, + Methods=httpMethods, + MethodName = method.Name, + Parameters = method.GetParameters(), + IsPermission = method.DeclaringType.GetCustomAttribute() != null || attributes.Any(p => p is BaseActionFilterAttribute), + Type = method.DeclaringType, Attributes = attributes, - Func = (key, parameters) => + Func = async (key, parameters) => { - var instance = _serviceProvider.GetInstances(key, method.DeclaringType); + object instance = null; + if (AppConfig.ServerOptions.IsModulePerLifetimeScope) + instance = _serviceProvider.GetInstancePerLifetimeScope(key, method.DeclaringType); + else + instance = _serviceProvider.GetInstances(key, method.DeclaringType); var list = new List(); foreach (var parameterInfo in method.GetParameters()) { + //ǷĬֵжϣĬֵûûȡĬֵ + if (parameterInfo.HasDefaultValue && !parameters.ContainsKey(parameterInfo.Name)) + { + list.Add(parameterInfo.DefaultValue); + continue; + } + else if(parameterInfo.ParameterType == typeof(CancellationToken)) + { + list.Add(new CancellationToken()); + continue; + } var value = parameters[parameterInfo.Name]; + + if(methodValidateAttribute !=null) + _validationProcessor.Validate(parameterInfo, value); + var parameterType = parameterInfo.ParameterType; var parameter = _typeConvertibleService.Convert(value, parameterType); list.Add(parameter); } - var result = fastInvoker(instance, list.ToArray()); - return Task.FromResult(result); + if (!isReactive) + { + var result = fastInvoker(instance, list.ToArray()); + return await Task.FromResult(result); + } + else + { + var serviceBehavior = instance as IServiceBehavior; + var callbackTask = RegisterResultCallbackAsync(serviceBehavior.MessageId, Task.Factory.CancellationToken); + serviceBehavior.Received += MessageListener_Received; + var result = fastInvoker(instance, list.ToArray()); + return await callbackTask; + } } }; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private async Task RegisterResultCallbackAsync(string id, CancellationToken cancellationToken) + { + + var task = new ManualResetValueTaskSource(); + _resultDictionary.TryAdd(id, task); + try + { + var result = await task.AwaitValue(cancellationToken); + return result.GetContent()?.Result; + } + finally + { + //ɾص + ManualResetValueTaskSource value; + _resultDictionary.TryRemove(id, out value); + value.SetCanceled(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private async Task MessageListener_Received(TransportMessage message) + { + ManualResetValueTaskSource task; + if (!_resultDictionary.TryGetValue(message.Id, out task)) + return; + + if (message.IsReactiveMessage()) + { + var content = message.GetContent(); + if (!string.IsNullOrEmpty(content.ExceptionMessage)) + { + task.SetException(new CPlatformCommunicationException(content.ExceptionMessage, content.StatusCode)); + } + else + { + task.SetResult(message); + } + } + } + private FastInvokeHandler GetHandler(string key, MethodInfo method) { var objInstance = ServiceResolver.Current.GetService(null, key); diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceHostAbstract.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceHostAbstract.cs index 8ba0c18e9..24c616624 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceHostAbstract.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/Implementation/ServiceHostAbstract.cs @@ -15,6 +15,8 @@ public abstract class ServiceHostAbstract : IServiceHost private readonly IServiceExecutor _serviceExecutor; + public IServiceExecutor ServiceExecutor { get => _serviceExecutor; } + /// /// 消息监听者。 /// diff --git a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/ServiceEntry.cs b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/ServiceEntry.cs index 83c599a4a..f7569b9af 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/ServiceEntry.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Runtime/Server/ServiceEntry.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Runtime.Server @@ -13,10 +14,12 @@ public class ServiceEntry /// 执行委托。 /// public Func, Task> Func { get; set; } - + public IEnumerable Methods { get; set; } public string RoutePath { get; set; } public Type Type { get; set; } + public bool IsPermission { get; set; } public string MethodName { get; set; } + public ParameterInfo[] Parameters { get; set; } public List Attributes { get; set; } /// /// 服务描述符。 diff --git a/src/Surging.Core/Surging.Core.CPlatform/Serialization/JsonConverters/DateTimeJsonConverter.cs b/src/Surging.Core/Surging.Core.CPlatform/Serialization/JsonConverters/DateTimeJsonConverter.cs new file mode 100644 index 000000000..7caae33db --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Serialization/JsonConverters/DateTimeJsonConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Surging.Core.CPlatform.Serialization.JsonConverters +{ + public class DateTimeJsonConverter : JsonConverter + { + private readonly string _dateFormatString; + public DateTimeJsonConverter() + { + _dateFormatString = "yyyy-MM-dd HH:mm:ss"; + } + + public DateTimeJsonConverter(string dateFormatString) + { + _dateFormatString = dateFormatString; + } + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.Parse(reader.GetString()); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToUniversalTime().ToString(_dateFormatString)); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/ServiceDescriptor.cs b/src/Surging.Core/Surging.Core.CPlatform/ServiceDescriptor.cs index 3c20cd16f..87bbdc178 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/ServiceDescriptor.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/ServiceDescriptor.cs @@ -1,4 +1,5 @@ -using Surging.Core.CPlatform.Filters.Implementation; +using Newtonsoft.Json; +using Surging.Core.CPlatform.Filters.Implementation; using System; using System.Collections.Generic; using System.Linq; @@ -30,7 +31,6 @@ public static string GroupName(this ServiceDescriptor descriptor) public static ServiceDescriptor GroupName(this ServiceDescriptor descriptor, string groupName) { descriptor.Metadatas["GroupName"] = groupName; - return descriptor; } @@ -80,6 +80,17 @@ public static bool EnableAuthorization(this ServiceDescriptor descriptor) return descriptor.GetMetadata("EnableAuthorization", false); } + public static ServiceDescriptor HttpMethod(this ServiceDescriptor descriptor, string httpMethod) + { + descriptor.Metadatas["HttpMethod"] = httpMethod; + return descriptor; + } + + public static string HttpMethod(this ServiceDescriptor descriptor) + { + return descriptor.GetMetadata("httpMethod", ""); + } + /// /// 设置是否禁用外网访问 /// @@ -109,8 +120,9 @@ public static bool DisableNetwork(this ServiceDescriptor descriptor) /// 服务描述符。 public static string AuthType(this ServiceDescriptor descriptor) { - return descriptor.GetMetadata("AuthType", AuthorizationType.AppSecret.ToString()); + return descriptor.GetMetadata("AuthType", ""); } + /// /// 设置授权类型 @@ -198,7 +210,7 @@ public ServiceDescriptor() /// /// 元数据。 - /// + /// public IDictionary Metadatas { get; set; } /// diff --git a/src/Surging.Core/Surging.Core.CPlatform/ServiceHostBuilderExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/ServiceHostBuilderExtensions.cs index 48040441b..49173f3c1 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/ServiceHostBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/ServiceHostBuilderExtensions.cs @@ -1,5 +1,4 @@ - -using Autofac; +using Autofac; using Surging.Core.CPlatform.Support; using System.Linq; using Surging.Core.CPlatform.Routing; @@ -28,46 +27,27 @@ public static class ServiceHostBuilderExtensions { public static IServiceHostBuilder UseServer(this IServiceHostBuilder hostBuilder, string ip, int port, string token = "True") { - return hostBuilder.MapServices(mapper => + return hostBuilder.MapServices(async mapper => { BuildServiceEngine(mapper); - mapper.Resolve().SetServiceCommandsAsync(); - string serviceToken = mapper.Resolve().GeneratorToken(token); - int _port = AppConfig.ServerOptions.Port == 0 ? port : AppConfig.ServerOptions.Port; - string _ip = AppConfig.ServerOptions.Ip ?? ip; - _port = AppConfig.ServerOptions.IpEndpoint?.Port ?? _port; - _ip = AppConfig.ServerOptions.IpEndpoint?.Address.ToString() ?? _ip; - if (_ip.IndexOf(".") < 0 || _ip == "" || _ip == "0.0.0.0") - { - NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface adapter in nics) - { - if (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet && (_ip == "" || _ip == "0.0.0.0" || _ip == adapter.Name)) - { - IPInterfaceProperties ipxx = adapter.GetIPProperties(); - UnicastIPAddressInformationCollection ipCollection = ipxx.UnicastAddresses; - foreach (UnicastIPAddressInformation ipadd in ipCollection) - { - if (ipadd.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) - { - _ip = ipadd.Address.ToString(); - } - } - } - } - } - var mappingIp = AppConfig.ServerOptions.MappingIP ?? _ip; - var mappingPort = AppConfig.ServerOptions.MappingPort; - if (mappingPort == 0) - mappingPort = _port; - ConfigureRoute(mapper, mappingIp, mappingPort, serviceToken); + mapper.Resolve().GeneratorToken(token); + int _port = AppConfig.ServerOptions.Port = AppConfig.ServerOptions.Port == 0 ? port : AppConfig.ServerOptions.Port; + string _ip = AppConfig.ServerOptions.Ip = AppConfig.ServerOptions.Ip ?? ip; + _port = AppConfig.ServerOptions.Port = AppConfig.ServerOptions.IpEndpoint?.Port ?? _port; + _ip = AppConfig.ServerOptions.Ip = AppConfig.ServerOptions.IpEndpoint?.Address.ToString() ?? _ip; + _ip = NetUtils.GetHostAddress(_ip); mapper.Resolve().Initialize(); + if (!AppConfig.ServerOptions.DisableServiceRegistration) + { + await mapper.Resolve().SetServiceCommandsAsync(); + await ConfigureRoute(mapper); + } var serviceHosts = mapper.Resolve>(); Task.Factory.StartNew(async () => { - foreach(var serviceHost in serviceHosts) - await serviceHost.StartAsync(_ip,_port); + foreach (var serviceHost in serviceHosts) + await serviceHost.StartAsync(_ip, _port); mapper.Resolve().NotifyStarted(); }).Wait(); }); @@ -78,7 +58,7 @@ public static IServiceHostBuilder UseServer(this IServiceHostBuilder hostBuilder var serverOptions = new SurgingServerOptions(); options.Invoke(serverOptions); AppConfig.ServerOptions = serverOptions; - return hostBuilder.UseServer(serverOptions.Ip,serverOptions.Port,serverOptions.Token); + return hostBuilder.UseServer(serverOptions.Ip, serverOptions.Port, serverOptions.Token); } public static IServiceHostBuilder UseClient(this IServiceHostBuilder hostBuilder) @@ -92,9 +72,9 @@ public static IServiceHostBuilder UseClient(this IServiceHostBuilder hostBuilder return new ServiceSubscriber { Address = new[] { new IpAddressModel { - Ip = Dns.GetHostEntry(Dns.GetHostName()) - .AddressList.FirstOrDefault - (a => a.AddressFamily.ToString().Equals("InterNetwork")).ToString() } }, + Ip = Dns.GetHostEntry(Dns.GetHostName()) + .AddressList.FirstOrDefault + (a => a.AddressFamily.ToString().Equals("InterNetwork")).ToString() } }, ServiceDescriptor = i.Descriptor }; }).ToList(); @@ -110,38 +90,27 @@ public static void BuildServiceEngine(IContainer container) var builder = new ContainerBuilder(); container.Resolve().Build(builder); - var configBuilder= container.Resolve(); + var configBuilder = container.Resolve(); var appSettingPath = Path.Combine(AppConfig.ServerOptions.RootPath, "appsettings.json"); - configBuilder.AddCPlatformFile("${appsettingspath}|"+ appSettingPath, optional: false, reloadOnChange: true); + configBuilder.AddCPlatformFile("${appsettingspath}|" + appSettingPath, optional: false, reloadOnChange: true); builder.Update(container); } } - public static void ConfigureRoute(IContainer mapper,string mappingIp,int mappingPort,string serviceToken) + public static async Task ConfigureRoute(IContainer mapper) { - var serviceEntryManager = mapper.Resolve(); if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.Tcp || AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) - new ServiceRouteWatch(mapper.Resolve(), () => - { - var addess = new IpAddressModel - { - Ip = mappingIp, - Port = mappingPort, - ProcessorTime = Math.Round(Convert.ToDecimal(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds), 2, MidpointRounding.AwayFromZero), - }; - RpcContext.GetContext().SetAttachment("Host", addess); - var addressDescriptors = serviceEntryManager.GetEntries().Select(i => - { - i.Descriptor.Token = serviceToken; - return new ServiceRoute - { - Address = new[] { addess }, - ServiceDescriptor = i.Descriptor - }; - }).ToList(); - mapper.Resolve().SetRoutesAsync(addressDescriptors).Wait(); - }); + { + var routeProvider = mapper.Resolve(); + if (AppConfig.ServerOptions.EnableRouteWatch) + new ServiceRouteWatch(mapper.Resolve(), + async () => await routeProvider.RegisterRoutes( + Math.Round(Convert.ToDecimal(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds), 2, MidpointRounding.AwayFromZero))); + else + await routeProvider.RegisterRoutes(0); + } } + } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/IBreakeRemoteInvokeService.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/IBreakeRemoteInvokeService.cs index 22883d07c..5dfc059e3 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/IBreakeRemoteInvokeService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/IBreakeRemoteInvokeService.cs @@ -1,7 +1,5 @@ using Surging.Core.CPlatform.Messages; -using System; using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Support diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/IClusterInvoker.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/IClusterInvoker.cs index 55774d068..421528473 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/IClusterInvoker.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/IClusterInvoker.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Support diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/BreakeRemoteInvokeService.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/BreakeRemoteInvokeService.cs index 3539b6e84..80201248f 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/BreakeRemoteInvokeService.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/BreakeRemoteInvokeService.cs @@ -13,6 +13,7 @@ using Autofac; using System.Threading; using Surging.Core.CPlatform.Filters.Implementation; +using System.Runtime.CompilerServices; namespace Surging.Core.CPlatform.Support.Implementation { @@ -23,7 +24,7 @@ public class BreakeRemoteInvokeService : IBreakeRemoteInvokeService private readonly ILogger _logger; private readonly ConcurrentDictionary _serviceInvokeListenInfo = new ConcurrentDictionary(); private readonly IHashAlgorithm _hashAlgorithm; - private readonly IEnumerable exceptionFilters=new List(); + private readonly IEnumerable exceptionFilters = new List(); public BreakeRemoteInvokeService(IHashAlgorithm hashAlgorithm, IServiceCommandProvider commandProvider, ILogger logger, IRemoteInvokeService remoteInvokeService, @@ -34,26 +35,30 @@ public BreakeRemoteInvokeService(IHashAlgorithm hashAlgorithm, IServiceCommandPr _logger = logger; _hashAlgorithm = hashAlgorithm; if (serviceProvider.Current.IsRegistered()) - exceptionFilters= serviceProvider.GetInstances>(); + exceptionFilters = serviceProvider.GetInstances>(); } public async Task InvokeAsync(IDictionary parameters, string serviceId, string serviceKey, bool decodeJOject) { var serviceInvokeInfos = _serviceInvokeListenInfo.GetOrAdd(serviceId, - new ServiceInvokeListenInfo() { FirstInvokeTime=DateTime.Now, - FinalRemoteInvokeTime =DateTime.Now }); - var command = await _commandProvider.GetCommand(serviceId); + new ServiceInvokeListenInfo() + { + FirstInvokeTime = DateTime.Now, + FinalRemoteInvokeTime = DateTime.Now + }); + var vt = _commandProvider.GetCommand(serviceId); + var command = vt.IsCompletedSuccessfully ? vt.Result : await vt; var intervalSeconds = (DateTime.Now - serviceInvokeInfos.FinalRemoteInvokeTime).TotalSeconds; bool reachConcurrentRequest() => serviceInvokeInfos.ConcurrentRequests > command.MaxConcurrentRequests; bool reachRequestVolumeThreshold() => intervalSeconds <= 10 && serviceInvokeInfos.SinceFaultRemoteServiceRequests > command.BreakerRequestVolumeThreshold; bool reachErrorThresholdPercentage() => (double)serviceInvokeInfos.FaultRemoteServiceRequests / (double)(serviceInvokeInfos.RemoteServiceRequests ?? 1) * 100 > command.BreakeErrorThresholdPercentage; - var hashCode = GetHashCode(command,parameters); + var item = GetHashItem(command, parameters); if (command.BreakerForceClosed) { _serviceInvokeListenInfo.AddOrUpdate(serviceId, new ServiceInvokeListenInfo(), (k, v) => { v.LocalServiceRequests++; return v; }); - return null; + return await MonitorRemoteInvokeAsync(parameters, serviceId, serviceKey, decodeJOject, command.ExecutionTimeoutInMilliseconds, item); } else { @@ -61,7 +66,7 @@ bool reachErrorThresholdPercentage() => { if (intervalSeconds * 1000 > command.BreakeSleepWindowInMilliseconds) { - return await MonitorRemoteInvokeAsync(parameters, serviceId, serviceKey, decodeJOject, command.ExecutionTimeoutInMilliseconds, hashCode); + return await MonitorRemoteInvokeAsync(parameters, serviceId, serviceKey, decodeJOject, command.ExecutionTimeoutInMilliseconds, item); } else { @@ -71,14 +76,13 @@ bool reachErrorThresholdPercentage() => } else { - return await MonitorRemoteInvokeAsync(parameters, serviceId, serviceKey, decodeJOject, command.ExecutionTimeoutInMilliseconds, hashCode); + return await MonitorRemoteInvokeAsync(parameters, serviceId, serviceKey, decodeJOject, command.ExecutionTimeoutInMilliseconds, item); } } } - private async Task MonitorRemoteInvokeAsync(IDictionary parameters, string serviceId, string serviceKey, bool decodeJOject, int requestTimeout,int hashCode) + private async Task MonitorRemoteInvokeAsync(IDictionary parameters, string serviceId, string serviceKey, bool decodeJOject, int requestTimeout, string item) { - var serviceInvokeInfo = _serviceInvokeListenInfo.GetOrAdd(serviceId, new ServiceInvokeListenInfo()); CancellationTokenSource source = new CancellationTokenSource(); var token = source.Token; var invokeMessage = new RemoteInvokeMessage @@ -100,7 +104,7 @@ private async Task MonitorRemoteInvokeAsync(IDictiona }); var message = await _remoteInvokeService.InvokeAsync(new RemoteInvokeContext { - HashCode=hashCode , + Item = item, InvokeMessage = invokeMessage }, requestTimeout); _serviceInvokeListenInfo.AddOrUpdate(serviceId, new ServiceInvokeListenInfo(), (k, v) => @@ -110,7 +114,7 @@ private async Task MonitorRemoteInvokeAsync(IDictiona }); return message; } - catch(Exception ex) + catch (Exception ex) { _serviceInvokeListenInfo.AddOrUpdate(serviceId, new ServiceInvokeListenInfo(), (k, v) => { @@ -126,23 +130,24 @@ private async Task MonitorRemoteInvokeAsync(IDictiona private async Task ExecuteExceptionFilter(Exception ex, RemoteInvokeMessage invokeMessage, CancellationToken token) { - foreach (var filter in exceptionFilters) + foreach (var filter in exceptionFilters) + { + await filter.ExecuteExceptionFilterAsync(new RpcActionExecutedContext { - await filter.ExecuteExceptionFilterAsync(new RpcActionExecutedContext - { - Exception = ex, - InvokeMessage = invokeMessage - }, token); - } + Exception = ex, + InvokeMessage = invokeMessage + }, token); + } } - private int GetHashCode(ServiceCommand command, IDictionary parameters) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private string GetHashItem(ServiceCommand command, IDictionary parameters) { - var result = 0; - if(command.ShuntStrategy==AddressSelectorMode.HashAlgorithm) + string result = ""; + if (command.ShuntStrategy == AddressSelectorMode.HashAlgorithm) { var parameter = parameters.Values.FirstOrDefault(); - result= _hashAlgorithm.Hash(parameter?.ToString()); + result = parameter?.ToString(); } return result; } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverHandoverInvoker.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverHandoverInvoker.cs index a8ef3b660..bbb6dbc5c 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverHandoverInvoker.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverHandoverInvoker.cs @@ -1,14 +1,12 @@ using Surging.Core.CPlatform.Convertibles; using Surging.Core.CPlatform.Messages; using Surging.Core.CPlatform.Runtime.Client; -using System; using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Support.Implementation { - public class FailoverHandoverInvoker: IClusterInvoker + public class FailoverHandoverInvoker: IClusterInvoker { #region Field private readonly IRemoteInvokeService _remoteInvokeService; @@ -30,12 +28,13 @@ public FailoverHandoverInvoker(IRemoteInvokeService remoteInvokeService, IServic #endregion Constructor - public async Task Invoke(IDictionary parameters, string serviceId, string _serviceKey,bool decodeJOject) + public async Task Invoke(IDictionary parameters, string serviceId, string _serviceKey, bool decodeJOject) { var time = 0; T result = default(T); RemoteInvokeResultMessage message = null; - var command =await _commandProvider.GetCommand(serviceId); + var vtCommand = _commandProvider.GetCommand(serviceId); + var command = vtCommand.IsCompletedSuccessfully ? vtCommand.Result : await vtCommand; do { message = await _breakeRemoteInvokeService.InvokeAsync(parameters, serviceId, _serviceKey, decodeJOject); @@ -48,7 +47,8 @@ public async Task Invoke(IDictionary parameters, string se public async Task Invoke(IDictionary parameters, string serviceId, string _serviceKey, bool decodeJOject) { var time = 0; - var command =await _commandProvider.GetCommand(serviceId); + var vtCommand = _commandProvider.GetCommand(serviceId); + var command = vtCommand.IsCompletedSuccessfully ? vtCommand.Result : await vtCommand; while (await _breakeRemoteInvokeService.InvokeAsync(parameters, serviceId, _serviceKey, decodeJOject) == null && ++time < command.FailoverCluster) ; } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverInjectionInvoker.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverInjectionInvoker.cs index 6ac9d56fe..4de72fa34 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverInjectionInvoker.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/FailoverInjectionInvoker.cs @@ -1,10 +1,9 @@ -using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Convertibles; +using Surging.Core.CPlatform.Runtime.Server; using System; using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; using System.Linq; -using Surging.Core.CPlatform.Convertibles; +using System.Threading.Tasks; namespace Surging.Core.CPlatform.Support.Implementation { @@ -23,7 +22,8 @@ public FailoverInjectionInvoker(IServiceCommandProvider serviceCommandProvider, public async Task Invoke(IDictionary parameters, string serviceId, string serviceKey, bool decodeJOject) { - var command = await _serviceCommandProvider.GetCommand(serviceId); + var vt = _serviceCommandProvider.GetCommand(serviceId); + var command = vt.IsCompletedSuccessfully ? vt.Result : await vt; var result = await _serviceCommandProvider.Run(command.Injection, command.InjectionNamespaces); if (result is Boolean) { @@ -38,7 +38,8 @@ public async Task Invoke(IDictionary parameters, string serviceI public async Task Invoke(IDictionary parameters, string serviceId, string serviceKey, bool decodeJOject) { - var command =await _serviceCommandProvider.GetCommand(serviceId); + var vt = _serviceCommandProvider.GetCommand(serviceId); + var command = vt.IsCompletedSuccessfully ? vt.Result : await vt; var injectionResult = await _serviceCommandProvider.Run(command.Injection, command.InjectionNamespaces); if (injectionResult is Boolean) { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/ServiceCommandProvider.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/ServiceCommandProvider.cs index 4d5d1d8dc..b0e9ef9ae 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/ServiceCommandProvider.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/Implementation/ServiceCommandProvider.cs @@ -28,16 +28,17 @@ public ServiceCommandProvider(IServiceEntryManager serviceEntryManager, IService } } - public override ValueTask GetCommand(string serviceId) + public override async ValueTask GetCommand(string serviceId) { var result = _serviceCommand.GetValueOrDefault(serviceId); if (result == null) { - return new ValueTask(GetCommandAsync(serviceId)); + var task = GetCommandAsync(serviceId); + return task.IsCompletedSuccessfully ? task.Result : await task; } else { - return new ValueTask(result); + return result; } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommand.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommand.cs index 052955467..6b5d61b99 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommand.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommand.cs @@ -1,9 +1,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation; -using System; -using System.Collections.Generic; -using System.Text; namespace Surging.Core.CPlatform.Support { @@ -28,7 +25,13 @@ public ServiceCommand() FallBackName = AppConfig.ServerOptions.FallBackName; } } + /// + /// 故障转移次数 + /// public int FailoverCluster { get; set; } = 3; + /// + /// 是否强制开启熔断 + /// public bool CircuitBreakerForceOpen { get; set; } /// /// 容错策略 @@ -42,13 +45,13 @@ public ServiceCommand() /// /// 是否开启缓存 /// + [JsonIgnore] public bool RequestCacheEnabled { get; set; } /// /// 注入 /// public string Injection { get; set; } = "return null"; - /// /// IFallbackInvoker 实例名称 /// @@ -58,9 +61,10 @@ public ServiceCommand() /// [JsonConverter(typeof(StringEnumConverter))] public AddressSelectorMode ShuntStrategy { get; set; } = AddressSelectorMode.Polling; - + /// + /// 注入命名空间 + /// public string[] InjectionNamespaces { get; set; } - /// /// 错误率达到多少开启熔断保护 /// @@ -70,12 +74,12 @@ public ServiceCommand() /// public int BreakeSleepWindowInMilliseconds { get; set; } = 60000; /// - /// 是否强制关闭熔断 + /// 是否强制关闭熔断 /// public bool BreakerForceClosed { get; set; } /// - /// 10秒钟内至少多少请求失败,熔断器才发挥起作用 + /// 10秒钟内至少多少请求失败,熔断器才发挥起作用 /// public int BreakerRequestVolumeThreshold { get; set; } = 20; diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommandDescriptor.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommandDescriptor.cs index 45ee809a9..da42ed5cb 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommandDescriptor.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceCommandDescriptor.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Surging.Core.CPlatform.Support +namespace Surging.Core.CPlatform.Support { public class ServiceCommandDescriptor:ServiceCommand { diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceInvokeListenInfo.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceInvokeListenInfo.cs index 295e165c9..c4a984adc 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceInvokeListenInfo.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/ServiceInvokeListenInfo.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; -using System.Text; namespace Surging.Core.CPlatform.Support { - public class ServiceInvokeListenInfo + public class ServiceInvokeListenInfo { /// diff --git a/src/Surging.Core/Surging.Core.CPlatform/Support/StrategyType.cs b/src/Surging.Core/Surging.Core.CPlatform/Support/StrategyType.cs index 7be6f7d2d..183ecfc93 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Support/StrategyType.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Support/StrategyType.cs @@ -1,13 +1,21 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Surging.Core.CPlatform.Support +namespace Surging.Core.CPlatform.Support { - public enum StrategyType + /// + /// 容错策略 + /// + public enum StrategyType { - Failover=0, - Injection=1, - FallBack=2, + /// + /// 故障转移策略、失败切换远程服务机制 + /// + Failover = 0, + /// + /// 脚本注入策略、失败执行注入脚本 + /// + Injection = 1, + /// + /// 回退策略、失败时调用通过FallBackName指定的接口 + /// + FallBack = 2, } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Surging.Core.CPlatform.csproj b/src/Surging.Core/Surging.Core.CPlatform/Surging.Core.CPlatform.csproj index 7f7bdd2c3..fa9dbb049 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Surging.Core.CPlatform.csproj +++ b/src/Surging.Core/Surging.Core.CPlatform/Surging.Core.CPlatform.csproj @@ -1,16 +1,15 @@  - netcoreapp2.1 + net6.0 false surging fanly https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 1.Fix incorrect question of Error Threshold Percentage -2.Service metadata add DisableNetwork option -3.Upgrade to core 2.1 + 1.multiple register center cluster +2. fix bug @@ -20,16 +19,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.CPlatform/Transport/IMessageListener.cs b/src/Surging.Core/Surging.Core.CPlatform/Transport/IMessageListener.cs index a81727f9c..6f4e146c0 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Transport/IMessageListener.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Transport/IMessageListener.cs @@ -1,5 +1,4 @@ using Surging.Core.CPlatform.Messages; -using System.Net; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Transport diff --git a/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClient.cs b/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClient.cs index 9e162072a..4149800cf 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClient.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClient.cs @@ -1,4 +1,5 @@ using Surging.Core.CPlatform.Messages; +using System.Threading; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Transport @@ -13,6 +14,6 @@ public interface ITransportClient /// /// 远程调用消息模型。 /// 远程调用消息的传输消息。 - Task SendAsync(RemoteInvokeMessage message); + Task SendAsync(RemoteInvokeMessage message, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClientFactory.cs b/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClientFactory.cs index be12c18bb..b29766e79 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClientFactory.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Transport/ITransportClientFactory.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Threading.Tasks; namespace Surging.Core.CPlatform.Transport { @@ -12,6 +13,6 @@ public interface ITransportClientFactory /// /// 终结点。 /// 传输客户端实例。 - ITransportClient CreateClient(EndPoint endPoint); + Task CreateClientAsync(EndPoint endPoint); } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/RpcContext.cs b/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/RpcContext.cs index be9a05072..c244f5906 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/RpcContext.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/RpcContext.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Text; +using System.Runtime.CompilerServices; using System.Threading; namespace Surging.Core.CPlatform.Transport.Implementation @@ -10,42 +9,50 @@ public class RpcContext { private ConcurrentDictionary contextParameters; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ConcurrentDictionary GetContextParameters() { return contextParameters; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetAttachment(string key,object value) { contextParameters.AddOrUpdate(key, value,(k,v)=>value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public object GetAttachment(string key) { contextParameters.TryGetValue(key, out object result); return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetContextParameters(ConcurrentDictionary contextParameters) { this.contextParameters = contextParameters; } - private static ThreadLocal rpcContextThreadLocal = new ThreadLocal(() => - { - RpcContext context = new RpcContext(); - context.SetContextParameters(new ConcurrentDictionary()); - return context; - }); - + private static AsyncLocal rpcContextThreadLocal=new AsyncLocal(); + public static RpcContext GetContext() { + var context = rpcContextThreadLocal.Value; + + if (context == null) + { + context = new RpcContext(); + context.SetContextParameters(new ConcurrentDictionary()); + rpcContextThreadLocal.Value = context; + } + return rpcContextThreadLocal.Value; } public static void RemoveContext() { - rpcContextThreadLocal.Dispose(); + rpcContextThreadLocal.Value = null; } private RpcContext() diff --git a/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/TransportClient.cs b/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/TransportClient.cs index 9bf1b4ae2..e3f803782 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/TransportClient.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Transport/Implementation/TransportClient.cs @@ -1,9 +1,15 @@ using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Diagnostics; using Surging.Core.CPlatform.Exceptions; using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Client; using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Utilities; using System; using System.Collections.Concurrent; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; namespace Surging.Core.CPlatform.Transport.Implementation @@ -20,8 +26,9 @@ public class TransportClient : ITransportClient, IDisposable private readonly ILogger _logger; private readonly IServiceExecutor _serviceExecutor; - private readonly ConcurrentDictionary> _resultDictionary = - new ConcurrentDictionary>(); + private readonly ConcurrentDictionary> _resultDictionary = + new ConcurrentDictionary>(); + private readonly DiagnosticListener _diagnosticListener; #endregion Field @@ -30,6 +37,8 @@ public class TransportClient : ITransportClient, IDisposable public TransportClient(IMessageSender messageSender, IMessageListener messageListener, ILogger logger, IServiceExecutor serviceExecutor) { + + _diagnosticListener =new DiagnosticListener(DiagnosticListenerExtensions.DiagnosticListenerName); _messageSender = messageSender; _messageListener = messageListener; _logger = logger; @@ -46,7 +55,8 @@ public TransportClient(IMessageSender messageSender, IMessageListener messageLis /// /// 远程调用消息模型。 /// 远程调用消息的传输消息。 - public async Task SendAsync(RemoteInvokeMessage message) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public async Task SendAsync(RemoteInvokeMessage message, CancellationToken cancellationToken) { try { @@ -54,9 +64,9 @@ public async Task SendAsync(RemoteInvokeMessage messa _logger.LogDebug("准备发送消息。"); var transportMessage = TransportMessage.CreateInvokeMessage(message); - + WirteDiagnosticBefore(transportMessage); //注册结果回调 - var callbackTask = RegisterResultCallbackAsync(transportMessage.Id); + var callbackTask = RegisterResultCallbackAsync(transportMessage.Id,cancellationToken); try { @@ -92,7 +102,7 @@ public void Dispose() (_messageListener as IDisposable)?.Dispose(); foreach (var taskCompletionSource in _resultDictionary.Values) { - taskCompletionSource.TrySetCanceled(); + taskCompletionSource.SetCanceled(); } } @@ -105,23 +115,25 @@ public void Dispose() /// /// 消息Id。 /// 远程调用结果消息模型。 - private async Task RegisterResultCallbackAsync(string id) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private async Task RegisterResultCallbackAsync(string id, CancellationToken cancellationToken) { if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"准备获取Id为:{id}的响应内容。"); - var task = new TaskCompletionSource(); + var task = new ManualResetValueTaskSource(); _resultDictionary.TryAdd(id, task); try { - var result = await task.Task; + var result = await task.AwaitValue(cancellationToken); return result.GetContent(); } finally { //删除回调任务 - TaskCompletionSource value; + ManualResetValueTaskSource value; _resultDictionary.TryRemove(id, out value); + value.SetCanceled(); } } @@ -130,7 +142,7 @@ private async Task MessageListener_Received(IMessageSender sender, TransportMess if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("服务消费者接收到消息。"); - TaskCompletionSource task; + ManualResetValueTaskSource task; if (!_resultDictionary.TryGetValue(message.Id, out task)) return; @@ -139,17 +151,69 @@ private async Task MessageListener_Received(IMessageSender sender, TransportMess var content = message.GetContent(); if (!string.IsNullOrEmpty(content.ExceptionMessage)) { - task.TrySetException(new CPlatformCommunicationException(content.ExceptionMessage,content.StatusCode)); + WirteDiagnosticError(message); + task.SetException(new CPlatformCommunicationException(content.ExceptionMessage,content.StatusCode)); } else { task.SetResult(message); + WirteDiagnosticAfter(message); } } if (_serviceExecutor != null && message.IsInvokeMessage()) await _serviceExecutor.ExecuteAsync(sender, message); } + + private void WirteDiagnosticBefore(TransportMessage message) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + var remoteInvokeMessage = message.GetContent(); + remoteInvokeMessage.Attachments.TryGetValue("TraceId", out object traceId); + _diagnosticListener.WriteTransportBefore(TransportType.Rpc, new TransportEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id, + MessageName = remoteInvokeMessage.ServiceId + }, remoteInvokeMessage.DecodeJOject ? RpcMethod.Json_Rpc.ToString() : RpcMethod.Proxy_Rpc.ToString(), + traceId?.ToString(), + RpcContext.GetContext().GetAttachment("RemoteAddress")?.ToString())); + } + var parameters = RpcContext.GetContext().GetContextParameters(); + parameters.TryRemove("RemoteAddress", out object value); + RpcContext.GetContext().SetContextParameters(parameters); + } + + private void WirteDiagnosticAfter(TransportMessage message) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + var remoteInvokeResultMessage = message.GetContent(); + _diagnosticListener.WriteTransportAfter(TransportType.Rpc, new ReceiveEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id + })); + } + } + + private void WirteDiagnosticError(TransportMessage message) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + var remoteInvokeResultMessage = message.GetContent(); + _diagnosticListener.WriteTransportError(TransportType.Rpc, new TransportErrorEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id + }, new CPlatformCommunicationException(remoteInvokeResultMessage.ExceptionMessage))); + } + } + #endregion Private Method } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.CPlatform/Utilities/AtomicLong.cs b/src/Surging.Core/Surging.Core.CPlatform/Utilities/AtomicLong.cs new file mode 100644 index 000000000..47293b95e --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Utilities/AtomicLong.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Surging.Core.CPlatform.Utilities +{ + public class AtomicLong + { + + private long _value; + + public AtomicLong() + : this(0) + { + + } + public AtomicLong(long value) + { + _value = value; + } + + public long Get() + { + return Interlocked.Read(ref _value); + } + public void Set(long value) + { + Interlocked.Exchange(ref _value, value); + } + + public long GetAndSet(long value) + { + return Interlocked.Exchange(ref _value, value); + } + + public bool CompareAndSet(long expected, long result) + { + return Interlocked.CompareExchange(ref _value, result, expected) == expected; + } + + public long AddAndGet(long delta) + { + return Interlocked.Add(ref _value, delta); + } + public long GetAndAdd(long delta) + { + for (; ; ) + { + long current = Get(); + long next = current + delta; + if (CompareAndSet(current, next)) + { + return current; + } + } + } + + public long Increment() + { + return GetAndAdd(1); + } + + public long Decrement() + { + return GetAndAdd(-1); + } + + + public long PreIncrement() + { + return Interlocked.Increment(ref _value); + } + + public long PreDecrement() + { + return Interlocked.Decrement(ref _value); + } + + public static implicit operator long(AtomicLong value) + { + return value.Get(); + } + + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Utilities/CancellationTokenExtensions.cs b/src/Surging.Core/Surging.Core.CPlatform/Utilities/CancellationTokenExtensions.cs index cfe1ff231..01d4b063a 100644 --- a/src/Surging.Core/Surging.Core.CPlatform/Utilities/CancellationTokenExtensions.cs +++ b/src/Surging.Core/Surging.Core.CPlatform/Utilities/CancellationTokenExtensions.cs @@ -22,16 +22,19 @@ public static async Task WithCancellation( using (cancellationToken.Register( s => ((TaskCompletionSource)s).TrySetResult(true), tcs)) if (task != await Task.WhenAny(task, tcs.Task)) - throw new OperationCanceledException("请求超时", cancellationToken); + throw new TimeoutException(); return await task; } public static async Task WithCancellation( - this Task task, int requestTimeout) + this Task task, CancellationTokenSource cts, int requestTimeout) { - if (task != await Task.WhenAny(task, Task.Delay(requestTimeout))) - throw new OperationCanceledException("请求超时"); - return await task; + if (task == await Task.WhenAny(task, Task.Delay(requestTimeout, cts.Token))) + { + cts.Cancel(); + return await task; + } + throw new TimeoutException(); } } } diff --git a/src/Surging.Core/Surging.Core.CPlatform/Utilities/DateTimeConverter.cs b/src/Surging.Core/Surging.Core.CPlatform/Utilities/DateTimeConverter.cs new file mode 100644 index 000000000..7fd98c74a --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Utilities/DateTimeConverter.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.CPlatform.Utilities +{ + public class DateTimeConverter + { + public static long DateTimeToUnixTimestamp( DateTime dateTime) + { + var start = new DateTime(1970, 1, 1, 0, 0, 0, dateTime.Kind); + return Convert.ToInt64((dateTime - start).TotalSeconds); + } + + public static DateTime UnixTimestampToDateTime( long timestamp, DateTime? time=null) + { + var start = time ==null?new DateTime(1970, 1, 1, 0, 0, 0): new DateTime(1970, 1, 1, 0, 0, 0,time.Value.Kind); + return start.AddSeconds(timestamp); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Utilities/ManualResetValueTaskSource.cs b/src/Surging.Core/Surging.Core.CPlatform/Utilities/ManualResetValueTaskSource.cs new file mode 100644 index 000000000..07a1897dd --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Utilities/ManualResetValueTaskSource.cs @@ -0,0 +1,340 @@ +using System; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Sources; + +namespace Surging.Core.CPlatform.Utilities +{ + internal interface IStrongBox + { + ref T Value { get; } + + bool RunContinuationsAsynchronously { get; set; } + } + + public enum ContinuationOptions + { + None, + + ForceDefaultTaskScheduler + } + + public class ManualResetValueTaskSource : IStrongBox>, IValueTaskSource, IValueTaskSource + { + private ManualResetValueTaskSourceLogic _logic; + private readonly Action _cancellationCallback; + + public ManualResetValueTaskSource(ContinuationOptions options = ContinuationOptions.None) + { + _logic = new ManualResetValueTaskSourceLogic(this, options); + _cancellationCallback = SetCanceled; + } + + public short Version => _logic.Version; + + public bool SetResult(T result) + { + lock (_cancellationCallback) + { + if (_logic.Completed) + { + return false; + } + + _logic.SetResult(result); + return true; + } + } + + public void SetException(Exception error) + { + if (Monitor.TryEnter(_cancellationCallback)) + { + if (_logic.Completed) + { + Monitor.Exit(_cancellationCallback); + return; + } + + _logic.SetException(error); + Monitor.Exit(_cancellationCallback); + } + } + + public void SetCanceled() => SetException(new TaskCanceledException()); + + public T GetResult(short token) => _logic.GetResult(token); + + void IValueTaskSource.GetResult(short token) => _logic.GetResult(token); + + public ValueTaskSourceStatus GetStatus(short token) => _logic.GetStatus(token); + + public bool RunContinuationsAsynchronously { get; set; } = true; + + public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _logic.OnCompleted(continuation, state, token, flags); + + ref ManualResetValueTaskSourceLogic IStrongBox>.Value => ref _logic; + + + public ValueTask AwaitValue(CancellationToken cancellation) + { + CancellationTokenRegistration? registration = cancellation == CancellationToken.None + ? (CancellationTokenRegistration?)null + : cancellation.Register(_cancellationCallback); + return _logic.AwaitValue(this, registration); + } + + public ValueTask AwaitVoid(CancellationToken cancellation) + { + CancellationTokenRegistration? registration = cancellation == CancellationToken.None + ? (CancellationTokenRegistration?)null + : cancellation.Register(_cancellationCallback); + return _logic.AwaitVoid(this, registration); + } + + public void Reset() => _logic.Reset(); + } + + internal struct ManualResetValueTaskSourceLogic + { + private static readonly Action s_sentinel = s => throw new InvalidOperationException(); + + private readonly IStrongBox> _parent; + private readonly ContinuationOptions _options; + private Action _continuation; + private object _continuationState; + private object _capturedContext; + private ExecutionContext _executionContext; + private bool _completed; + private TResult _result; + private ExceptionDispatchInfo _error; + private CancellationTokenRegistration? _registration; + + public ManualResetValueTaskSourceLogic(IStrongBox> parent, ContinuationOptions options) + { + _parent = parent ?? throw new ArgumentNullException(nameof(parent)); + _options = options; + _continuation = null; + _continuationState = null; + _capturedContext = null; + _executionContext = null; + _completed = false; + _result = default(TResult); + _error = null; + Version = 0; + _registration = null; + } + + public short Version { get; private set; } + + public bool Completed => _completed; + + private void ValidateToken(short token) + { + if (token != Version) + { + throw new InvalidOperationException(); + } + } + + public ValueTaskSourceStatus GetStatus(short token) + { + ValidateToken(token); + + return + !_completed ? ValueTaskSourceStatus.Pending : + _error == null ? ValueTaskSourceStatus.Succeeded : + _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled : + ValueTaskSourceStatus.Faulted; + } + + public TResult GetResult(short token) + { + ValidateToken(token); + + if (!_completed) + { + throw new InvalidOperationException(); + } + + TResult result = _result; + ExceptionDispatchInfo error = _error; + Reset(); + + error?.Throw(); + return result; + } + + public void Reset() + { + Version++; + + _registration?.Dispose(); + + _completed = false; + _continuation = null; + _continuationState = null; + _result = default(TResult); + _error = null; + _executionContext = null; + _capturedContext = null; + _registration = null; + } + + public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) + { + if (continuation == null) + { + throw new ArgumentNullException(nameof(continuation)); + } + + ValidateToken(token); + + + if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) + { + _executionContext = ExecutionContext.Capture(); + } + + if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) + { + SynchronizationContext sc = SynchronizationContext.Current; + if (sc != null && sc.GetType() != typeof(SynchronizationContext)) + { + _capturedContext = sc; + } + else + { + TaskScheduler ts = TaskScheduler.Current; + if (ts != TaskScheduler.Default) + { + _capturedContext = ts; + } + } + } + + _continuationState = state; + if (Interlocked.CompareExchange(ref _continuation, continuation, null) != null) + { + _executionContext = null; + + object cc = _capturedContext; + _capturedContext = null; + + switch (cc) + { + case null: + Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + break; + + case SynchronizationContext sc: + sc.Post(s => + { + var tuple = (Tuple, object>)s; + tuple.Item1(tuple.Item2); + }, Tuple.Create(continuation, state)); + break; + + case TaskScheduler ts: + Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); + break; + } + } + } + + public void SetResult(TResult result) + { + _result = result; + SignalCompletion(); + } + + public void SetException(Exception error) + { + _error = ExceptionDispatchInfo.Capture(error); + SignalCompletion(); + } + + private void SignalCompletion() + { + if (_completed) + { + throw new InvalidOperationException("Double completion of completion source is prohibited"); + } + + _completed = true; + + if (Interlocked.CompareExchange(ref _continuation, s_sentinel, null) != null) + { + if (_executionContext != null) + { + ExecutionContext.Run( + _executionContext, + s => ((IStrongBox>)s).Value.InvokeContinuation(), + _parent ?? throw new InvalidOperationException()); + } + else + { + InvokeContinuation(); + } + } + } + + private void InvokeContinuation() + { + object cc = _capturedContext; + _capturedContext = null; + + if (_options == ContinuationOptions.ForceDefaultTaskScheduler) + { + cc = TaskScheduler.Default; + } + + switch (cc) + { + case null: + if (_parent.RunContinuationsAsynchronously) + { + var c = _continuation; + if (_executionContext != null) + { + ThreadPool.QueueUserWorkItem(s => c(s), _continuationState); + } + else + { + ThreadPool.UnsafeQueueUserWorkItem(s => c(s), _continuationState); + } + } + else + { + _continuation(_continuationState); + } + break; + + case SynchronizationContext sc: + sc.Post(s => + { + ref ManualResetValueTaskSourceLogic logicRef = ref ((IStrongBox>)s).Value; + logicRef._continuation(logicRef._continuationState); + }, _parent ?? throw new InvalidOperationException()); + break; + + case TaskScheduler ts: + Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); + break; + } + } + + public ValueTask AwaitValue(IValueTaskSource source, CancellationTokenRegistration? registration) + { + _registration = registration; + return new ValueTask(source, Version); + } + + public ValueTask AwaitVoid(IValueTaskSource source, CancellationTokenRegistration? registration) + { + _registration = registration; + return new ValueTask(source, Version); + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Utilities/NetUtils.cs b/src/Surging.Core/Surging.Core.CPlatform/Utilities/NetUtils.cs new file mode 100644 index 000000000..1195c7025 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Utilities/NetUtils.cs @@ -0,0 +1,107 @@ +using Surging.Core.CPlatform.Address; +using System; +using System.Collections.Generic; +using System.Net.NetworkInformation; +using System.Text; + +namespace Surging.Core.CPlatform.Utilities +{ + public class NetUtils + { + public const string LOCALHOST = "127.0.0.1"; + public const string ANYHOST = "0.0.0.0"; + private const int MIN_PORT = 0; + private const int MAX_PORT = 65535; + private const string LOCAL_IP_PATTERN = "127(\\.\\d{1,3}){3}$"; + private const string IP_PATTERN = "\\d{1,3}(\\.\\d{1,3}){3,5}$"; + private static AddressModel _host = null; + + public static bool IsInvalidPort(int port) + { + return port <= MIN_PORT || port > MAX_PORT; + } + + public static bool IsLocalHost(string host) + { + return host != null + && (host.IsMatch(LOCAL_IP_PATTERN) + || host.Equals("localhost", StringComparison.OrdinalIgnoreCase)); + } + + public static bool IsAnyHost(String host) + { + return "0.0.0.0".Equals(host); + } + + private static bool IsValidAddress(string address) + { + return (address != null + && !ANYHOST.Equals(address) + && address.IsMatch(IP_PATTERN)); + } + + public static bool IsInvalidLocalHost(String host) + { + return host == null + || host.Length == 0 + || host.Equals("localhost", StringComparison.OrdinalIgnoreCase) + || host.Equals("0.0.0.0") + || (host.IsMatch(LOCAL_IP_PATTERN)); + } + + public static string GetAnyHostAddress() + { + string result = ""; + NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface adapter in nics) + { + if (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet) + { + IPInterfaceProperties ipxx = adapter.GetIPProperties(); + UnicastIPAddressInformationCollection ipCollection = ipxx.UnicastAddresses; + foreach (UnicastIPAddressInformation ipadd in ipCollection) + { + if (ipadd.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { + result = ipadd.Address.ToString(); + } + } + } + } + return result; + } + + public static string GetHostAddress(string hostAddress) + { + var result = hostAddress; + if ((!IsValidAddress(hostAddress) && !IsLocalHost(hostAddress)) || IsAnyHost(hostAddress)) + { + result = GetAnyHostAddress(); + } + return result; + } + + public static AddressModel GetHostAddress() + { + if (_host != null) + return _host; + var ports = AppConfig.ServerOptions.Ports; + string address = GetHostAddress(AppConfig.ServerOptions.Ip); + int port = AppConfig.ServerOptions.Port; + var mappingIp = AppConfig.ServerOptions.MappingIP ?? address; + var mappingPort = AppConfig.ServerOptions.MappingPort; + if (mappingPort == 0) + mappingPort = port; + _host = new IpAddressModel + { + HttpPort = ports.HttpPort, + Ip = mappingIp, + Port = mappingPort, + MqttPort = ports.MQTTPort, + WanIp = AppConfig.ServerOptions.WanIp, + WsPort = ports.WSPort + }; + return _host; + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Validation/IValidationProcessor.cs b/src/Surging.Core/Surging.Core.CPlatform/Validation/IValidationProcessor.cs new file mode 100644 index 000000000..8c15009b3 --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Validation/IValidationProcessor.cs @@ -0,0 +1,9 @@ +using System.Reflection; + +namespace Surging.Core.CPlatform.Validation +{ + public interface IValidationProcessor + { + void Validate(ParameterInfo parameterInfo, object value); + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Validation/Implementation/DefaultValidationProcessor.cs b/src/Surging.Core/Surging.Core.CPlatform/Validation/Implementation/DefaultValidationProcessor.cs new file mode 100644 index 000000000..805c7cdfe --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Validation/Implementation/DefaultValidationProcessor.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Reflection; +using Surging.Core.CPlatform.Convertibles; +using Surging.Core.CPlatform.Exceptions; +using Surging.Core.CPlatform.Utilities; + +namespace Surging.Core.CPlatform.Validation.Implementation +{ + public class DefaultValidationProcessor : IValidationProcessor + { + private readonly ITypeConvertibleService _typeConvertibleService; + + public DefaultValidationProcessor(ITypeConvertibleService typeConvertibleService) + { + _typeConvertibleService = typeConvertibleService; + } + + public void Validate(ParameterInfo parameterInfo, object value) + { + Check.NotNull(parameterInfo, nameof(parameterInfo)); + if (value != null) + { + var parameterType = parameterInfo.ParameterType; + var parameter = _typeConvertibleService.Convert(value, parameterType); + var customAttributes = parameterInfo.GetCustomAttributes(true); + var customValidAttributes = customAttributes + .Where(ca => ca.GetType() != typeof(ValidateAttribute)) + .OfType() + .ToList(); + var validationContext = new ValidationContext(parameter); + var validationResults = new List(); + var isObjValid = Validator.TryValidateObject(parameter, validationContext, + validationResults, + true); + + var isValueValid = Validator.TryValidateValue(parameter, validationContext, + validationResults, customValidAttributes); + + if (isObjValid && isValueValid) return; + + throw new ValidateException(validationResults.Select(p => p.ErrorMessage).First()); + + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.CPlatform/Validation/ValidateAttribute.cs b/src/Surging.Core/Surging.Core.CPlatform/Validation/ValidateAttribute.cs new file mode 100644 index 000000000..c68ce9c8a --- /dev/null +++ b/src/Surging.Core/Surging.Core.CPlatform/Validation/ValidateAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace Surging.Core.CPlatform.Validation +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] + public class ValidateAttribute : Attribute + { + public ValidateAttribute() + { + + } + } +} diff --git a/src/Surging.Core/Surging.Core.Caching/AddressResolvers/Implementation/DefaultAddressResolver.cs b/src/Surging.Core/Surging.Core.Caching/AddressResolvers/Implementation/DefaultAddressResolver.cs index bf230eb61..1c4125e73 100644 --- a/src/Surging.Core/Surging.Core.Caching/AddressResolvers/Implementation/DefaultAddressResolver.cs +++ b/src/Surging.Core/Surging.Core.Caching/AddressResolvers/Implementation/DefaultAddressResolver.cs @@ -14,6 +14,9 @@ namespace Surging.Core.Caching.AddressResolvers.Implementation { + /// + /// 默认地址解析程序 + /// public class DefaultAddressResolver : IAddressResolver { @@ -92,35 +95,43 @@ private static string GetKey(CacheDescriptor descriptor) private void ServiceCacheManager_Removed(object sender, ServiceCacheEventArgs e) { var key = GetKey(e.Cache.CacheDescriptor); - var redisContext = CacheContainer.GetService(e.Cache.CacheDescriptor.Prefix); - ServiceCache value; - _concurrent.TryRemove(key, out value); - ConsistentHash hash; - redisContext.dicHash.TryGetValue(e.Cache.CacheDescriptor.Type, out hash); - if (hash != null) - foreach (var node in e.Cache.CacheEndpoint) - { - var hashNode = node as ConsistentHashNode; - hash.Remove(hashNode); - hash.Add(hashNode); - } - + if (CacheContainer.IsRegistered(e.Cache.CacheDescriptor.Prefix)) + { + var redisContext = CacheContainer.GetService(e.Cache.CacheDescriptor.Prefix); + ServiceCache value; + _concurrent.TryRemove(key, out value); + ConsistentHash hash; + redisContext.dicHash.TryGetValue(e.Cache.CacheDescriptor.Type, out hash); + if (hash != null) + foreach (var node in e.Cache.CacheEndpoint) + { + + var hashNode = node as ConsistentHashNode; + var addr = string.Format("{0}:{1}", hashNode.Host, hashNode.Port); + hash.Remove(addr); + hash.Add(hashNode, addr); + } + } } private void ServiceCacheManager_Add(object sender, ServiceCacheEventArgs e) { var key = GetKey(e.Cache.CacheDescriptor); - var redisContext = CacheContainer.GetService(e.Cache.CacheDescriptor.Prefix); - _concurrent.GetOrAdd(key, e.Cache); - ConsistentHash hash; - redisContext.dicHash.TryGetValue(e.Cache.CacheDescriptor.Type, out hash); - if (hash != null) - foreach (var node in e.Cache.CacheEndpoint) - { - var hashNode = node as ConsistentHashNode; - hash.Remove(hashNode); - hash.Add(hashNode); - } + if (CacheContainer.IsRegistered(e.Cache.CacheDescriptor.Prefix)) + { + var redisContext = CacheContainer.GetService(e.Cache.CacheDescriptor.Prefix); + _concurrent.GetOrAdd(key, e.Cache); + ConsistentHash hash; + redisContext.dicHash.TryGetValue(e.Cache.CacheDescriptor.Type, out hash); + if (hash != null) + foreach (var node in e.Cache.CacheEndpoint) + { + var hashNode = node as ConsistentHashNode; + var addr = string.Format("{0}:{1}", hashNode.Host, hashNode.Port); + hash.Remove(addr); + hash.Add(hashNode, addr); + } + } } } } diff --git a/src/Surging.Core/Surging.Core.Caching/CachingModule.cs b/src/Surging.Core/Surging.Core.Caching/CachingModule.cs index 4949d3a39..0e97a04c4 100644 --- a/src/Surging.Core/Surging.Core.Caching/CachingModule.cs +++ b/src/Surging.Core/Surging.Core.Caching/CachingModule.cs @@ -22,9 +22,10 @@ namespace Surging.Core.Caching { public class CachingModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); var serviceCacheProvider = serviceProvider.GetInstances(); var addressDescriptors = serviceCacheProvider.GetServiceCaches().ToList(); serviceProvider.GetInstances().SetCachesAsync(addressDescriptors); diff --git a/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationExtensions.cs b/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationExtensions.cs index eab7df3d6..0e636812f 100644 --- a/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationExtensions.cs +++ b/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationExtensions.cs @@ -12,22 +12,28 @@ public static class CacheConfigurationExtensionsstatic { public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder builder, string path) { - return AddCacheFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + return AddCacheFile(builder, provider: null, path: path, basePath: null, optional: false, reloadOnChange: false); } public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder builder, string path, bool optional) { - return AddCacheFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + return AddCacheFile(builder, provider: null, path: path, basePath: null, optional: optional, reloadOnChange: false); } public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { - return AddCacheFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + return AddCacheFile(builder, provider: null, path: path, basePath: null, optional: optional, reloadOnChange: reloadOnChange); } - public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder builder, string path, string basePath, bool optional, bool reloadOnChange) + { + return AddCacheFile(builder, provider: null, path: path, basePath: basePath, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder builder, IFileProvider provider, string path, string basePath, bool optional, bool reloadOnChange) { Check.NotNull(builder, "builder"); + //获取一个环境变量的路径 Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); path = CPlatform.Utilities.EnvironmentHelper.GetEnvironmentVariable(path); if (provider == null && Path.IsPathRooted(path)) @@ -35,6 +41,7 @@ public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder buil provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); path = Path.GetFileName(path); } + //建立CacheConfigurationSource类,此类继承了FileConfigurationSource接口,并重写加入了json转换方法 var source = new CacheConfigurationSource { FileProvider = provider, @@ -43,6 +50,8 @@ public static IConfigurationBuilder AddCacheFile(this IConfigurationBuilder buil ReloadOnChange = reloadOnChange }; builder.Add(source); + if (!string.IsNullOrEmpty(basePath)) + builder.SetBasePath(basePath); AppConfig.Path = path; AppConfig.Configuration = builder.Build(); return builder; diff --git a/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationProvider.cs b/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationProvider.cs index e612f802b..bc29e99fe 100644 --- a/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationProvider.cs +++ b/src/Surging.Core/Surging.Core.Caching/Configurations/CacheConfigurationProvider.cs @@ -12,6 +12,10 @@ class CacheConfigurationProvider : FileConfigurationProvider { public CacheConfigurationProvider(CacheConfigurationSource source) : base(source) { } + /// + /// 重写数据转换方法 + /// + /// public override void Load(Stream stream) { var parser = new JsonConfigurationParser(); diff --git a/src/Surging.Core/Surging.Core.Caching/Configurations/Implementation/ConfigurationWatchProvider.cs b/src/Surging.Core/Surging.Core.Caching/Configurations/Implementation/ConfigurationWatchProvider.cs index 2d4ac3f09..332362e74 100644 --- a/src/Surging.Core/Surging.Core.Caching/Configurations/Implementation/ConfigurationWatchProvider.cs +++ b/src/Surging.Core/Surging.Core.Caching/Configurations/Implementation/ConfigurationWatchProvider.cs @@ -17,6 +17,9 @@ namespace Surging.Core.Caching.Configurations.Implementation { + /// + /// 配置watch提供者 + /// public class ConfigurationWatchProvider : ConfigurationWatch, IConfigurationWatchProvider { #region Field @@ -54,23 +57,34 @@ private void SaveConfiguration(ServiceCache cache) { if (this.queue.Count > 0) this.queue.Dequeue(); var setting = _cachingProvider.CachingSettings.Where(p => p.Id == cache.CacheDescriptor.Prefix).FirstOrDefault(); - setting.Properties.ForEach(p => + if (setting != null) { - if (p.Maps != null) - p.Maps.ForEach(m => + setting.Properties.ForEach(p => { - if (m.Name == cache.CacheDescriptor.Type) - m.Properties = cache.CacheEndpoint.Select(n => - { - var hashNode = n as ConsistentHashNode; - return new Property + if (p.Maps != null) + p.Maps.ForEach(m => + { + if (m.Name == cache.CacheDescriptor.Type) + m.Properties = cache.CacheEndpoint.Select(n => { - Value = $"{hashNode.Host}:{hashNode.Port}::{hashNode.Db}" - }; - }).ToList(); + var hashNode = n as ConsistentHashNode; + if (!string.IsNullOrEmpty(hashNode.UserName) || !string.IsNullOrEmpty(hashNode.Password)) + { + return new Property + { + Value = $"{hashNode.UserName}:{hashNode.Password}@{hashNode.Host}:{hashNode.Port}::{hashNode.Db}" + }; + } + return new Property + { + Value = $"{hashNode.Host}:{hashNode.Port}::{hashNode.Db}" + }; + + }).ToList(); + }); }); - }); - this.queue.Enqueue(true); + this.queue.Enqueue(true); + } } public override async Task Process() diff --git a/src/Surging.Core/Surging.Core.Caching/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Caching/ContainerBuilderExtensions.cs index fa25441b2..7bf0d3250 100644 --- a/src/Surging.Core/Surging.Core.Caching/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.Caching/ContainerBuilderExtensions.cs @@ -21,10 +21,18 @@ namespace Surging.Core.Caching { + /// + /// 容器生成扩展 + /// public static class ContainerBuilderExtensions { private const string CacheSectionName = "CachingProvider"; + /// + /// 附加缓存注入 + /// + /// 服务构建者 + /// 服务构建者 public static IServiceBuilder AddCache(this IServiceBuilder builder) { var services = builder.Services; @@ -39,6 +47,11 @@ public static IServiceBuilder AddCache(this IServiceBuilder builder) return builder; } + /// + /// 注册本地实例 + /// + /// + /// private static void RegisterLocalInstance(string typeName, ContainerBuilder services) { var types = typeof(AppConfig) @@ -50,6 +63,10 @@ private static void RegisterLocalInstance(string typeName, ContainerBuilder serv } } + /// + /// 注册配置实例 + /// + /// private static void RegisterConfigInstance(ContainerBuilder services) { var cacheWrapperSetting = AppConfig.Configuration.Get(); @@ -90,6 +107,11 @@ var mapsetting in catch { } } + /// + /// 获取类型的属性值 + /// + /// + /// private static object GetTypedPropertyValue(Property obj) { var mapCollections = obj.Maps; diff --git a/src/Surging.Core/Surging.Core.Caching/HashAlgorithms/ConsistentHash.cs b/src/Surging.Core/Surging.Core.Caching/HashAlgorithms/ConsistentHash.cs index 03cfc68bb..33a852505 100644 --- a/src/Surging.Core/Surging.Core.Caching/HashAlgorithms/ConsistentHash.cs +++ b/src/Surging.Core/Surging.Core.Caching/HashAlgorithms/ConsistentHash.cs @@ -46,22 +46,6 @@ public int VirtualNodeReplicationFactor } #endregion - /// - /// 初始化节点服务器 - /// - /// 节点 - /// - /// 创建:范亮 - /// 日期:2016/4/2 - /// - public void Initialize(IEnumerable nodes) - { - foreach (var node in nodes) - { - AddNode(node); - } - _nodeKeysInRing = _ring.Keys.ToArray(); - } /// /// 添加节点 @@ -71,12 +55,17 @@ public void Initialize(IEnumerable nodes) /// 创建:范亮 /// 日期:2016/4/2 /// - public void Add(T node) + public void Add(T node, string value) { - AddNode(node); + AddNode(node, value); _nodeKeysInRing = _ring.Keys.ToArray(); } + public IEnumerable GetNodes() + { + return _ring.Values.Distinct().ToList(); + } + /// /// 删除节点 /// @@ -85,7 +74,7 @@ public void Add(T node) /// 创建:范亮 /// 日期:2016/4/2 /// - public void Remove(T node) + public void Remove(string node) { RemoveNode(node); _nodeKeysInRing = _ring.Keys.ToArray(); @@ -107,11 +96,6 @@ public T GetItemNode(string item) return _ring[_nodeKeysInRing[nearestNodePosition]]; } - public IEnumerable GetNodes() - { - return _ring.Values.Distinct().ToList(); - } - /// /// 添加节点 /// @@ -120,11 +104,11 @@ public IEnumerable GetNodes() /// 创建:范亮 /// 日期:2016/4/2 /// - private void AddNode(T node) + private void AddNode(T node, string value) { for (var i = 0; i < _virtualNodeReplicationFactor; i++) { - var hashOfVirtualNode = _hashAlgorithm.Hash(node.GetHashCode().ToString(CultureInfo.InvariantCulture) + i); + var hashOfVirtualNode = _hashAlgorithm.Hash(value.ToString(CultureInfo.InvariantCulture) + i); _ring[hashOfVirtualNode] = node; } } @@ -137,13 +121,12 @@ private void AddNode(T node) /// 创建:范亮 /// 日期:2016/4/2 /// - private void RemoveNode(T node) + private void RemoveNode(string value) { for (var i = 0; i < _virtualNodeReplicationFactor; i++) { - var hashOfVirtualNode = _hashAlgorithm.Hash(node.GetHashCode().ToString() + i); - if (_ring.ContainsKey(hashOfVirtualNode)) - _ring.Remove(hashOfVirtualNode); + var hashOfVirtualNode = _hashAlgorithm.Hash(value.ToString() + i); + _ring.Remove(hashOfVirtualNode); } } diff --git a/src/Surging.Core/Surging.Core.Caching/HealthChecks/Implementation/DefaultHealthCheckService.cs b/src/Surging.Core/Surging.Core.Caching/HealthChecks/Implementation/DefaultHealthCheckService.cs index e12a9bf3b..cb6048ebc 100644 --- a/src/Surging.Core/Surging.Core.Caching/HealthChecks/Implementation/DefaultHealthCheckService.cs +++ b/src/Surging.Core/Surging.Core.Caching/HealthChecks/Implementation/DefaultHealthCheckService.cs @@ -11,6 +11,9 @@ namespace Surging.Core.Caching.HealthChecks.Implementation { + /// + /// 默认的健康检查服务 + /// public class DefaultHealthCheckService : IHealthCheckService, IDisposable { private readonly Timer _timer; diff --git a/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultCacheNodeProvider.cs b/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultCacheNodeProvider.cs index 6b41377e8..a6eb67c1c 100644 --- a/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultCacheNodeProvider.cs +++ b/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultCacheNodeProvider.cs @@ -9,6 +9,9 @@ namespace Surging.Core.Caching.Internal.Implementation { + /// + /// 默认缓存节点提供者 + /// public class DefaultCacheNodeProvider : ICacheNodeProvider { private readonly CPlatformContainer _serviceProvider; diff --git a/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultServiceCacheFactory.cs b/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultServiceCacheFactory.cs index 27afe868c..a767f22c4 100644 --- a/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultServiceCacheFactory.cs +++ b/src/Surging.Core/Surging.Core.Caching/Internal/Implementation/DefaultServiceCacheFactory.cs @@ -9,6 +9,9 @@ namespace Surging.Core.Caching.Internal.Implementation { + /// + /// 默认的服务缓存工程 + /// public class DefaultServiceCacheFactory : IServiceCacheFactory { private readonly ISerializer _serializer; diff --git a/src/Surging.Core/Surging.Core.Caching/NetCache/MemoryCacheProvider.cs b/src/Surging.Core/Surging.Core.Caching/NetCache/MemoryCacheProvider.cs index 16a12fc54..6d61d60ed 100644 --- a/src/Surging.Core/Surging.Core.Caching/NetCache/MemoryCacheProvider.cs +++ b/src/Surging.Core/Surging.Core.Caching/NetCache/MemoryCacheProvider.cs @@ -79,12 +79,12 @@ public async void AddAsync(string key, object value, bool defaultExpire) public void Add(string key, object value, long numOfMinutes) { - MemoryCache.Set(GetKeySuffix(key), value, numOfMinutes); + MemoryCache.Set(GetKeySuffix(key), value, numOfMinutes*60); } public async void AddAsync(string key, object value, long numOfMinutes) { - await Task.Run(() => MemoryCache.Set(GetKeySuffix(key), value, numOfMinutes)); + await Task.Run(() => MemoryCache.Set(GetKeySuffix(key), value, numOfMinutes*60)); } public void Add(string key, object value, TimeSpan timeSpan) @@ -196,4 +196,4 @@ private string GetKeySuffix(string key) #endregion } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisContext.cs b/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisContext.cs index 18f948d21..238d3e0a4 100644 --- a/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisContext.cs +++ b/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisContext.cs @@ -206,7 +206,7 @@ private void InitSettingHashStorage() { db = dbs[dbs.Length - 1]; } - hash.Add(new ConsistentHashNode() + var node = new ConsistentHashNode() { Type = targetType, Host = endpoints[0], @@ -216,7 +216,8 @@ private void InitSettingHashStorage() MaxSize = this._maxSize, MinSize = this._minSize, Db = db.ToString() - }); + }; + hash.Add(node,string.Format("{0}:{1}",node.Host,node.Port)); dicHash.GetOrAdd(targetType.ToString(), hash); }); } diff --git a/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisProvider.cs b/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisProvider.cs index b2bd73b66..4cbe77b43 100644 --- a/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisProvider.cs +++ b/src/Surging.Core/Surging.Core.Caching/RedisCache/RedisProvider.cs @@ -78,7 +78,7 @@ public void Add(string key, object value) /// public void AddAsync(string key, object value) { - this.AddTaskAsync(key, value, TimeSpan.FromMinutes(ExpireTime)); + this.AddTaskAsync(key, value, TimeSpan.FromSeconds(ExpireTime)); } /// @@ -93,7 +93,7 @@ public void AddAsync(string key, object value) /// public void Add(string key, object value, bool defaultExpire) { - this.Add(key, value, TimeSpan.FromMinutes(defaultExpire ? DefaultExpireTime : ExpireTime)); + this.Add(key, value, TimeSpan.FromSeconds(defaultExpire ? DefaultExpireTime : ExpireTime)); } /// @@ -108,7 +108,7 @@ public void Add(string key, object value, bool defaultExpire) /// public void AddAsync(string key, object value, bool defaultExpire) { - this.AddTaskAsync(key, value, TimeSpan.FromMinutes(defaultExpire ? DefaultExpireTime : ExpireTime)); + this.AddTaskAsync(key, value, TimeSpan.FromSeconds(defaultExpire ? DefaultExpireTime : ExpireTime)); } /// @@ -472,4 +472,4 @@ public async Task ConnectionAsync(CacheEndpoint endpoint) } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.Caching/Surging.Core.Caching.csproj b/src/Surging.Core/Surging.Core.Caching/Surging.Core.Caching.csproj index 85dbe6513..6eb2c7ce1 100644 --- a/src/Surging.Core/Surging.Core.Caching/Surging.Core.Caching.csproj +++ b/src/Surging.Core/Surging.Core.Caching/Surging.Core.Caching.csproj @@ -1,8 +1,8 @@  - netcoreapp2.1 - 0.8.0.1 + net6.0 + 1.1.0.0 fanly surging Micro Service Framework @@ -11,30 +11,20 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 0.8.0.1 - 0.8.0.1 - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component + 1.1.0.0 + 1.1.0.0 + 1.multiple register center cluster +2. fix bug - - - - - + + + + + - + diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/ContainerBuilderExtensions.cs index 871459c64..872250146 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/ContainerBuilderExtensions.cs @@ -4,6 +4,11 @@ namespace Surging.Core.Codec.MessagePack { public static class ContainerBuilderExtensions { + /// + /// 使用messagepack编码解码方式 + /// + /// + /// public static IServiceBuilder UseMessagePackCodec(this IServiceBuilder builder) { return builder.UseCodec(); diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackModule.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackModule.cs index 92aa083e8..33ebadba9 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackModule.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackModule.cs @@ -9,9 +9,9 @@ namespace Surging.Core.Codec.MessagePack { public class MessagePackModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } /// diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageCodecFactory.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageCodecFactory.cs index f0441f19e..7e4ddec46 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageCodecFactory.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageCodecFactory.cs @@ -1,4 +1,6 @@ using Surging.Core.CPlatform.Transport.Codec; +using System.Runtime.CompilerServices; + namespace Surging.Core.Codec.MessagePack { public sealed class MessagePackTransportMessageCodecFactory : ITransportMessageCodecFactory @@ -10,11 +12,23 @@ public sealed class MessagePackTransportMessageCodecFactory : ITransportMessageC #region Implementation of ITransportMessageCodecFactory + /// + /// + /// 获取编码器 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ITransportMessageEncoder GetEncoder() { return _transportMessageEncoder; } + /// + /// + /// 获取解码器 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ITransportMessageDecoder GetDecoder() { return _transportMessageDecoder; diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageDecoder.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageDecoder.cs index 87ca8d2ea..9bf7e28d5 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageDecoder.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageDecoder.cs @@ -2,6 +2,7 @@ using Surging.Core.Codec.MessagePack.Utilities; using Surging.Core.CPlatform.Messages; using Surging.Core.CPlatform.Transport.Codec; +using System.Runtime.CompilerServices; namespace Surging.Core.Codec.MessagePack { @@ -9,6 +10,7 @@ public sealed class MessagePackTransportMessageDecoder : ITransportMessageDecode { #region Implementation of ITransportMessageDecoder + [MethodImpl(MethodImplOptions.AggressiveInlining)] public TransportMessage Decode(byte[] data) { var message = SerializerUtilitys.Deserialize(data); diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageEncoder.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageEncoder.cs index a81d6ce50..a7ae1366a 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageEncoder.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/MessagePackTransportMessageEncoder.cs @@ -2,6 +2,7 @@ using Surging.Core.Codec.MessagePack.Utilities; using Surging.Core.CPlatform.Messages; using Surging.Core.CPlatform.Transport.Codec; +using System.Runtime.CompilerServices; namespace Surging.Core.Codec.MessagePack { @@ -9,6 +10,7 @@ public sealed class MessagePackTransportMessageEncoder:ITransportMessageEncoder { #region Implementation of ITransportMessageEncoder + [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] Encode(TransportMessage message) { var transportMessage = new MessagePackTransportMessage(message) diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/DynamicItem.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/DynamicItem.cs index 255841e20..a9a16e3b4 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/DynamicItem.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/DynamicItem.cs @@ -4,6 +4,8 @@ using Surging.Core.Codec.MessagePack.Utilities; using Surging.Core.CPlatform.Utilities; using System; +using System.Runtime.CompilerServices; +using System.Threading; namespace Surging.Core.Codec.MessagePack.Messages { @@ -15,6 +17,7 @@ public class DynamicItem public DynamicItem() { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public DynamicItem(object value) { if (value == null) @@ -23,14 +26,14 @@ public DynamicItem(object value) var valueType = value.GetType(); var code = Type.GetTypeCode(valueType); - if (code != TypeCode.Object) + if (code != TypeCode.Object && valueType.BaseType!=typeof(Enum)) TypeName = valueType.FullName; else TypeName = valueType.AssemblyQualifiedName; if (valueType == UtilityType.JObjectType || valueType == UtilityType.JArrayType) Content = SerializerUtilitys.Serialize(value.ToString()); - else + else if(valueType != typeof(CancellationToken)) Content = SerializerUtilitys.Serialize(value); } @@ -46,6 +49,7 @@ public DynamicItem(object value) #endregion Property #region Public Method + [MethodImpl(MethodImplOptions.AggressiveInlining)] public object Get() { if (Content == null || TypeName == null) @@ -55,7 +59,7 @@ public object Get() if (typeName == UtilityType.JObjectType || typeName == UtilityType.JArrayType) { var content = SerializerUtilitys.Deserialize(Content); - return JsonConvert.DeserializeObject(content,typeName); + return JsonConvert.DeserializeObject(content, typeName); } else { diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeMessage.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeMessage.cs index e22da7618..c72619231 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeMessage.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeMessage.cs @@ -1,7 +1,9 @@ using MessagePack; using Surging.Core.CPlatform.Messages; +using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace Surging.Core.Codec.MessagePack.Messages { @@ -34,7 +36,7 @@ public class MessagePackRemoteInvokeMessage { public MessagePackRemoteInvokeMessage(RemoteInvokeMessage message) { - ServiceId = message.ServiceId; + ServiceId = message.ServiceId; DecodeJOject = message.DecodeJOject; ServiceKey = message.ServiceKey; Parameters = message.Parameters?.Select(i => new ParameterItem(i)).ToArray(); @@ -63,6 +65,7 @@ public MessagePackRemoteInvokeMessage() [Key(5)] public ParameterItem[] Attachments { get; set; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public RemoteInvokeMessage GetRemoteInvokeMessage() { return new RemoteInvokeMessage @@ -71,7 +74,7 @@ public RemoteInvokeMessage GetRemoteInvokeMessage() Attachments = Attachments?.ToDictionary(i => i.Key, i => i.Value?.Get()), ServiceId = ServiceId, DecodeJOject = DecodeJOject, - ServiceKey = ServiceKey, + ServiceKey = ServiceKey, }; } } diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeResultMessage.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeResultMessage.cs index 7f85d0ae3..52aa524b2 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeResultMessage.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackRemoteInvokeResultMessage.cs @@ -1,5 +1,6 @@ using MessagePack; using Surging.Core.CPlatform.Messages; +using System.Runtime.CompilerServices; namespace Surging.Core.Codec.MessagePack.Messages { @@ -26,6 +27,7 @@ public MessagePackRemoteInvokeResultMessage() [Key(1)] public DynamicItem Result { get; set; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public RemoteInvokeResultMessage GetRemoteInvokeResultMessage() { return new RemoteInvokeResultMessage diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackTransportMessage.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackTransportMessage.cs index 16c483acd..947ddbc6a 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackTransportMessage.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/Messages/MessagePackTransportMessage.cs @@ -2,6 +2,7 @@ using Surging.Core.Codec.MessagePack.Utilities; using Surging.Core.CPlatform.Messages; using System; +using System.Runtime.CompilerServices; namespace Surging.Core.Codec.MessagePack.Messages { @@ -43,11 +44,13 @@ public MessagePackTransportMessage() [Key(2)] public string ContentType { get; set; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsInvokeMessage() { return ContentType == MessagePackTransportMessageType.remoteInvokeMessageTypeName; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsInvokeResultMessage() { return ContentType == MessagePackTransportMessageType.remoteInvokeResultMessageTypeName; diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/Surging.Core.Codec.MessagePack.csproj b/src/Surging.Core/Surging.Core.Codec.MessagePack/Surging.Core.Codec.MessagePack.csproj index e8c4ca9d8..fd759e630 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/Surging.Core.Codec.MessagePack.csproj +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/Surging.Core.Codec.MessagePack.csproj @@ -1,8 +1,8 @@ - netcoreapp2.1 - 0.8.0.1 + net6.0 + 1.1.0.0 fanly surging Micro Service Framework @@ -11,20 +11,10 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component - 0.8.0.1 - 0.8.0.1 + 1.multiple register center cluster +2. fix bug + 1.1.0.0 + 1.1.0.0 diff --git a/src/Surging.Core/Surging.Core.Codec.MessagePack/Utilities/SerializerUtilitys.cs b/src/Surging.Core/Surging.Core.Codec.MessagePack/Utilities/SerializerUtilitys.cs index 3c39cbecf..d7472e9ec 100644 --- a/src/Surging.Core/Surging.Core.Codec.MessagePack/Utilities/SerializerUtilitys.cs +++ b/src/Surging.Core/Surging.Core.Codec.MessagePack/Utilities/SerializerUtilitys.cs @@ -10,7 +10,6 @@ public class SerializerUtilitys static SerializerUtilitys() { CompositeResolver.RegisterAndSetAsDefault(NativeDateTimeResolver.Instance, ContractlessStandardResolverAllowPrivate.Instance); - MessagePackSerializer.SetDefaultResolver(ContractlessStandardResolverAllowPrivate.Instance); } public static byte[] Serialize(T instance) diff --git a/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/ProtoBufferModule.cs b/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/ProtoBufferModule.cs index d78b68b53..861843233 100644 --- a/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/ProtoBufferModule.cs +++ b/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/ProtoBufferModule.cs @@ -9,9 +9,9 @@ namespace Surging.Core.Codec.ProtoBuffer { public class ProtoBufferModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } /// diff --git a/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/Surging.Core.Codec.ProtoBuffer.csproj b/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/Surging.Core.Codec.ProtoBuffer.csproj index 40e9d1f52..2c4ba86f8 100644 --- a/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/Surging.Core.Codec.ProtoBuffer.csproj +++ b/src/Surging.Core/Surging.Core.Codec.ProtoBuffer/Surging.Core.Codec.ProtoBuffer.csproj @@ -1,9 +1,9 @@ - + - netcoreapp2.1 + net6.0 surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec - 0.8.0.1 + 1.1.0.0 fanly surging Micro Service Framework @@ -11,24 +11,14 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component - 0.8.0.1 - 0.8.0.1 + 1.multiple register center cluster +2. fix bug + 1.1.0.0 + 1.1.0.0 - + diff --git a/src/Surging.IModuleServices/Surging.IModuleServices.Common/Models/ApiResult.cs b/src/Surging.Core/Surging.Core.Common/ApiResult.cs similarity index 69% rename from src/Surging.IModuleServices/Surging.IModuleServices.Common/Models/ApiResult.cs rename to src/Surging.Core/Surging.Core.Common/ApiResult.cs index f39d7149a..95f2ff913 100644 --- a/src/Surging.IModuleServices/Surging.IModuleServices.Common/Models/ApiResult.cs +++ b/src/Surging.Core/Surging.Core.Common/ApiResult.cs @@ -1,12 +1,14 @@ - - +using System; +using System.Collections.Generic; using System.Runtime.Serialization; +using System.Text; -namespace Surging.IModuleServices.Common.Models +namespace Surging.Core.Common { [DataContract] public class ApiResult { + [DataMember] public int StatusCode { get; set; } diff --git a/src/Surging.Core/Surging.Core.Common/CommonModule.cs b/src/Surging.Core/Surging.Core.Common/CommonModule.cs new file mode 100644 index 000000000..2ec5355fa --- /dev/null +++ b/src/Surging.Core/Surging.Core.Common/CommonModule.cs @@ -0,0 +1,20 @@ +using Surging.Core.CPlatform.Module; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Common +{ + public class CommonModule:SystemModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Common/Surging.Core.Common.csproj b/src/Surging.Core/Surging.Core.Common/Surging.Core.Common.csproj index 6ba969fcd..41e781bec 100644 --- a/src/Surging.Core/Surging.Core.Common/Surging.Core.Common.csproj +++ b/src/Surging.Core/Surging.Core.Common/Surging.Core.Common.csproj @@ -1,7 +1,19 @@  - netcoreapp2.1 + net6.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/ApolloModule.cs b/src/Surging.Core/Surging.Core.Configuration.Apollo/ApolloModule.cs new file mode 100644 index 000000000..b517b58d8 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/ApolloModule.cs @@ -0,0 +1,26 @@ +using Surging.Core.Configuration.Apollo.Configurations; +using Surging.Core.CPlatform.Module; +using System; + +namespace Surging.Core.Configuration.Apollo +{ + public class ApolloModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); + serviceProvider.GetInstances().Create(); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.RegisterType(typeof(ConfigurationFactory)).As(typeof(IConfigurationFactory)); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/ConfigFileFormatMethods.cs b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/ConfigFileFormatMethods.cs new file mode 100644 index 000000000..a9c5e724a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/ConfigFileFormatMethods.cs @@ -0,0 +1,24 @@ +using Com.Ctrip.Framework.Apollo.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Configuration.Apollo.Configurations +{ + public static class ConfigFileFormatMethods + { + public static string GetString(this ConfigFileFormat format) + { + return format switch + { + ConfigFileFormat.Properties => "properties", + ConfigFileFormat.Xml => "xml", + ConfigFileFormat.Json => "json", + ConfigFileFormat.Yml => "yml", + ConfigFileFormat.Yaml => "yaml", + ConfigFileFormat.Txt => "txt", + _ => "unknown", + }; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/ConfigurationFactory.cs b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/ConfigurationFactory.cs new file mode 100644 index 000000000..4a062d98e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/ConfigurationFactory.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using Microsoft.Extensions.Configuration; +using Surging.Core.CPlatform; +namespace Surging.Core.Configuration.Apollo.Configurations +{ + public class ConfigurationFactory : IConfigurationFactory + { + private const string CONFIG_FILE_PATH = "APOLLO__CONFIG__PATH"; + + public ConfigurationFactory() + { + } + + public IConfiguration Create() + { + var builder = new ConfigurationBuilder(); + var environmentName = Environment.GetEnvironmentVariable("environmentname"); + + + builder.AddJsonFile("apollo.json", true) + .AddJsonFile($"apollo.{environmentName}.json", true); + + + if (!string.IsNullOrEmpty(AppConfig.ServerOptions.RootPath)) + { + var skyapmPath = Path.Combine(AppConfig.ServerOptions.RootPath, "apollo.json"); + builder.AddJsonFile(skyapmPath, true); + } + + + if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(CONFIG_FILE_PATH))) + { + builder.AddJsonFile(Environment.GetEnvironmentVariable(CONFIG_FILE_PATH), false); + } + + builder.AddEnvironmentVariables(); + + var providers = AppConfig.Configuration.Providers; + + foreach (var provider in providers) + { + var fileConfigurationProvider = provider as FileConfigurationProvider; + if (fileConfigurationProvider != null) + { + builder.Add(fileConfigurationProvider.Source); + } + } + var config = builder.Build(); + var section = config.GetSection("apollo"); + if (!section.Exists()) + { + throw new Exception("apollo config file not exists!"); + } + var apollo = builder.AddApollo(section); + apollo.AddNamespaceSurgingApollo("surgingSettings"); + return config; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/IConfigurationFactory.cs b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/IConfigurationFactory.cs new file mode 100644 index 000000000..867bfcd9b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/IConfigurationFactory.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.Configuration; + +namespace Surging.Core.Configuration.Apollo.Configurations +{ + public interface IConfigurationFactory + { + IConfiguration Create(); + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/SurgingApolloConfigurationProvider.cs b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/SurgingApolloConfigurationProvider.cs new file mode 100644 index 000000000..c9b344f51 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/Configurations/SurgingApolloConfigurationProvider.cs @@ -0,0 +1,39 @@ +using Com.Ctrip.Framework.Apollo; +using Com.Ctrip.Framework.Apollo.Core.Utils; +using Com.Ctrip.Framework.Apollo.Internals; +using Microsoft.Extensions.Configuration; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; + +namespace Surging.Core.Configuration.Apollo.Configurations +{ + public class SurgingApolloConfigurationProvider : ApolloConfigurationProvider + { + internal string SectionKey { get; } + internal IConfigRepository ConfigRepository { get; } + + public SurgingApolloConfigurationProvider(string sectionKey, IConfigRepository configRepository) : base(sectionKey, configRepository) + { + SectionKey = sectionKey; + ConfigRepository = configRepository; + } + + protected override void SetData(Properties properties) + { + var data = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var key in properties.GetPropertyNames()) + { + if (string.IsNullOrEmpty(SectionKey)) + data[key] = EnvironmentHelper.GetEnvironmentVariable(properties.GetProperty(key) ?? string.Empty); + else + data[$"{SectionKey}{ConfigurationPath.KeyDelimiter}{key}"] = EnvironmentHelper.GetEnvironmentVariable(properties.GetProperty(key) ?? string.Empty); + } + + Data = data; + } + + + } +} diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/Extensions/ApolloConfigurationBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Configuration.Apollo/Extensions/ApolloConfigurationBuilderExtensions.cs new file mode 100644 index 000000000..f6118d000 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/Extensions/ApolloConfigurationBuilderExtensions.cs @@ -0,0 +1,45 @@ +using Com.Ctrip.Framework.Apollo; +using Com.Ctrip.Framework.Apollo.Enums; +using Com.Ctrip.Framework.Apollo.Spi; +using System; +using System.Linq; + +namespace Surging.Core.Configuration.Apollo.Configurations +{ + public static class ApolloConfigurationBuilderExtensions + { + + /// 添加其他namespace + public static IApolloConfigurationBuilder AddNamespaceSurgingApollo(this IApolloConfigurationBuilder builder, string @namespace, ConfigFileFormat format = ConfigFileFormat.Json) => + builder.AddNamespaceSurgingApollo(@namespace, null, format); + + /// 添加其他namespace。如果sectionKey为null则添加到root中,可以直接读取,否则使用Configuration.GetSection(sectionKey)读取 + public static IApolloConfigurationBuilder AddNamespaceSurgingApollo(this IApolloConfigurationBuilder builder, string @namespace, string? sectionKey, ConfigFileFormat format = ConfigFileFormat.Json) + { + if (string.IsNullOrWhiteSpace(@namespace)) throw new ArgumentNullException(nameof(@namespace)); + if (format < ConfigFileFormat.Properties || format > ConfigFileFormat.Txt) throw new ArgumentOutOfRangeException(nameof(format), format, $"最小值{ConfigFileFormat.Properties},最大值{ConfigFileFormat.Txt}"); + + if (format != ConfigFileFormat.Properties) @namespace += "." + format.GetString(); + + var configRepository = builder.ConfigRepositoryFactory.GetConfigRepository(@namespace); + var previous = builder.Sources.FirstOrDefault(source => + source is SurgingApolloConfigurationProvider apollo && + apollo.SectionKey == sectionKey && + apollo.ConfigRepository == configRepository); + if (previous != null) + { + builder.Sources.Remove(previous); + builder.Sources.Add(previous); + } + else + { + builder.Add(new SurgingApolloConfigurationProvider(sectionKey, configRepository)); +#pragma warning disable 618 + ApolloConfigurationManager.Manager.Registry.Register(@namespace, new DefaultConfigFactory(builder.ConfigRepositoryFactory)); +#pragma warning restore 618 + } + + return builder; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Configuration.Apollo/Surging.Core.Configuration.Apollo.csproj b/src/Surging.Core/Surging.Core.Configuration.Apollo/Surging.Core.Configuration.Apollo.csproj new file mode 100644 index 000000000..427dfb261 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Configuration.Apollo/Surging.Core.Configuration.Apollo.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Consul/Configurations/ConfigInfo.cs b/src/Surging.Core/Surging.Core.Consul/Configurations/ConfigInfo.cs index 17e6c1f98..698401c68 100644 --- a/src/Surging.Core/Surging.Core.Consul/Configurations/ConfigInfo.cs +++ b/src/Surging.Core/Surging.Core.Consul/Configurations/ConfigInfo.cs @@ -1,6 +1,7 @@ -using System; +using Surging.Core.CPlatform.Address; +using System; using System.Collections.Generic; -using System.Text; +using System.Linq; namespace Surging.Core.Consul.Configurations { @@ -18,8 +19,9 @@ public ConfigInfo(string connectionString,string routePath = "services/serviceRo string subscriberPath = "services/serviceSubscribers/", string commandPath = "services/serviceCommands/", string cachePath="services/serviceCaches/", + string mqttRoutePath = "services/mqttServiceRoutes/", bool reloadOnChange=false, bool enableChildrenMonitor = false) : - this(connectionString, TimeSpan.FromSeconds(20), routePath, subscriberPath,commandPath, cachePath, reloadOnChange, enableChildrenMonitor) + this(connectionString, TimeSpan.FromSeconds(20), 0, routePath, subscriberPath,commandPath, cachePath, mqttRoutePath, reloadOnChange, enableChildrenMonitor) { } @@ -32,29 +34,43 @@ public ConfigInfo(string connectionString,string routePath = "services/serviceRo /// 订阅者配置命令。 /// 路由路径配置路径 /// 缓存中心配置路径 - public ConfigInfo(string connectionString, TimeSpan sessionTimeout, + /// Mqtt路由路径配置路径 + public ConfigInfo(string connectionString, TimeSpan sessionTimeout, int lockDelay, string routePath = "services/serviceRoutes/", string subscriberPath = "services/serviceSubscribers/", string commandPath = "services/serviceCommands/", string cachePath= "services/serviceCaches/", + string mqttRoutePath= "services/mqttServiceRoutes/", bool reloadOnChange=false, bool enableChildrenMonitor = false) { CachePath = cachePath; ReloadOnChange = reloadOnChange; SessionTimeout = sessionTimeout; RoutePath = routePath; + LockDelay = lockDelay; SubscriberPath = subscriberPath; CommandPath = commandPath; + MqttRoutePath = mqttRoutePath; EnableChildrenMonitor = enableChildrenMonitor; if (!string.IsNullOrEmpty(connectionString)) { - var address = connectionString.Split(":"); - if (address.Length > 1) + var addresses = connectionString.Split(","); + if (addresses.Length > 1) { - int port; - int.TryParse(address[1], out port); - Host = address[0]; - Port = port; + Addresses = addresses.Select(p => ConvertAddressModel(p)); + } + else + { + var address = ConvertAddressModel(connectionString); + if (address !=null) + { + var ipAddress=address as IpAddressModel; + Host = ipAddress.Ip; + Port = ipAddress.Port; + } + Addresses = new IpAddressModel[] { + new IpAddressModel(Host,Port) + }; } } } @@ -77,6 +93,7 @@ public ConfigInfo(string host, int port, TimeSpan sessionTimeout) /// public int WatchInterval { get; set; } = 60; + public int LockDelay { get; set; } = 600; public bool EnableChildrenMonitor { get; set; } /// @@ -94,6 +111,14 @@ public ConfigInfo(string host, int port, TimeSpan sessionTimeout) /// public string RoutePath { get; set; } + + /// + /// Mqtt路由配置路径。 + /// + public string MqttRoutePath { get; set; } + + public IEnumerable Addresses { get; set; } + /// /// 缓存中心配置中心 /// @@ -108,5 +133,17 @@ public ConfigInfo(string host, int port, TimeSpan sessionTimeout) /// public TimeSpan SessionTimeout { get; set; } + public AddressModel ConvertAddressModel(string connection) + { + var address = connection.Split(":"); + if (address.Length > 1) + { + int port; + int.TryParse(address[1], out port); + return new IpAddressModel(address[0], port); + } + return null; + } + } } diff --git a/src/Surging.Core/Surging.Core.Consul/Configurations/ConsulOption.cs b/src/Surging.Core/Surging.Core.Consul/Configurations/ConsulOption.cs index 37ba88253..b49fab259 100644 --- a/src/Surging.Core/Surging.Core.Consul/Configurations/ConsulOption.cs +++ b/src/Surging.Core/Surging.Core.Consul/Configurations/ConsulOption.cs @@ -18,8 +18,12 @@ public class ConsulOption public string CachePath { get; set; } + public string MqttRoutePath { get; set; } + public string ReloadOnChange { get; set; } public string EnableChildrenMonitor { get; set; } + + public int? LockDelay { get; set; } } } diff --git a/src/Surging.Core/Surging.Core.Consul/ConsulModule.cs b/src/Surging.Core/Surging.Core.Consul/ConsulModule.cs index 206986d6f..d46898d33 100644 --- a/src/Surging.Core/Surging.Core.Consul/ConsulModule.cs +++ b/src/Surging.Core/Surging.Core.Consul/ConsulModule.cs @@ -2,27 +2,33 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Surging.Core.Consul.Configurations; +using Surging.Core.Consul.Internal; +using Surging.Core.Consul.Internal.Cluster.HealthChecks; +using Surging.Core.Consul.Internal.Cluster.HealthChecks.Implementation; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation; +using Surging.Core.Consul.Internal.Implementation; using Surging.Core.Consul.WatcherProvider; using Surging.Core.Consul.WatcherProvider.Implementation; using Surging.Core.CPlatform; using Surging.Core.CPlatform.Cache; using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Mqtt; using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Runtime.Client; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Serialization; using Surging.Core.CPlatform.Support; using System; -using System.Collections.Generic; -using System.Text; +using Autofac; namespace Surging.Core.Consul { public class ConsulModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } /// @@ -33,11 +39,15 @@ protected override void RegisterBuilder(ContainerBuilderWrapper builder) { base.RegisterBuilder(builder); var configInfo = new ConfigInfo(null); - UseConsulRouteManager(builder, configInfo) + UseConsulAddressSelector(builder) + .UseHealthCheck(builder) + .UseCounlClientProvider(builder, configInfo) + .UseConsulRouteManager(builder, configInfo) .UseConsulServiceSubscribeManager(builder, configInfo) .UseConsulCommandManager(builder, configInfo) .UseConsulCacheManager(builder, configInfo) - .UseConsulWatch(builder, configInfo); + .UseConsulWatch(builder, configInfo) + .UseConsulMqttRouteManager(builder, configInfo); } public ConsulModule UseConsulRouteManager(ContainerBuilderWrapper builder, ConfigInfo configInfo) @@ -49,7 +59,9 @@ public ConsulModule UseConsulRouteManager(ContainerBuilderWrapper builder, Confi provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>())); + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService())); return this; } @@ -62,7 +74,8 @@ public ConsulModule UseConsulCacheManager(ContainerBuilderWrapper builder, Confi provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>())); + provider.GetRequiredService>(), + provider.GetRequiredService())); return this; } @@ -74,34 +87,44 @@ public ConsulModule UseConsulCacheManager(ContainerBuilderWrapper builder, Confi /// 服务构建者。 public ConsulModule UseConsulCommandManager(ContainerBuilderWrapper builder, ConfigInfo configInfo) { - UseCommandManager(builder, provider => - { - var result = new ConsulServiceCommandManager( + UseCommandManager(builder, provider => new ConsulServiceCommandManager( GetConfigInfo(configInfo), provider.GetRequiredService>(), provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>()); - return result; - }); + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService())); return this; } public ConsulModule UseConsulServiceSubscribeManager(ContainerBuilderWrapper builder, ConfigInfo configInfo) { - UseSubscribeManager(builder, provider => - { - var result = new ConsulServiceSubscribeManager( + UseSubscribeManager(builder, provider => new ConsulServiceSubscribeManager( GetConfigInfo(configInfo), provider.GetRequiredService>(), provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>()); - return result; - }); + provider.GetRequiredService>(), + provider.GetRequiredService())); + return this; + } + + public ConsulModule UseConsulMqttRouteManager(ContainerBuilderWrapper builder, ConfigInfo configInfo) + { + UseMqttRouteManager(builder, provider => + new ConsulMqttServiceRouteManager( + GetConfigInfo(configInfo), + provider.GetRequiredService>(), + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService(), + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService())); return this; } @@ -114,11 +137,34 @@ public ConsulModule UseConsulWatch(ContainerBuilderWrapper builder, ConfigInfo c { builder.Register(provider => { - return new ClientWatchManager(configInfo); + return new ClientWatchManager(provider.Resolve>(),configInfo); }).As().SingleInstance(); return this; } + public ConsulModule UseConsulAddressSelector(ContainerBuilderWrapper builder) + { + builder.RegisterType().As().SingleInstance(); + return this; + } + + public ConsulModule UseHealthCheck(ContainerBuilderWrapper builder) + { + builder.RegisterType().As().SingleInstance(); + return this; + } + + public ConsulModule UseCounlClientProvider(ContainerBuilderWrapper builder, ConfigInfo configInfo) + { + UseCounlClientProvider(builder, provider => + new DefaultConsulClientProvider( + GetConfigInfo(configInfo), + provider.GetRequiredService(), + provider.GetRequiredService(), + provider.GetRequiredService>())); + return this; + } + public ContainerBuilderWrapper UseSubscribeManager(ContainerBuilderWrapper builder, Func factory) { builder.RegisterAdapter(factory).InstancePerLifetimeScope(); @@ -143,6 +189,18 @@ public ContainerBuilderWrapper UseRouteManager(ContainerBuilderWrapper builder, return builder; } + public ContainerBuilderWrapper UseMqttRouteManager(ContainerBuilderWrapper builder, Func factory) + { + builder.RegisterAdapter(factory).InstancePerLifetimeScope(); + return builder; + } + + public ContainerBuilderWrapper UseCounlClientProvider(ContainerBuilderWrapper builder, Func factory) + { + builder.RegisterAdapter(factory).InstancePerLifetimeScope(); + return builder; + } + private ConfigInfo GetConfigInfo(ConfigInfo config) { ConsulOption option = null; @@ -158,10 +216,12 @@ private ConfigInfo GetConfigInfo(ConfigInfo config) config = new ConfigInfo( option.ConnectionString, TimeSpan.FromSeconds(sessionTimeout), + option.LockDelay ?? config.LockDelay, option.RoutePath ?? config.RoutePath, option.SubscriberPath ?? config.SubscriberPath, option.CommandPath ?? config.CommandPath, option.CachePath ?? config.CachePath, + option.MqttRoutePath ?? config.MqttRoutePath, option.ReloadOnChange != null ? bool.Parse(option.ReloadOnChange) : config.ReloadOnChange, option.EnableChildrenMonitor != null ? bool.Parse(option.EnableChildrenMonitor) : diff --git a/src/Surging.Core/Surging.Core.Consul/ConsulMqttServiceRouteManager.cs b/src/Surging.Core/Surging.Core.Consul/ConsulMqttServiceRouteManager.cs new file mode 100644 index 000000000..47b282763 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/ConsulMqttServiceRouteManager.cs @@ -0,0 +1,390 @@ +using Consul; +using Microsoft.Extensions.Logging; +using Surging.Core.Consul.Configurations; +using Surging.Core.Consul.Internal; +using Surging.Core.Consul.Utilitys; +using Surging.Core.Consul.WatcherProvider; +using Surging.Core.Consul.WatcherProvider.Implementation; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Mqtt; +using Surging.Core.CPlatform.Mqtt.Implementation; +using Surging.Core.CPlatform.Runtime.Client; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Consul +{ + public class ConsulMqttServiceRouteManager : MqttServiceRouteManagerBase, IDisposable + { + private readonly ConfigInfo _configInfo; + private readonly ISerializer _serializer; + private readonly IMqttServiceFactory _mqttServiceFactory; + private readonly ILogger _logger; + private readonly ISerializer _stringSerializer; + private readonly IClientWatchManager _manager; + private MqttServiceRoute[] _routes; + private readonly IConsulClientProvider _consulClientFactory; + private readonly IServiceHeartbeatManager _serviceHeartbeatManager; + + public ConsulMqttServiceRouteManager(ConfigInfo configInfo, ISerializer serializer, + ISerializer stringSerializer, IClientWatchManager manager, IMqttServiceFactory mqttServiceFactory, + ILogger logger,IServiceHeartbeatManager serviceHeartbeatManager, + IConsulClientProvider consulClientFactory) : base(stringSerializer) + { + _configInfo = configInfo; + _serializer = serializer; + _stringSerializer = stringSerializer; + _mqttServiceFactory = mqttServiceFactory; + _logger = logger; + _manager = manager; + _serviceHeartbeatManager = serviceHeartbeatManager; + _consulClientFactory = consulClientFactory; + EnterRoutes().Wait(); + } + + public override async Task ClearAsync() + { + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) + { + //根据前缀获取consul结果 + var queryResult = await client.KV.List(_configInfo.MqttRoutePath); + var response = queryResult.Response; + if (response != null) + { + //删除操作 + foreach (var result in response) + { + await client.KV.DeleteCAS(result); + } + } + } + } + + public void Dispose() + { + } + + /// + /// 获取所有可用的服务路由信息。 + /// + /// 服务路由集合。 + public override async Task> GetRoutesAsync() + { + await EnterRoutes(); + return _routes; + } + + public override async Task SetRoutesAsync(IEnumerable routes) + { + var hostAddr = NetUtils.GetHostAddress(); + var mqttServiceRoutes = await GetRoutes(routes.Select(p => $"{ _configInfo.MqttRoutePath}{p.MqttDescriptor.Topic}")); + foreach (var route in routes) + { + var mqttServiceRoute = mqttServiceRoutes.Where(p => p.MqttDescriptor.Topic == route.MqttDescriptor.Topic).FirstOrDefault(); + + if (mqttServiceRoute != null) + { + var addresses = mqttServiceRoute.MqttEndpoint.Concat( + route.MqttEndpoint.Except(mqttServiceRoute.MqttEndpoint)).ToList(); + + foreach (var address in route.MqttEndpoint) + { + addresses.Remove(addresses.Where(p => p.ToString() == address.ToString()).FirstOrDefault()); + addresses.Add(address); + } + route.MqttEndpoint = addresses; + } + } + + await base.SetRoutesAsync(routes); + } + + public override async Task RemveAddressAsync(IEnumerable endpoint) + { + var routes = await GetRoutesAsync(); + try + { + foreach (var route in routes) + { + route.MqttEndpoint = route.MqttEndpoint.Except(endpoint); + } + } + catch (Exception ex) + { + throw ex; + } + await base.SetRoutesAsync(routes); + } + + public override async Task RemoveByTopicAsync(string topic, IEnumerable endpoint) + { + var routes = await GetRoutesAsync(); + try + { + var route = routes.Where(p => p.MqttDescriptor.Topic == topic).SingleOrDefault(); + if(route !=null) + { + route.MqttEndpoint = route.MqttEndpoint.Except(endpoint); + await base.SetRoutesAsync(new MqttServiceRoute[] { route }); + } + } + catch (Exception ex) + { + throw ex; + } + + } + + protected override async Task SetRoutesAsync(IEnumerable routes) + { + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) + { + foreach (var serviceRoute in routes) + { + var nodeData = _serializer.Serialize(serviceRoute); + var keyValuePair = new KVPair($"{_configInfo.MqttRoutePath}{serviceRoute.MqttDescriptor.Topic}") { Value = nodeData }; + await client.KV.Put(keyValuePair); + } + } + } + + #region 私有方法 + + private async Task RemoveExceptRoutesAsync(IEnumerable routes, AddressModel hostAddr) + { + routes = routes.ToArray(); + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) + { + if (_routes != null) + { + var oldRouteTopics = _routes.Select(i => i.MqttDescriptor.Topic).ToArray(); + var newRouteTopics = routes.Select(i => i.MqttDescriptor.Topic).ToArray(); + var deletedRouteTopics = oldRouteTopics.Except(newRouteTopics).ToArray(); + foreach (var deletedRouteTopic in deletedRouteTopics) + { + var addresses = _routes.Where(p => p.MqttDescriptor.Topic == deletedRouteTopic).Select(p => p.MqttEndpoint).FirstOrDefault(); + if (addresses.Contains(hostAddr)) + await client.KV.Delete($"{_configInfo.MqttRoutePath}{deletedRouteTopic}"); + } + } + } + } + + private async Task GetRoute(byte[] data) + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"准备转换mqtt服务路由,配置内容:{Encoding.UTF8.GetString(data)}。"); + + if (data == null) + return null; + + var descriptor = _serializer.Deserialize(data); + return (await _mqttServiceFactory.CreateMqttServiceRoutesAsync(new[] { descriptor })).First(); + } + + private async Task GetRouteDatas(string[] routes) + { + List serviceRoutes = new List(); + foreach (var route in routes) + { + var serviceRoute = await GetRouteData(route); + serviceRoutes.Add(serviceRoute); + } + return serviceRoutes.ToArray(); + } + + private async Task GetRouteData(string data) + { + if (data == null) + return null; + + var descriptor = _stringSerializer.Deserialize(data, typeof(MqttServiceDescriptor)) as MqttServiceDescriptor; + return (await _mqttServiceFactory.CreateMqttServiceRoutesAsync(new[] { descriptor })).First(); + } + + private async Task GetRoutes(IEnumerable childrens) + { + + childrens = childrens.ToArray(); + var routes = new List(childrens.Count()); + + foreach (var children in childrens) + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"准备从节点:{children}中获取mqtt路由信息。"); + + var route = await GetRoute(children); + if (route != null) + routes.Add(route); + } + + return routes.ToArray(); + } + + private async Task GetRoute(string path) + { + MqttServiceRoute result = null; + var client = await GetConsulClient(); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, path, + async (oldData, newData) => await NodeChange(oldData, newData),tmpPath=> { + var index = tmpPath.LastIndexOf("/"); + return _serviceHeartbeatManager.ExistsWhitelist(tmpPath.Substring(index + 1)); + }); + + var queryResult = await client.KV.Keys(path); + if (queryResult.Response != null) + { + var data = (await client.GetDataAsync(path)); + if (data != null) + { + watcher.SetCurrentData(data); + result = await GetRoute(data); + } + } + return result; + } + + private async Task EnterRoutes() + { + if (_routes != null && _routes.Length > 0) + return; + Action action = null; + var client =await GetConsulClient(); + if (_configInfo.EnableChildrenMonitor) + { + var watcher = new ChildrenMonitorWatcher(GetConsulClient, _manager, _configInfo.MqttRoutePath, + async (oldChildrens, newChildrens) => await ChildrenChange(oldChildrens, newChildrens), + (result) => ConvertPaths(result).Result); + action = currentData => watcher.SetCurrentData(currentData); + } + if (client.KV.Keys(_configInfo.MqttRoutePath).Result.Response?.Count() > 0) + { + var result = await client.GetChildrenAsync(_configInfo.MqttRoutePath); + var keys = await client.KV.Keys(_configInfo.MqttRoutePath); + var childrens = result; + action?.Invoke(ConvertPaths(childrens).Result.Select(key => $"{_configInfo.MqttRoutePath}{key}").ToArray()); + _routes = await GetRoutes(keys.Response); + } + else + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Warning)) + _logger.LogWarning($"无法获取路由信息,因为节点:{_configInfo.MqttRoutePath},不存在。"); + _routes = new MqttServiceRoute[0]; + } + } + + + private static bool DataEquals(IReadOnlyList data1, IReadOnlyList data2) + { + if (data1.Count != data2.Count) + return false; + for (var i = 0; i < data1.Count; i++) + { + var b1 = data1[i]; + var b2 = data2[i]; + if (b1 != b2) + return false; + } + return true; + } + + private async ValueTask GetConsulClient() + { + var client = await _consulClientFactory.GetClient(); + return client; + } + + /// + /// 转化topic集合 + /// + /// 信息数据集合 + /// 返回路径集合 + private async Task ConvertPaths(string[] datas) + { + List topics = new List(); + foreach (var data in datas) + { + var result = await GetRouteData(data); + var topic = result?.MqttDescriptor.Topic; + if (!string.IsNullOrEmpty(topic)) + topics.Add(topic); + } + return topics.ToArray(); + } + + private async Task NodeChange(byte[] oldData, byte[] newData) + { + if (DataEquals(oldData, newData)) + return; + + var newRoute = await GetRoute(newData); + //得到旧的路由。 + var oldRoute = _routes.FirstOrDefault(i => i.MqttDescriptor.Topic == newRoute.MqttDescriptor.Topic); + + lock (_routes) + { + //删除旧路由,并添加上新的路由。 + _routes = + _routes + .Where(i => i.MqttDescriptor.Topic != newRoute.MqttDescriptor.Topic) + .Concat(new[] { newRoute }).ToArray(); + } + + //触发路由变更事件。 + OnChanged(new MqttServiceRouteChangedEventArgs(newRoute, oldRoute)); + } + + private async Task ChildrenChange(string[] oldChildrens, string[] newChildrens) + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"最新的mqtt节点信息:{string.Join(",", newChildrens)}"); + + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"旧的mqtt节点信息:{string.Join(",", oldChildrens)}"); + + //计算出已被删除的节点。 + var deletedChildrens = oldChildrens.Except(newChildrens).ToArray(); + //计算出新增的节点。 + var createdChildrens = newChildrens.Except(oldChildrens).ToArray(); + + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"需要被删除的mqtt路由节点:{string.Join(",", deletedChildrens)}"); + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"需要被添加的mqtt路由节点:{string.Join(",", createdChildrens)}"); + + //获取新增的路由信息。 + var newRoutes = (await GetRoutes(createdChildrens)).ToArray(); + + var routes = _routes.ToArray(); + lock (_routes) + { + _routes = _routes + //删除无效的节点路由。 + .Where(i => !deletedChildrens.Contains($"{_configInfo.MqttRoutePath}{i.MqttDescriptor.Topic}")) + //连接上新的路由。 + .Concat(newRoutes) + .ToArray(); + } + //需要删除的路由集合。 + var deletedRoutes = routes.Where(i => deletedChildrens.Contains($"{_configInfo.MqttRoutePath}{i.MqttDescriptor.Topic}")).ToArray(); + //触发删除事件。 + OnRemoved(deletedRoutes.Select(route => new MqttServiceRouteEventArgs(route)).ToArray()); + + //触发路由被创建事件。 + OnCreated(newRoutes.Select(route => new MqttServiceRouteEventArgs(route)).ToArray()); + + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information)) + _logger.LogInformation("mqtt路由数据更新成功。"); + } + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/ConsulServiceCacheManager.cs b/src/Surging.Core/Surging.Core.Consul/ConsulServiceCacheManager.cs index 94b7165ea..7b32dc090 100644 --- a/src/Surging.Core/Surging.Core.Consul/ConsulServiceCacheManager.cs +++ b/src/Surging.Core/Surging.Core.Consul/ConsulServiceCacheManager.cs @@ -1,6 +1,7 @@ using Consul; using Microsoft.Extensions.Logging; using Surging.Core.Consul.Configurations; +using Surging.Core.Consul.Internal; using Surging.Core.Consul.Utilitys; using Surging.Core.Consul.WatcherProvider; using Surging.Core.Consul.WatcherProvider.Implementation; @@ -17,65 +18,56 @@ namespace Surging.Core.Consul { public class ConsulServiceCacheManager : ServiceCacheManagerBase, IDisposable { - private readonly ConsulClient _consul; private readonly ConfigInfo _configInfo; private readonly ISerializer _serializer; private readonly ILogger _logger; private readonly IClientWatchManager _manager; private ServiceCache[] _serviceCaches; private readonly IServiceCacheFactory _serviceCacheFactory; - private readonly ISerializer _stringSerializer; + private readonly ISerializer _stringSerializer; + private readonly IConsulClientProvider _consulClientFactory; public ConsulServiceCacheManager(ConfigInfo configInfo, ISerializer serializer, ISerializer stringSerializer, IClientWatchManager manager, IServiceCacheFactory serviceCacheFactory, - ILogger logger) : base(stringSerializer) + ILogger logger, IConsulClientProvider consulClientFactory) : base(stringSerializer) { _configInfo = configInfo; _serializer = serializer; _stringSerializer = stringSerializer; _serviceCacheFactory = serviceCacheFactory; + _consulClientFactory = consulClientFactory; _logger = logger; _manager = manager; - _consul = new ConsulClient(config => - { - config.Address = new Uri($"http://{configInfo.Host}:{configInfo.Port}"); - }, null, h => { h.UseProxy = false; h.Proxy = null; }); EnterCaches().Wait(); } public override async Task ClearAsync() { - - var queryResult = await _consul.KV.List(_configInfo.CachePath); - - var response = queryResult.Response; - if (response != null) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - foreach (var result in response) + // 根据前缀获取consul结果 + var queryResult = await client.KV.List(_configInfo.CachePath); + var response = queryResult.Response; + if (response != null) { - await _consul.KV.DeleteCAS(result); + foreach (var result in response) + { + await client.KV.DeleteCAS(result); + } } } } public void Dispose() { - _consul.Dispose(); } public override async Task SetCachesAsync(IEnumerable caches) { var serviceCaches = await GetCaches(caches.Select(p => $"{ _configInfo.CachePath}{p.CacheDescriptor.Id}")); - foreach (var cache in caches) - { - var serviceCache = serviceCaches.Where(p => p.CacheDescriptor.Id == cache.CacheDescriptor.Id).FirstOrDefault(); - if (serviceCache != null) - { - cache.CacheEndpoint = serviceCache.CacheEndpoint.Concat( - cache.CacheEndpoint.Except(serviceCache.CacheEndpoint)); - } - } - await RemoveExceptCachesAsync(caches); + + await RemoveCachesAsync(caches); await base.SetCachesAsync(caches); } @@ -104,11 +96,15 @@ public override async Task RemveAddressAsync(IEnumerable endpoint public override async Task SetCachesAsync(IEnumerable cacheDescriptors) { - foreach (var cacheDescriptor in cacheDescriptors) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - var nodeData = _serializer.Serialize(cacheDescriptor); - var keyValuePair = new KVPair($"{_configInfo.CachePath}{cacheDescriptor.CacheDescriptor.Id}") { Value = nodeData }; - await _consul.KV.Put(keyValuePair); + foreach (var cacheDescriptor in cacheDescriptors) + { + var nodeData = _serializer.Serialize(cacheDescriptor); + var keyValuePair = new KVPair($"{_configInfo.CachePath}{cacheDescriptor.CacheDescriptor.Id}") { Value = nodeData }; + await client.KV.Put(keyValuePair); + } } } @@ -130,15 +126,40 @@ private async Task GetCaches(IEnumerable childrens) return caches.ToArray(); } + private async Task GetCaches(IEnumerable childrens) + { + if (childrens == null) return new ServiceCache[0]; + childrens = childrens.ToArray(); + var caches = new List(childrens.Count()); + + foreach (var children in childrens) + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"准备从节点:{children}中获取缓存信息。"); + + var cache = await GetCache(children); + if (cache != null) + { + caches.Add(cache); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, $"{_configInfo.CachePath}{cache.CacheDescriptor.Id}", + async (oldData, newData) => await NodeChange(oldData, newData), null); + watcher.SetCurrentData(children); + } + } + return caches.ToArray(); + } + + private async Task GetCache(string path) { ServiceCache result = null; - var watcher = new NodeMonitorWatcher(_consul, _manager, path, - async (oldData, newData) => await NodeChange(oldData, newData)); - var queryResult = await _consul.KV.Keys(path); + var client = await GetConsulClient(); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, path, + async (oldData, newData) => await NodeChange(oldData, newData),null); + var queryResult = await client.KV.Keys(path); if (queryResult.Response != null) { - var data = (await _consul.GetDataAsync(path)); + var data = (await client.GetDataAsync(path)); if (data != null) { watcher.SetCurrentData(data); @@ -150,24 +171,22 @@ private async Task GetCache(string path) #region 私有方法 - private async Task RemoveExceptCachesAsync(IEnumerable caches) + private async Task RemoveCachesAsync(IEnumerable caches) { var path = _configInfo.CachePath; caches = caches.ToArray(); if (_serviceCaches != null) { - var oldCacheIds = _serviceCaches.Select(i => i.CacheDescriptor.Id).ToArray(); - var newCacheIds = _serviceCaches.Select(i => i.CacheDescriptor.Id).ToArray(); - var deletedCacheIds = oldCacheIds.Except(newCacheIds).ToArray(); - foreach (var deletedCacheId in deletedCacheIds) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - var endpoints = _serviceCaches.Where(p => p.CacheDescriptor.Id == deletedCacheId).Select(p => p.CacheEndpoint).FirstOrDefault(); - var nodePath = $"{path}{deletedCacheId}"; - foreach (var endpoint in endpoints) + + var deletedCacheIds = caches.Select(i => i.CacheDescriptor.Id).ToArray(); + foreach (var deletedCacheId in deletedCacheIds) { - if (caches.Any(p => p.CacheEndpoint.Select(a => a.ToString()).Contains(endpoint.ToString()))) - await _consul.KV.Delete(nodePath); + var nodePath = $"{path}{deletedCacheId}"; + await client.KV.Delete(nodePath); } } } @@ -176,17 +195,17 @@ private async Task RemoveExceptCachesAsync(IEnumerable caches) private async Task EnterCaches() { if (_serviceCaches != null && _serviceCaches.Length > 0) - return; - var watcher = new ChildrenMonitorWatcher(_consul, _manager, _configInfo.CachePath, + return; + var client =await GetConsulClient(); + var watcher = new ChildrenMonitorWatcher(GetConsulClient, _manager, _configInfo.CachePath, async (oldChildrens, newChildrens) => await ChildrenChange(oldChildrens, newChildrens), (result) => ConvertPaths(result).Result); - if (_consul.KV.Keys(_configInfo.CachePath).Result.Response?.Count() > 0) + if (client.KV.Keys(_configInfo.CachePath).Result.Response?.Count() > 0) { - var result = await _consul.GetChildrenAsync(_configInfo.CachePath); - var keys = await _consul.KV.Keys(_configInfo.CachePath); - var childrens = result; - watcher.SetCurrentData(ConvertPaths(childrens).Result.Select(key => $"{_configInfo.CachePath}{key}").ToArray()); - _serviceCaches = await GetCaches(keys.Response); + var response = await client.GetChildrenListAsync(_configInfo.CachePath); + _serviceCaches = await GetCaches(response); + var serviceCacheIds = _serviceCaches.Select(p => p.CacheDescriptor.Id).ToArray(); + watcher.SetCurrentData(serviceCacheIds.Select(key => $"{_configInfo.CachePath}{key}").ToArray()); } else { @@ -255,6 +274,12 @@ private async Task ConvertPaths(string[] datas) return paths.ToArray(); } + private async ValueTask GetConsulClient() + { + var client = await _consulClientFactory.GetClient(); + return client; + } + private async Task NodeChange(byte[] oldData, byte[] newData) { if (DataEquals(oldData, newData)) diff --git a/src/Surging.Core/Surging.Core.Consul/ConsulServiceCommandManager.cs b/src/Surging.Core/Surging.Core.Consul/ConsulServiceCommandManager.cs index e9a9538fe..fa71d7c6c 100644 --- a/src/Surging.Core/Surging.Core.Consul/ConsulServiceCommandManager.cs +++ b/src/Surging.Core/Surging.Core.Consul/ConsulServiceCommandManager.cs @@ -16,12 +16,13 @@ using Surging.Core.Consul.WatcherProvider.Implementation; using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Routing.Implementation; +using Surging.Core.CPlatform.Runtime.Client; +using Surging.Core.Consul.Internal; namespace Surging.Core.Consul { public class ConsulServiceCommandManager : ServiceCommandManagerBase, IDisposable { - private readonly ConsulClient _consul; private readonly ConfigInfo _configInfo; private readonly ISerializer _serializer; private readonly ILogger _logger; @@ -29,43 +30,47 @@ public class ConsulServiceCommandManager : ServiceCommandManagerBase, IDisposabl private ServiceCommandDescriptor[] _serviceCommands; private readonly ISerializer _stringSerializer; private readonly IServiceRouteManager _serviceRouteManager; + private readonly IServiceHeartbeatManager _serviceHeartbeatManager; + private readonly IConsulClientProvider _consulClientFactory; public ConsulServiceCommandManager(ConfigInfo configInfo, ISerializer serializer, ISerializer stringSerializer, IServiceRouteManager serviceRouteManager, IClientWatchManager manager, IServiceEntryManager serviceEntryManager, - ILogger logger, bool enableChildrenMonitor = false) : base(stringSerializer, serviceEntryManager) + ILogger logger, + IServiceHeartbeatManager serviceHeartbeatManager, IConsulClientProvider consulClientFactory) : base(stringSerializer, serviceEntryManager) { _configInfo = configInfo; _serializer = serializer; _logger = logger; + _consulClientFactory = consulClientFactory; _stringSerializer = stringSerializer; _manager = manager; _serviceRouteManager = serviceRouteManager; - _consul = new ConsulClient(config => - { - config.Address = new Uri($"http://{configInfo.Host}:{configInfo.Port}"); - - }, null, h => { h.UseProxy = false; h.Proxy = null; }); - EnterServiceCommands().Wait(); + _serviceHeartbeatManager = serviceHeartbeatManager; + EnterServiceCommands().Wait(); _serviceRouteManager.Removed += ServiceRouteManager_Removed; } public override async Task ClearAsync() { - var queryResult = await _consul.KV.List(_configInfo.CommandPath); - - var response = queryResult.Response; - if (response != null) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - foreach (var result in response) + //根据前缀获取consul结果 + var queryResult = await client.KV.List(_configInfo.CommandPath); + var response = queryResult.Response; + if (response != null) { - await _consul.KV.DeleteCAS(result); + //删除操作 + foreach (var result in response) + { + await client.KV.DeleteCAS(result); + } } } } public void Dispose() { - _consul.Dispose(); } /// @@ -103,12 +108,12 @@ public void NodeChange(byte[] oldData, byte[] newData) else if (oldCommand == null) OnCreated(new ServiceCommandEventArgs(newCommand)); else - //触发服务命令变更事件。 - OnChanged(new ServiceCommandChangedEventArgs(newCommand, oldCommand)); + //触发服务命令变更事件。 + OnChanged(new ServiceCommandChangedEventArgs(newCommand, oldCommand)); } public void NodeChange(ServiceCommandDescriptor newCommand) - { + { //得到旧的服务命令。 var oldCommand = _serviceCommands.FirstOrDefault(i => i.ServiceId == newCommand.ServiceId); @@ -126,33 +131,43 @@ public void NodeChange(ServiceCommandDescriptor newCommand) public override async Task SetServiceCommandsAsync(IEnumerable serviceCommands) { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information)) - _logger.LogInformation("准备添加服务命令。"); - foreach (var serviceCommand in serviceCommands) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - var nodeData = _serializer.Serialize(serviceCommand); - var keyValuePair = new KVPair($"{_configInfo.CommandPath}{serviceCommand.ServiceId}") { Value = nodeData }; - var isSuccess= await _consul.KV.Put(keyValuePair); - if (isSuccess.Response) - NodeChange(serviceCommand); - } + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information)) + _logger.LogInformation("准备添加服务命令。"); + foreach (var serviceCommand in serviceCommands) + { + var nodeData = _serializer.Serialize(serviceCommand); + var keyValuePair = new KVPair($"{_configInfo.CommandPath}{serviceCommand.ServiceId}") { Value = nodeData }; + var isSuccess = await client.KV.Put(keyValuePair); + if (isSuccess.Response) + NodeChange(serviceCommand); + } + } } protected override async Task InitServiceCommandsAsync(IEnumerable serviceCommands) { - var commands = await GetServiceCommands(serviceCommands.Select(p => $"{ _configInfo.CommandPath}{ p.ServiceId}")); + var client = await GetConsulClient(); + var response = await client.GetChildrenListAsync(_configInfo.CommandPath); + var commands = await GetServiceCommands(response); //传参数到方法中 if (commands.Count() == 0 || _configInfo.ReloadOnChange) - { + { await SetServiceCommandsAsync(serviceCommands); } } private void ServiceRouteManager_Removed(object sender, ServiceRouteEventArgs e) - { - _consul.KV.Delete($"{_configInfo.CommandPath}{e.Route.ServiceDescriptor.Id}").Wait(); + { + var clients = _consulClientFactory.GetClients().Result; + foreach (var client in clients) + { + client.KV.Delete($"{_configInfo.CommandPath}{e.Route.ServiceDescriptor.Id}").Wait(); + } } - + private ServiceCommandDescriptor GetServiceCommand(byte[] data) { @@ -189,12 +204,17 @@ private ServiceCommandDescriptor GetServiceCommandData(string data) private async Task GetServiceCommand(string path) { ServiceCommandDescriptor result = null; - var watcher = new NodeMonitorWatcher(_consul, _manager, path, - (oldData, newData) => NodeChange(oldData, newData)); - var queryResult = await _consul.KV.Keys(path); + var client = await GetConsulClient(); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, path, + (oldData, newData) => NodeChange(oldData, newData), tmpPath => + { + var index = tmpPath.LastIndexOf("/"); + return _serviceHeartbeatManager.ExistsWhitelist(tmpPath.Substring(index + 1)); + }); + var queryResult = await client.KV.Keys(path); if (queryResult.Response != null) { - var data = (await _consul.GetDataAsync(path)); + var data = (await client.GetDataAsync(path)); if (data != null) { watcher.SetCurrentData(data); @@ -225,20 +245,58 @@ private async Task GetServiceCommands(IEnumerable GetServiceCommands(IEnumerable childrens) + { + if (childrens == null) return Task.FromResult(new ServiceCommandDescriptor[0]); + childrens = childrens.ToArray(); + var serviceCommands = new List(childrens.Count()); + + foreach (var children in childrens) + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"准备从节点:{children}中获取服务命令信息。"); + + var serviceCommand = GetServiceCommand(children); + if (serviceCommand != null) + { + serviceCommands.Add(serviceCommand); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, $"{ _configInfo.CommandPath}{ serviceCommand.ServiceId}", + (oldData, newData) => NodeChange(oldData, newData), tmpPath => + { + var index = tmpPath.LastIndexOf("/"); + return _serviceHeartbeatManager.ExistsWhitelist(tmpPath.Substring(index + 1)); + }); + watcher.SetCurrentData(children); + } + } + return Task.FromResult(serviceCommands.ToArray()); + } + + private async ValueTask GetConsulClient() + { + var client = await _consulClientFactory.GetClient(); + return client; + } + private async Task EnterServiceCommands() { if (_serviceCommands != null) - return; - var watcher = new ChildrenMonitorWatcher(_consul, _manager, _configInfo.CommandPath, + return; + Action action = null; + var client = await GetConsulClient(); + if (_configInfo.EnableChildrenMonitor) + { + var watcher = new ChildrenMonitorWatcher(GetConsulClient, _manager, _configInfo.CommandPath, async (oldChildrens, newChildrens) => await ChildrenChange(oldChildrens, newChildrens), (result) => ConvertPaths(result)); - if (_consul.KV.Keys(_configInfo.CommandPath).Result.Response?.Count() > 0) + action = currentData => watcher.SetCurrentData(currentData); + } + if (client.KV.Keys(_configInfo.CommandPath).Result.Response?.Count() > 0) { - var result = await _consul.GetChildrenAsync(_configInfo.CommandPath); - var keys = await _consul.KV.Keys(_configInfo.CommandPath); - var childrens = result; - watcher.SetCurrentData(ConvertPaths(childrens).Select(key => $"{_configInfo.CommandPath}{key}").ToArray()); - _serviceCommands = await GetServiceCommands(keys.Response); + var response = await client.GetChildrenListAsync(_configInfo.CommandPath); + _serviceCommands = await GetServiceCommands(response); + var serviceIds = _serviceCommands.Select(p => p.ServiceId).ToArray(); + action?.Invoke(serviceIds.Select(key => $"{_configInfo.CommandPath}{key}").ToArray()); } else { @@ -300,27 +358,27 @@ public async Task ChildrenChange(string[] oldChildrens, string[] newChildrens) //获取新增的服务命令信息。 var newCommands = (await GetServiceCommands(createdChildrens)).ToArray(); - - var serviceCommands = _serviceCommands.ToArray(); - lock (_serviceCommands) - { - _serviceCommands = _serviceCommands - //删除无效的节点服务命令。 - .Where(i => !deletedChildrens.Contains($"{_configInfo.CommandPath}{i.ServiceId}")) - //连接上新的服务命令。 - .Concat(newCommands) - .ToArray(); - } - //需要删除的服务命令集合。 - var deletedRoutes = serviceCommands.Where(i => deletedChildrens.Contains($"{_configInfo.CommandPath}{i.ServiceId}")).ToArray(); - //触发删除事件。 - OnRemoved(deletedRoutes.Select(command => new ServiceCommandEventArgs(command)).ToArray()); - - //触发服务命令被创建事件。 - OnCreated(newCommands.Select(command => new ServiceCommandEventArgs(command)).ToArray()); - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information)) - _logger.LogInformation("服务命令数据更新成功。"); + var serviceCommands = _serviceCommands.ToArray(); + lock (_serviceCommands) + { + _serviceCommands = _serviceCommands + //删除无效的节点服务命令。 + .Where(i => !deletedChildrens.Contains($"{_configInfo.CommandPath}{i.ServiceId}")) + //连接上新的服务命令。 + .Concat(newCommands) + .ToArray(); } + //需要删除的服务命令集合。 + var deletedRoutes = serviceCommands.Where(i => deletedChildrens.Contains($"{_configInfo.CommandPath}{i.ServiceId}")).ToArray(); + //触发删除事件。 + OnRemoved(deletedRoutes.Select(command => new ServiceCommandEventArgs(command)).ToArray()); + + //触发服务命令被创建事件。 + OnCreated(newCommands.Select(command => new ServiceCommandEventArgs(command)).ToArray()); + + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information)) + _logger.LogInformation("服务命令数据更新成功。"); + } } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Consul/ConsulServiceRouteManager.cs b/src/Surging.Core/Surging.Core.Consul/ConsulServiceRouteManager.cs index 9c98def3f..88bd10cda 100644 --- a/src/Surging.Core/Surging.Core.Consul/ConsulServiceRouteManager.cs +++ b/src/Surging.Core/Surging.Core.Consul/ConsulServiceRouteManager.cs @@ -1,26 +1,30 @@ -using Surging.Core.CPlatform.Routing.Implementation; -using System; -using System.Collections.Generic; -using System.Text; -using Surging.Core.CPlatform.Routing; -using System.Threading.Tasks; -using Surging.Core.CPlatform.Serialization; +using Consul; using Microsoft.Extensions.Logging; using Surging.Core.Consul.Configurations; -using Consul; -using System.Threading; -using System.Linq; -using Surging.Core.Consul.WatcherProvider; +using Surging.Core.Consul.Internal; using Surging.Core.Consul.Utilitys; +using Surging.Core.Consul.WatcherProvider; using Surging.Core.Consul.WatcherProvider.Implementation; using Surging.Core.CPlatform.Address; -using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Routing.Implementation; +using Surging.Core.CPlatform.Runtime.Client; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace Surging.Core.Consul { + /// + /// consul服务路由管理器 + /// public class ConsulServiceRouteManager : ServiceRouteManagerBase, IDisposable { - private readonly ConsulClient _consul; private readonly ConfigInfo _configInfo; private readonly ISerializer _serializer; private readonly IServiceRouteFactory _serviceRouteFactory; @@ -28,41 +32,50 @@ public class ConsulServiceRouteManager : ServiceRouteManagerBase, IDisposable private readonly ISerializer _stringSerializer; private readonly IClientWatchManager _manager; private ServiceRoute[] _routes; - private readonly bool _enableChildrenMonitor; + private readonly IConsulClientProvider _consulClientProvider; + private readonly IServiceHeartbeatManager _serviceHeartbeatManager; public ConsulServiceRouteManager(ConfigInfo configInfo, ISerializer serializer, ISerializer stringSerializer, IClientWatchManager manager, IServiceRouteFactory serviceRouteFactory, - ILogger logger) : base(stringSerializer) + ILogger logger, + IServiceHeartbeatManager serviceHeartbeatManager, IConsulClientProvider consulClientProvider) : base(stringSerializer) { _configInfo = configInfo; _serializer = serializer; _stringSerializer = stringSerializer; _serviceRouteFactory = serviceRouteFactory; _logger = logger; + _consulClientProvider = consulClientProvider; _manager = manager; - _consul = new ConsulClient(config => - { - config.Address = new Uri($"http://{configInfo.Host}:{configInfo.Port}"); - },null,h=> { h.UseProxy = false; h.Proxy = null; }); + _serviceHeartbeatManager = serviceHeartbeatManager; EnterRoutes().Wait(); } + /// + /// 清空服务路由 + /// + /// public override async Task ClearAsync() { - var queryResult = await _consul.KV.List(_configInfo.RoutePath); - var response = queryResult.Response; - if (response != null) + var clients = await _consulClientProvider.GetClients(); + foreach (var client in clients) { - foreach (var result in response) + //根据前缀获取consul结果 + var queryResult = await client.KV.List(_configInfo.RoutePath); + var response = queryResult.Response; + if (response != null) { - await _consul.KV.DeleteCAS(result); + //删除操作 + foreach (var result in response) + { + await client.KV.DeleteCAS(result); + } } } } public void Dispose() { - _consul.Dispose(); } /// @@ -77,27 +90,40 @@ public override async Task> GetRoutesAsync() public override async Task SetRoutesAsync(IEnumerable routes) { - var hostAddr = RpcContext.GetContext().GetAttachment("Host") as AddressModel; - var serviceRoutes = await GetRoutes(routes.Select(p => $"{ _configInfo.RoutePath}{p.ServiceDescriptor.Id}")); - foreach (var route in routes) + // var locks = await CreateLock(); + try { - var serviceRoute = serviceRoutes.Where(p => p.ServiceDescriptor.Id == route.ServiceDescriptor.Id).FirstOrDefault(); - - if (serviceRoute != null) + await _consulClientProvider.Check(); + var hostAddr = NetUtils.GetHostAddress(); + var client = await GetConsulClient(); + var response = await client.GetChildrenListAsync(_configInfo.RoutePath); + var serviceRoutes = await GetRoutes(response); + foreach (var route in routes) { - var addresses = serviceRoute.Address.Concat( - route.Address.Except(serviceRoute.Address)).ToList(); + var serviceRoute = serviceRoutes.Where(p => p.ServiceDescriptor.Id == route.ServiceDescriptor.Id).FirstOrDefault(); - foreach (var address in route.Address) + if (serviceRoute != null) { - addresses.Remove(addresses.Where(p => p.ToString() == address.ToString()).FirstOrDefault()); - addresses.Add(address); + var addresses = serviceRoute.Address.Concat( + route.Address.Except(serviceRoute.Address)).ToList(); + + foreach (var address in route.Address) + { + addresses.Remove(addresses.Where(p => p.ToString() == address.ToString()).FirstOrDefault()); + addresses.Add(address); + } + route.Address = addresses; } - route.Address = addresses; } + await RemoveExceptRoutesAsync(routes, hostAddr); + var routeIds = serviceRoutes.Where(p => p.Address.Contains(hostAddr)).Select(p => p.ServiceDescriptor.Id).ToList(); + routes = routes.Where(p => !routeIds.Contains(p.ServiceDescriptor.Id)); + await base.SetRoutesAsync(routes); + } + finally + { + //locks.ForEach(p => p.Release()); } - await RemoveExceptRoutesAsync(routes, hostAddr); - await base.SetRoutesAsync(routes); } public override async Task RemveAddressAsync(IEnumerable Address) @@ -110,21 +136,24 @@ public override async Task RemveAddressAsync(IEnumerable Address) route.Address = route.Address.Except(Address); } } - catch(Exception ex) + catch (Exception ex) { throw ex; } await base.SetRoutesAsync(routes); } - + protected override async Task SetRoutesAsync(IEnumerable routes) { - - foreach (var serviceRoute in routes) + var clients = await _consulClientProvider.GetClients(); + foreach (var client in clients) { - var nodeData = _serializer.Serialize(serviceRoute); - var keyValuePair = new KVPair($"{_configInfo.RoutePath}{serviceRoute.ServiceDescriptor.Id}") { Value = nodeData }; - await _consul.KV.Put(keyValuePair); + foreach (var serviceRoute in routes) + { + var nodeData = _serializer.Serialize(serviceRoute); + var keyValuePair = new KVPair($"{_configInfo.RoutePath}{serviceRoute.ServiceDescriptor.Id}") { Value = nodeData }; + await client.KV.Put(keyValuePair); + } } } @@ -133,21 +162,53 @@ protected override async Task SetRoutesAsync(IEnumerable private async Task RemoveExceptRoutesAsync(IEnumerable routes, AddressModel hostAddr) { routes = routes.ToArray(); - - if (_routes != null) + var clients = await _consulClientProvider.GetClients(); + foreach (var client in clients) { - var oldRouteIds = _routes.Select(i => i.ServiceDescriptor.Id).ToArray(); - var newRouteIds = routes.Select(i => i.ServiceDescriptor.Id).ToArray(); - var deletedRouteIds = oldRouteIds.Except(newRouteIds).ToArray(); - foreach (var deletedRouteId in deletedRouteIds) + if (_routes != null) { - var addresses = _routes.Where(p => p.ServiceDescriptor.Id == deletedRouteId).Select(p => p.Address).FirstOrDefault(); - if (addresses.Contains(hostAddr)) - await _consul.KV.Delete($"{_configInfo.RoutePath}{deletedRouteId}"); + var oldRouteIds = _routes.Select(i => i.ServiceDescriptor.Id).ToArray(); + var newRouteIds = routes.Select(i => i.ServiceDescriptor.Id).ToArray(); + var deletedRouteIds = oldRouteIds.Except(newRouteIds).ToArray(); + foreach (var deletedRouteId in deletedRouteIds) + { + var addresses = _routes.Where(p => p.ServiceDescriptor.Id == deletedRouteId).Select(p => p.Address).FirstOrDefault(); + if (addresses.Contains(hostAddr)) + await client.KV.Delete($"{_configInfo.RoutePath}{deletedRouteId}"); + } } } } + private async Task> CreateLock() + { + var result = new List(); + var clients = await _consulClientProvider.GetClients(); + foreach (var client in clients) + { + var key = $"lock_{_configInfo.RoutePath}"; + var writeResult = await client.KV.Get(key); + if (writeResult.Response != null) + { + var distributedLock = await client.AcquireLock(key); + result.Add(distributedLock); + } + else + { + var distributedLock = await client.AcquireLock(new LockOptions($"lock_{_configInfo.RoutePath}") + { + SessionTTL = TimeSpan.FromSeconds(_configInfo.LockDelay), + LockTryOnce = true, + LockWaitTime = TimeSpan.FromSeconds(_configInfo.LockDelay) + }, _configInfo.LockDelay == 0 ? + default : + new CancellationTokenSource(TimeSpan.FromSeconds(_configInfo.LockDelay)).Token); + result.Add(distributedLock); + } + + } + return result; + } private async Task GetRoute(byte[] data) { if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) @@ -199,15 +260,48 @@ private async Task GetRoutes(IEnumerable childrens) return routes.ToArray(); } + private async Task GetRoutes(IEnumerable childrens) + { + if (childrens == null) return new ServiceRoute[0]; + childrens = childrens.ToArray(); + var routes = new List(childrens.Count()); + + foreach (var children in childrens) + { + if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + _logger.LogDebug($"准备从节点:{children}中获取路由信息。"); + + var route = await GetRoute(children); + if (route != null) + { + routes.Add(route); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, $"{_configInfo.RoutePath}{route.ServiceDescriptor.Id}", + async (oldData, newData) => await NodeChange(oldData, newData), tmpPath => + { + var index = tmpPath.LastIndexOf("/"); + return _serviceHeartbeatManager.ExistsWhitelist(tmpPath.Substring(index + 1)); + }); + watcher.SetCurrentData(children); + } + } + return routes.ToArray(); + } + private async Task GetRoute(string path) { ServiceRoute result = null; - var watcher = new NodeMonitorWatcher(_consul, _manager, path, - async (oldData, newData) => await NodeChange(oldData, newData)); - var queryResult = await _consul.KV.Keys(path); + var client = await GetConsulClient(); + var watcher = new NodeMonitorWatcher(GetConsulClient, _manager, path, + async (oldData, newData) => await NodeChange(oldData, newData), tmpPath => + { + var index = tmpPath.LastIndexOf("/"); + return _serviceHeartbeatManager.ExistsWhitelist(tmpPath.Substring(index + 1)); + }); + + var queryResult = await client.KV.Keys(path); if (queryResult.Response != null) { - var data = (await _consul.GetDataAsync(path)); + var data = (await client.GetDataAsync(path)); if (data != null) { watcher.SetCurrentData(data); @@ -217,20 +311,36 @@ private async Task GetRoute(string path) return result; } + private async ValueTask GetConsulClient() + { + var client = await _consulClientProvider.GetClient(); + return client; + } + private async Task EnterRoutes() { if (_routes != null && _routes.Length > 0) return; - var watcher = new ChildrenMonitorWatcher(_consul, _manager, _configInfo.RoutePath, + Action action = null; + var client = await GetConsulClient(); + //判断是否启用子监视器 + if (_configInfo.EnableChildrenMonitor) + { + //创建子监控类 + var watcher = new ChildrenMonitorWatcher(GetConsulClient, _manager, _configInfo.RoutePath, async (oldChildrens, newChildrens) => await ChildrenChange(oldChildrens, newChildrens), (result) => ConvertPaths(result).Result); - if (_consul.KV.Keys(_configInfo.RoutePath).Result.Response?.Count() > 0) + //对委托绑定方法 + action = currentData => watcher.SetCurrentData(currentData); + } + if (client.KV.Keys(_configInfo.RoutePath).Result.Response?.Count() > 0) { - var result = await _consul.GetChildrenAsync(_configInfo.RoutePath); - var keys = await _consul.KV.Keys(_configInfo.RoutePath); - var childrens = result; - watcher.SetCurrentData(ConvertPaths(childrens).Result.Select(key => $"{_configInfo.RoutePath}{key}").ToArray()); - _routes = await GetRoutes(keys.Response); + var response = await client.GetChildrenListAsync(_configInfo.RoutePath); + //重新赋值到routes中 + _routes = await GetRoutes(response); + var serviceIds = _routes.Select(p => p.ServiceDescriptor.Id).ToArray(); + //传参数到方法中 + action?.Invoke(serviceIds.Select(key => $"{_configInfo.RoutePath}{key}").ToArray()); } else { @@ -289,11 +399,17 @@ private async Task NodeChange(byte[] oldData, byte[] newData) .Where(i => i.ServiceDescriptor.Id != newRoute.ServiceDescriptor.Id) .Concat(new[] { newRoute }).ToArray(); } - + //触发路由变更事件。 OnChanged(new ServiceRouteChangedEventArgs(newRoute, oldRoute)); } + /// + /// 数据更新 + /// + /// 旧的节点信息 + /// 最新的节点信息 + /// private async Task ChildrenChange(string[] oldChildrens, string[] newChildrens) { if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) @@ -318,12 +434,14 @@ private async Task ChildrenChange(string[] oldChildrens, string[] newChildrens) var routes = _routes.ToArray(); lock (_routes) { + #region 节点变更操作 _routes = _routes //删除无效的节点路由。 .Where(i => !deletedChildrens.Contains($"{_configInfo.RoutePath}{i.ServiceDescriptor.Id}")) //连接上新的路由。 .Concat(newRoutes) .ToArray(); + #endregion } //需要删除的路由集合。 var deletedRoutes = routes.Where(i => deletedChildrens.Contains($"{_configInfo.RoutePath}{i.ServiceDescriptor.Id}")).ToArray(); diff --git a/src/Surging.Core/Surging.Core.Consul/ConsulServiceSubscribeManager.cs b/src/Surging.Core/Surging.Core.Consul/ConsulServiceSubscribeManager.cs index 4d1a023f7..3640e4a5e 100644 --- a/src/Surging.Core/Surging.Core.Consul/ConsulServiceSubscribeManager.cs +++ b/src/Surging.Core/Surging.Core.Consul/ConsulServiceSubscribeManager.cs @@ -1,6 +1,7 @@ using Consul; using Microsoft.Extensions.Logging; using Surging.Core.Consul.Configurations; +using Surging.Core.Consul.Internal; using Surging.Core.Consul.Utilitys; using Surging.Core.Consul.WatcherProvider; using Surging.Core.CPlatform.Runtime.Client; @@ -14,20 +15,20 @@ namespace Surging.Core.Consul { - public class ConsulServiceSubscribeManager: ServiceSubscribeManagerBase, IDisposable -{ - private readonly ConsulClient _consul; + public class ConsulServiceSubscribeManager : ServiceSubscribeManagerBase, IDisposable + { private readonly ConfigInfo _configInfo; private readonly ISerializer _serializer; private readonly IServiceSubscriberFactory _serviceSubscriberFactory; private readonly ILogger _logger; private readonly ISerializer _stringSerializer; private readonly IClientWatchManager _manager; + private readonly IConsulClientProvider _consulClientFactory; private ServiceSubscriber[] _subscribers; public ConsulServiceSubscribeManager(ConfigInfo configInfo, ISerializer serializer, ISerializer stringSerializer, IClientWatchManager manager, IServiceSubscriberFactory serviceSubscriberFactory, - ILogger logger):base(stringSerializer) + ILogger logger, IConsulClientProvider consulClientFactory) : base(stringSerializer) { _configInfo = configInfo; _serializer = serializer; @@ -35,10 +36,7 @@ public ConsulServiceSubscribeManager(ConfigInfo configInfo, ISerializer _serviceSubscriberFactory = serviceSubscriberFactory; _logger = logger; _manager = manager; - _consul = new ConsulClient(config => - { - config.Address = new Uri($"http://{configInfo.Host}:{configInfo.Port}"); - },null, h => { h.UseProxy = false; h.Proxy = null; }); + _consulClientFactory = consulClientFactory; EnterSubscribers().Wait(); } @@ -54,46 +52,55 @@ public override async Task> GetSubscribersAsync() public override async Task ClearAsync() { - var queryResult = await _consul.KV.List(_configInfo.SubscriberPath); - var response = queryResult.Response; - if (response != null) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - foreach (var result in response) + //根据前缀获取consul结果 + var queryResult = await client.KV.List(_configInfo.SubscriberPath); + var response = queryResult.Response; + if (response != null) { - await _consul.KV.DeleteCAS(result); + //删除操作 + foreach (var result in response) + { + await client.KV.DeleteCAS(result); + } } } } - + public void Dispose() { - _consul.Dispose(); } protected override async Task SetSubscribersAsync(IEnumerable subscribers) { subscribers = subscribers.ToArray(); - if (_subscribers != null) + var clients = await _consulClientFactory.GetClients(); + foreach (var client in clients) { - var oldSubscriberIds = _subscribers.Select(i => i.ServiceDescriptor.Id).ToArray(); - var newSubscriberIds = subscribers.Select(i => i.ServiceDescriptor.Id).ToArray(); - var deletedSubscriberIds = oldSubscriberIds.Except(newSubscriberIds).ToArray(); - foreach (var deletedSubscriberId in deletedSubscriberIds) + if (_subscribers != null) + { + var oldSubscriberIds = _subscribers.Select(i => i.ServiceDescriptor.Id).ToArray(); + var newSubscriberIds = subscribers.Select(i => i.ServiceDescriptor.Id).ToArray(); + var deletedSubscriberIds = oldSubscriberIds.Except(newSubscriberIds).ToArray(); + foreach (var deletedSubscriberId in deletedSubscriberIds) + { + await client.KV.Delete($"{_configInfo.SubscriberPath}{deletedSubscriberId}"); + } + } + foreach (var serviceSubscriber in subscribers) { - await _consul.KV.Delete($"{_configInfo.SubscriberPath}{deletedSubscriberId}"); + var nodeData = _serializer.Serialize(serviceSubscriber); + var keyValuePair = new KVPair($"{_configInfo.SubscriberPath}{serviceSubscriber.ServiceDescriptor.Id}") { Value = nodeData }; + await client.KV.Put(keyValuePair); } } - foreach (var serviceSubscriber in subscribers) - { - var nodeData = _serializer.Serialize(serviceSubscriber); - var keyValuePair = new KVPair($"{_configInfo.SubscriberPath}{serviceSubscriber.ServiceDescriptor.Id}") { Value = nodeData }; - await _consul.KV.Put(keyValuePair); - } } public override async Task SetSubscribersAsync(IEnumerable subscribers) { - var serviceSubscribers = await GetSubscribers(subscribers.Select(p =>$"{ _configInfo.SubscriberPath }{ p.ServiceDescriptor.Id}")); + var serviceSubscribers = await GetSubscribers(subscribers.Select(p => $"{ _configInfo.SubscriberPath }{ p.ServiceDescriptor.Id}")); if (serviceSubscribers.Count() > 0) { foreach (var subscriber in subscribers) @@ -122,14 +129,14 @@ private async Task GetSubscriber(byte[] data) } private async Task EnterSubscribers() - { + { if (_subscribers != null) return; - if (_consul.KV.Keys(_configInfo.SubscriberPath).Result.Response?.Count() > 0) + var client = await _consulClientFactory.GetClient(); + if (client.KV.Keys(_configInfo.SubscriberPath).Result.Response?.Count() > 0) { - var result = await _consul.GetChildrenAsync(_configInfo.SubscriberPath); - var keys = await _consul.KV.Keys(_configInfo.SubscriberPath); - var childrens = result; + var result = await client.GetChildrenAsync(_configInfo.SubscriberPath); + var keys = await client.KV.Keys(_configInfo.SubscriberPath); _subscribers = await GetSubscribers(keys.Response); } else @@ -143,10 +150,11 @@ private async Task EnterSubscribers() private async Task GetSubscriber(string path) { ServiceSubscriber result = null; - var queryResult = await _consul.KV.Keys(path); + var client = await _consulClientFactory.GetClient(); + var queryResult = await client.KV.Keys(path); if (queryResult.Response != null) { - var data = (await _consul.GetDataAsync(path)); + var data = (await client.GetDataAsync(path)); if (data != null) { result = await GetSubscriber(data); @@ -163,7 +171,7 @@ private async Task GetSubscribers(IEnumerable child { if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) _logger.LogDebug($"准备从节点:{children}中获取订阅者信息。"); - + var subscriber = await GetSubscriber(children); if (subscriber != null) subscribers.Add(subscriber); diff --git a/src/Surging.Core/Surging.Core.Consul/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Consul/ContainerBuilderExtensions.cs index 6e586e4f2..4de155127 100644 --- a/src/Surging.Core/Surging.Core.Consul/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.Consul/ContainerBuilderExtensions.cs @@ -12,6 +12,15 @@ using Surging.Core.CPlatform.Serialization; using System; using Microsoft.Extensions.Configuration; +using Surging.Core.CPlatform.Mqtt; +using Surging.Core.Consul.Internal; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation; +using Surging.Core.CPlatform.Module; +using Surging.Core.Consul.Internal.Implementation; +using Surging.Core.Consul.Internal.Cluster.HealthChecks; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors; +using Autofac; +using Surging.Core.Consul.Internal.Cluster.HealthChecks.Implementation; namespace Surging.Core.Consul { @@ -21,54 +30,73 @@ public static class ContainerBuilderExtensions /// 设置服务路由管理者。 /// /// Rpc服务构建者。 - /// ZooKeeper设置信息。 + /// Consul设置信息。 /// 服务构建者。 public static IServiceBuilder UseConsulRouteManager(this IServiceBuilder builder, ConfigInfo configInfo) { return builder.UseRouteManager(provider => new ConsulServiceRouteManager( - GetConfigInfo(configInfo), - provider.GetRequiredService>(), + GetConfigInfo(configInfo), + provider.GetRequiredService>(), provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>())); + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService())); } public static IServiceBuilder UseConsulCacheManager(this IServiceBuilder builder, ConfigInfo configInfo) { return builder.UseCacheManager(provider => new ConsulServiceCacheManager( - GetConfigInfo(configInfo), - provider.GetRequiredService>(), + GetConfigInfo(configInfo), + provider.GetRequiredService>(), provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>())); + provider.GetRequiredService>(), + provider.GetRequiredService())); } /// /// 设置服务命令管理者。 /// /// Rpc服务构建者。 - /// ZooKeeper设置信息。 + /// Consul设置信息。 /// 服务构建者。 public static IServiceBuilder UseConsulCommandManager(this IServiceBuilder builder, ConfigInfo configInfo) { return builder.UseCommandManager(provider => { var result = new ConsulServiceCommandManager( - GetConfigInfo(configInfo), - provider.GetRequiredService>(), + GetConfigInfo(configInfo), + provider.GetRequiredService>(), provider.GetRequiredService>(), - provider.GetRequiredService (), + provider.GetRequiredService(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>()); + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService()); return result; }); } + public static IServiceBuilder UseConsulMqttRouteManager(this IServiceBuilder builder, ConfigInfo configInfo) + { + return builder.UseMqttRouteManager(provider => + new ConsulMqttServiceRouteManager( + GetConfigInfo(configInfo), + provider.GetRequiredService>(), + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService(), + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService())); + } + public static IServiceBuilder UseConsulServiceSubscribeManager(this IServiceBuilder builder, ConfigInfo configInfo) { return builder.UseSubscribeManager(provider => @@ -79,7 +107,8 @@ public static IServiceBuilder UseConsulServiceSubscribeManager(this IServiceBuil provider.GetRequiredService>(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService>()); + provider.GetRequiredService>(), + provider.GetRequiredService()); return result; }); } @@ -93,18 +122,47 @@ public static IServiceBuilder UseConsulWatch(this IServiceBuilder builder, Confi { builder.Services.Register(provider => { - return new ClientWatchManager(configInfo); + return new ClientWatchManager(provider.Resolve>(), configInfo); }).As().SingleInstance(); return builder; } + public static IServiceBuilder UseConsulAddressSelector(this IServiceBuilder builder) + { + builder.Services.RegisterType().As().SingleInstance(); + return builder; + } + + public static IServiceBuilder UseHealthCheck(this IServiceBuilder builder) + { + builder.Services.RegisterType().As().SingleInstance(); + return builder; + } + + + public static IServiceBuilder UseCounlClientProvider(this IServiceBuilder builder, ConfigInfo configInfo) + { + builder.Services.Register(provider => + new DefaultConsulClientProvider( + GetConfigInfo(configInfo), + provider.Resolve(), + provider.Resolve(), + provider.Resolve>())).As().SingleInstance(); + return builder; + } + [Obsolete] public static IServiceBuilder UseConsulManager(this IServiceBuilder builder, ConfigInfo configInfo) { return builder.UseConsulRouteManager(configInfo) + .UseHealthCheck() .UseConsulServiceSubscribeManager(configInfo) - .UseConsulCommandManager(configInfo) - .UseConsulCacheManager(configInfo).UseConsulWatch(configInfo); + .UseConsulCommandManager(configInfo) + .UseConsulCacheManager(configInfo) + .UseCounlClientProvider(configInfo) + .UseConsulAddressSelector() + .UseConsulWatch(configInfo) + .UseConsulMqttRouteManager(configInfo); } [Obsolete] @@ -112,9 +170,13 @@ public static IServiceBuilder UseConsulManager(this IServiceBuilder builder) { var configInfo = new ConfigInfo(null); return builder.UseConsulRouteManager(configInfo) + .UseHealthCheck() .UseConsulServiceSubscribeManager(configInfo) - .UseConsulCommandManager(configInfo) - .UseConsulCacheManager(configInfo).UseConsulWatch(configInfo); + .UseConsulCommandManager(configInfo) + .UseCounlClientProvider(configInfo) + .UseConsulAddressSelector() + .UseConsulCacheManager(configInfo).UseConsulWatch(configInfo) + .UseConsulMqttRouteManager(configInfo); } @@ -124,20 +186,23 @@ private static ConfigInfo GetConfigInfo(ConfigInfo config) var section = CPlatform.AppConfig.GetSection("Consul"); if (section.Exists()) option = section.Get(); - else if(AppConfig.Configuration!=null) + else if (AppConfig.Configuration != null) option = AppConfig.Configuration.Get(); + if (option != null) { var sessionTimeout = config.SessionTimeout.TotalSeconds; Double.TryParse(option.SessionTimeout, out sessionTimeout); config = new ConfigInfo( - option.ConnectionString, + option.ConnectionString, TimeSpan.FromSeconds(sessionTimeout), + option.LockDelay ?? config.LockDelay, option.RoutePath ?? config.RoutePath, option.SubscriberPath ?? config.SubscriberPath, - option.CommandPath ?? config.CommandPath, + option.CommandPath ?? config.CommandPath, option.CachePath ?? config.CachePath, - option.ReloadOnChange != null ? bool.Parse(option.ReloadOnChange) : + option.MqttRoutePath ?? config.MqttRoutePath, + option.ReloadOnChange != null ? bool.Parse(option.ReloadOnChange) : config.ReloadOnChange, option.EnableChildrenMonitor != null ? bool.Parse(option.EnableChildrenMonitor) : config.EnableChildrenMonitor diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/HealthChecks/IHealthCheckService.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/HealthChecks/IHealthCheckService.cs new file mode 100644 index 000000000..5c0afbb1d --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/HealthChecks/IHealthCheckService.cs @@ -0,0 +1,15 @@ +using Surging.Core.CPlatform.Address; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Consul.Internal.Cluster.HealthChecks +{ + public interface IHealthCheckService + { + void Monitor(AddressModel address); + + ValueTask IsHealth(AddressModel address); + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/HealthChecks/Implementation/DefaultHealthCheckService.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/HealthChecks/Implementation/DefaultHealthCheckService.cs new file mode 100644 index 000000000..dec1fa714 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/HealthChecks/Implementation/DefaultHealthCheckService.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Address; + +namespace Surging.Core.Consul.Internal.Cluster.HealthChecks.Implementation +{ + public class DefaultHealthCheckService : IHealthCheckService,IDisposable + { + private readonly int _timeout = 30000; + private readonly Timer _timer; + private readonly ConcurrentDictionary, MonitorEntry> _dictionary = + new ConcurrentDictionary, MonitorEntry>(); + + #region Implementation of IHealthCheckService + public DefaultHealthCheckService() + { + var timeSpan = TimeSpan.FromSeconds(60); + + _timer = new Timer(async s => + { + await Check(_dictionary.ToArray().Select(i => i.Value), _timeout); + }, null, timeSpan, timeSpan); + } + + public async ValueTask IsHealth(AddressModel address) + { + var ipAddress = address as IpAddressModel; + MonitorEntry entry; + var isHealth = !_dictionary.TryGetValue(new ValueTuple(ipAddress.Ip, ipAddress.Port), out entry) ? await Check(address, _timeout) : entry.Health; + return isHealth; + } + + public void Monitor(AddressModel address) + { + var ipAddress = address as IpAddressModel; + _dictionary.GetOrAdd(new ValueTuple(ipAddress.Ip, ipAddress.Port), k => new MonitorEntry(address)); + } + + #region Implementation of IDisposable + + public void Dispose() + { + _timer.Dispose(); + } + #endregion + + #endregion Implementation of IDisposable + + #region Private Method + + private static async Task Check(AddressModel address, int timeout) + { + bool isHealth = false; + using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = timeout }) + { + try + { + await socket.ConnectAsync(address.CreateEndPoint()); + isHealth = true; + } + catch + { + + } + return isHealth; + } + } + + private static async Task Check(IEnumerable entrys, int timeout) + { + foreach (var entry in entrys) + { + using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { SendTimeout = timeout }) + { + try + { + await socket.ConnectAsync(entry.EndPoint); + entry.UnhealthyTimes = 0; + entry.Health = true; + } + catch + { + entry.UnhealthyTimes++; + entry.Health = false; + } + } + } + } + + #endregion Private Method + + #region Help Class + + protected class MonitorEntry + { + public MonitorEntry(AddressModel addressModel, bool health = true) + { + EndPoint = addressModel.CreateEndPoint(); + Health = health; + + } + + public int UnhealthyTimes { get; set; } + + public EndPoint EndPoint { get; set; } + public bool Health { get; set; } + } + + #endregion Help Class + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/IConsulAddressSelector.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/IConsulAddressSelector.cs new file mode 100644 index 000000000..ec3e06f1f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/IConsulAddressSelector.cs @@ -0,0 +1,13 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Consul.Internal.Cluster.Implementation.Selectors +{ + public interface IConsulAddressSelector : IAddressSelector + { + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/AddressSelectorMode.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/AddressSelectorMode.cs new file mode 100644 index 000000000..c80c81605 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/AddressSelectorMode.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation +{ + public enum AddressSelectorMode + { + Polling, + Random + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/ConsulAddressSelectorBase.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/ConsulAddressSelectorBase.cs new file mode 100644 index 000000000..9a28e2e1a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/ConsulAddressSelectorBase.cs @@ -0,0 +1,53 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation +{ + public abstract class ConsulAddressSelectorBase : IConsulAddressSelector + { + #region Implementation of IAddressSelector + + /// + /// 选择一个地址。 + /// + /// 地址选择上下文。 + /// 地址模型。 + async ValueTask IAddressSelector.SelectAsync(AddressSelectContext context) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + if (context.Descriptor == null) + throw new ArgumentNullException(nameof(context.Descriptor)); + if (context.Address == null) + throw new ArgumentNullException(nameof(context.Address)); + + // var address = context.Address.ToArray(); + if (context.Address.Count() == 0) + throw new ArgumentException("没有任何地址信息。", nameof(context.Address)); + + if (context.Address.Count() == 1) + { + return context.Address.First(); + } + else + { + var vt = SelectAsync(context); + return vt.IsCompletedSuccessfully ? vt.Result : await vt; + } + } + + #endregion Implementation of IAddressSelector + + /// + /// 选择一个地址。 + /// + /// 地址选择上下文。 + /// 地址模型。 + protected abstract ValueTask SelectAsync(AddressSelectContext context); + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/ConsulRandomAddressSelector.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/ConsulRandomAddressSelector.cs new file mode 100644 index 000000000..889d36760 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Cluster/Implementation/Selectors/Implementation/ConsulRandomAddressSelector.cs @@ -0,0 +1,62 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation +{ + public class ConsulRandomAddressSelector : ConsulAddressSelectorBase + { + #region Field + + private readonly Func _generate; + private readonly Random _random; + + #endregion Field + + #region Constructor + + /// + /// 初始化一个以Random生成随机数的随机地址选择器。 + /// + public ConsulRandomAddressSelector() + { + _random = new Random(); + _generate = (min, max) => _random.Next(min, max); + } + + /// + /// 初始化一个自定义的随机地址选择器。 + /// + /// 随机数生成委托,第一个参数为最小值,第二个参数为最大值(不可以超过该值)。 + public ConsulRandomAddressSelector(Func generate) + { + if (generate == null) + throw new ArgumentNullException(nameof(generate)); + _generate = generate; + } + + #endregion Constructor + + #region Overrides of AddressSelectorBase + + /// + /// 选择一个地址。 + /// + /// 地址选择上下文。 + /// 地址模型。 + protected override ValueTask SelectAsync(AddressSelectContext context) + { + var address = context.Address.ToArray(); + var length = address.Length; + + var index = _generate(0, length); + return new ValueTask(address[index]); + } + + #endregion Overrides of AddressSelectorBase + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/IConsulClientProvider.cs b/src/Surging.Core/Surging.Core.Consul/Internal/IConsulClientProvider.cs new file mode 100644 index 000000000..6318ee88a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/IConsulClientProvider.cs @@ -0,0 +1,18 @@ +using Consul; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Consul.Internal +{ + public interface IConsulClientProvider + { + ValueTask GetClient(); + + ValueTask> GetClients(); + + ValueTask Check(); + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Internal/Implementation/DefaultConsulClientProvider.cs b/src/Surging.Core/Surging.Core.Consul/Internal/Implementation/DefaultConsulClientProvider.cs new file mode 100644 index 000000000..d2bd7eb71 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Consul/Internal/Implementation/DefaultConsulClientProvider.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Consul; +using Microsoft.Extensions.Logging; +using Surging.Core.Consul.Configurations; +using Surging.Core.Consul.Internal.Cluster.HealthChecks; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors; +using Surging.Core.Consul.Internal.Cluster.Implementation.Selectors.Implementation; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Exceptions; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors; +using Level = Microsoft.Extensions.Logging.LogLevel; + +namespace Surging.Core.Consul.Internal.Implementation +{ + public class DefaultConsulClientProvider : IConsulClientProvider + { + private ConfigInfo _config; + private readonly IHealthCheckService _healthCheckService; + private readonly IConsulAddressSelector _consulAddressSelector; + private readonly ILogger _logger; + private readonly ConcurrentDictionary _addressSelectors = new + ConcurrentDictionary(); + private readonly ConcurrentDictionary _consulClients = new + ConcurrentDictionary(); + + public DefaultConsulClientProvider(ConfigInfo config, IHealthCheckService healthCheckService, IConsulAddressSelector consulAddressSelector, + ILogger logger) + { + _config = config; + _healthCheckService = healthCheckService; + _consulAddressSelector = consulAddressSelector; + _logger = logger; + } + + public async ValueTask GetClient() + { + ConsulClient result = null; + var address = new List(); + foreach (var addressModel in _config.Addresses) + { + _healthCheckService.Monitor(addressModel); + var task = _healthCheckService.IsHealth(addressModel); + if (!(task.IsCompletedSuccessfully ? task.Result : await task)) + { + continue; + } + address.Add(addressModel); + } + if (address.Count == 0) + { + if (_logger.IsEnabled(Level.Warning)) + _logger.LogWarning($"找不到可用的注册中心地址。"); + return null; + } + + var vt = _consulAddressSelector.SelectAsync(new AddressSelectContext + { + Descriptor = new ServiceDescriptor { Id = nameof(DefaultConsulClientProvider) }, + Address = address + }); + var addr = vt.IsCompletedSuccessfully ? vt.Result : await vt; + if (addr != null) + { + var ipAddress = addr as IpAddressModel; + result = _consulClients.GetOrAdd(ipAddress, new ConsulClient(config => + { + config.Address = new Uri($"http://{ipAddress.Ip}:{ipAddress.Port}"); + }, null, h => { h.UseProxy = false; h.Proxy = null; })); + } + return result; + } + + public async ValueTask> GetClients() + { + var result = new List(); + foreach (var address in _config.Addresses) + { + var ipAddress = address as IpAddressModel; + if (await _healthCheckService.IsHealth(address)) + { + result.Add(_consulClients.GetOrAdd(ipAddress, new ConsulClient(config => + { + config.Address = new Uri($"http://{ipAddress.Ip}:{ipAddress.Port}"); + }, null, h => { h.UseProxy = false; h.Proxy = null; }))); + + } + } + return result; + } + + public async ValueTask Check() + { + foreach (var address in _config.Addresses) + { + if (!await _healthCheckService.IsHealth(address)) + { + throw new RegisterConnectionException(string.Format("注册中心{0}连接异常,请联系管理员", address.ToString())); + } + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Consul/Surging.Core.Consul.csproj b/src/Surging.Core/Surging.Core.Consul/Surging.Core.Consul.csproj index a8734a0b5..d9fc55559 100644 --- a/src/Surging.Core/Surging.Core.Consul/Surging.Core.Consul.csproj +++ b/src/Surging.Core/Surging.Core.Consul/Surging.Core.Consul.csproj @@ -1,34 +1,25 @@ - + - netcoreapp2.1 + net6.0 fanly - 0.8.0.1 + 1.1.0.0 surging Micro Service Framework Copyright © fanly All Rights Reserved - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component + 1.multiple register center cluster +2. fix bug surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 0.8.0.1 - 0.8.0.1 + 1.1.0.0 + 1.1.0.0 + 7.1 - + diff --git a/src/Surging.Core/Surging.Core.Consul/Utilitys/ConsulClientExtensions.cs b/src/Surging.Core/Surging.Core.Consul/Utilitys/ConsulClientExtensions.cs index 3ecdf27ad..1ccbe7502 100644 --- a/src/Surging.Core/Surging.Core.Consul/Utilitys/ConsulClientExtensions.cs +++ b/src/Surging.Core/Surging.Core.Consul/Utilitys/ConsulClientExtensions.cs @@ -5,6 +5,7 @@ using System.Text; using System.Net.Http; using System.Net.Http.Headers; +using System.Collections.Generic; namespace Surging.Core.Consul.Utilitys { @@ -23,6 +24,19 @@ public static async Task GetChildrenAsync(this ConsulClient client, st } } + public static async Task> GetChildrenListAsync(this ConsulClient client, string path) + { + try + { + var queryResult = await client.KV.List(path); + return queryResult.Response?.Select(p => p.Value).ToList(); + } + catch (HttpRequestException) + { + return null; + } + } + public static async Task GetDataAsync(this ConsulClient client, string path) { try diff --git a/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ChildrenMonitorWatcher.cs b/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ChildrenMonitorWatcher.cs index 8e99fc2d4..b723bd5df 100644 --- a/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ChildrenMonitorWatcher.cs +++ b/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ChildrenMonitorWatcher.cs @@ -10,17 +10,17 @@ namespace Surging.Core.Consul.WatcherProvider public class ChildrenMonitorWatcher : WatcherBase { private readonly Action _action; - private readonly IClientWatchManager _manager; - private readonly ConsulClient _client; + private readonly IClientWatchManager _manager; private readonly string _path; private readonly Func _func; private string[] _currentData = new string[0]; - public ChildrenMonitorWatcher(ConsulClient client, IClientWatchManager manager, string path, + private readonly Func> _clientCall; + public ChildrenMonitorWatcher(Func> clientCall, IClientWatchManager manager, string path, Action action, Func func) { this._action = action; _manager = manager; - _client = client; + _clientCall = clientCall; _path = path; _func = func; RegisterWatch(); @@ -35,7 +35,8 @@ public ChildrenMonitorWatcher SetCurrentData(string[] currentData) protected override async Task ProcessImpl() { RegisterWatch(this); - var result = await _client.GetChildrenAsync(_path); + var client =await _clientCall(); + var result = await client.GetChildrenAsync(_path); if (result != null) { var convertResult = _func.Invoke(result).Select(key => $"{_path}{key}").ToArray(); diff --git a/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ClientWatchManager.cs b/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ClientWatchManager.cs index 31564e49a..6558af233 100644 --- a/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ClientWatchManager.cs +++ b/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/ClientWatchManager.cs @@ -1,4 +1,5 @@ using Consul; +using Microsoft.Extensions.Logging; using Surging.Core.Consul.Configurations; using Surging.Core.Consul.Utilitys; using System; @@ -7,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace Surging.Core.Consul.WatcherProvider.Implementation { @@ -15,10 +17,12 @@ public class ClientWatchManager : IClientWatchManager internal Dictionary> dataWatches = new Dictionary>(); private readonly Timer _timer; + private readonly ILogger _logger; - public ClientWatchManager(ConfigInfo config) + public ClientWatchManager(ILogger logger,ConfigInfo config) { var timeSpan = TimeSpan.FromSeconds(config.WatchInterval); + _logger = logger; _timer = new Timer(async s => { await Watching(); @@ -50,10 +54,18 @@ private HashSet Materialize() private async Task Watching() { - var watches = Materialize(); - foreach (var watch in watches) + try { - await watch.Process(); + var watches = Materialize(); + foreach (var watch in watches) + { + await watch.Process(); + } + } + catch (Exception ex) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"message:{ex.Message},Source:{ex.Source},Trace:{ex.StackTrace}"); } } } diff --git a/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/NodeMonitorWatcher.cs b/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/NodeMonitorWatcher.cs index f4ea43d54..a4d835eb2 100644 --- a/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/NodeMonitorWatcher.cs +++ b/src/Surging.Core/Surging.Core.Consul/WatcherProvider/Implementation/NodeMonitorWatcher.cs @@ -11,15 +11,18 @@ class NodeMonitorWatcher : WatcherBase { private readonly Action _action; private readonly IClientWatchManager _manager; - private readonly ConsulClient _client; + private readonly Func> _clientCall; private readonly string _path; private byte[] _currentData = new byte[0]; - public NodeMonitorWatcher(ConsulClient client, IClientWatchManager manager, string path, Action action) + Func _allowChange; + public NodeMonitorWatcher(Func> clientCall, IClientWatchManager manager, string path, + Action action,Func allowChange) { this._action = action; _manager = manager; - _client = client; + _clientCall = clientCall; _path = path; + _allowChange = allowChange; RegisterWatch(); } @@ -32,7 +35,9 @@ public NodeMonitorWatcher SetCurrentData(byte[] currentData) protected override async Task ProcessImpl() { RegisterWatch(this); - var result = await _client.GetDataAsync(_path); + if (_allowChange!=null&&! _allowChange(_path)) return; + var client = await _clientCall(); + var result =await client.GetDataAsync(_path); if (result != null) { _action(_currentData, result); diff --git a/src/Surging.Core/Surging.Core.DNS/AppConfig.cs b/src/Surging.Core/Surging.Core.DNS/AppConfig.cs new file mode 100644 index 000000000..58dc00600 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/AppConfig.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.Configuration; +using Surging.Core.DNS.Configurations; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DNS +{ + public static class AppConfig + { + public static IConfigurationRoot Configuration { get; set; } + + public static DnsOption DnsOption { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Configurations/DnsOption.cs b/src/Surging.Core/Surging.Core.DNS/Configurations/DnsOption.cs new file mode 100644 index 000000000..aeebb9eb9 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Configurations/DnsOption.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DNS.Configurations +{ + public class DnsOption + { + public string RootDnsAddress { get; set; } + + public int QueryTimeout { get; set; } = 1000; + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationExtensions.cs b/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationExtensions.cs new file mode 100644 index 000000000..fe4a4dd94 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationExtensions.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.FileProviders; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Surging.Core.DNS.Configurations +{ + public static class EventBusConfigurationExtensions + { + public static IConfigurationBuilder AddDnsFile(this IConfigurationBuilder builder, string path) + { + return AddDnsFile(builder, provider: null, path: path, basePath: null, optional: false, reloadOnChange: false); + } + + public static IConfigurationBuilder AddDnsFile(this IConfigurationBuilder builder, string path, bool optional) + { + return AddDnsFile(builder, provider: null, path: path, basePath: null, optional: optional, reloadOnChange: false); + } + + public static IConfigurationBuilder AddDnsFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) + { + return AddDnsFile(builder, provider: null, path: path, basePath: null, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddDnsFile(this IConfigurationBuilder builder, string path, string basePath, bool optional, bool reloadOnChange) + { + return AddDnsFile(builder, provider: null, path: path, basePath: basePath, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddDnsFile(this IConfigurationBuilder builder, IFileProvider provider, string path, string basePath, bool optional, bool reloadOnChange) + { + Check.NotNull(builder, "builder"); + Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); + if (provider == null && Path.IsPathRooted(path)) + { + provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); + path = Path.GetFileName(path); + } + + var source = new EventBusConfigurationSource + { + FileProvider = provider, + Path = path, + Optional = optional, + ReloadOnChange = reloadOnChange + }; + builder.Add(source); + if (!string.IsNullOrEmpty(basePath)) + builder.SetBasePath(basePath); + AppConfig.Configuration = builder.Build(); + AppConfig.DnsOption = AppConfig.Configuration.Get(); + return builder; + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationProvider.cs b/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationProvider.cs new file mode 100644 index 000000000..40dfdf54e --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationProvider.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.Configuration; +using Surging.Core.CPlatform.Configurations.Remote; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Surging.Core.DNS.Configurations +{ + public class EventBusConfigurationProvider : FileConfigurationProvider + { + public EventBusConfigurationProvider(EventBusConfigurationSource source) : base(source) { } + + public override void Load(Stream stream) + { + var parser = new JsonConfigurationParser(); + this.Data = parser.Parse(stream, null); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationSource.cs b/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationSource.cs new file mode 100644 index 000000000..3a09f88e7 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Configurations/EventBusConfigurationSource.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DNS.Configurations +{ + public class EventBusConfigurationSource : FileConfigurationSource + { + public string ConfigurationKeyPrefix { get; set; } + + public override IConfigurationProvider Build(IConfigurationBuilder builder) + { + FileProvider = FileProvider ?? builder.GetFileProvider(); + return new EventBusConfigurationProvider(this); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/DnsProtocolModule.cs b/src/Surging.Core/Surging.Core.DNS/DnsProtocolModule.cs new file mode 100644 index 000000000..a5b540854 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/DnsProtocolModule.cs @@ -0,0 +1,95 @@ +using Autofac; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.DNS.Configurations; +using Surging.Core.DNS.Runtime; +using Surging.Core.DNS.Runtime.Implementation; + +namespace Surging.Core.DNS +{ + public class DnsProtocolModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + var section = CPlatform.AppConfig.GetSection("Dns"); + if (section.Exists()) + AppConfig.DnsOption = section.Get(); + builder.Register(provider => + { + return new DefaultDnsServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(IDnsServiceEntryProvider)).SingleInstance(); + builder.RegisterType(typeof(DnsServiceExecutor)).As(typeof(IServiceExecutor)) + .Named(CommunicationProtocol.Dns.ToString()).SingleInstance(); + if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.Dns) + { + RegisterDefaultProtocol(builder); + } + else if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterDnsProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DotNettyDnsServerMessageListener(provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var serviceExecutor = provider.ResolveKeyed(CommunicationProtocol.Dns.ToString()); + var messageListener = provider.Resolve(); + return new DnsServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, serviceExecutor); + + }).As(); + } + + private static void RegisterDnsProtocol(ContainerBuilderWrapper builder) + { + + builder.Register(provider => + { + return new DotNettyDnsServerMessageListener(provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var serviceExecutor = provider.ResolveKeyed(CommunicationProtocol.Dns.ToString()); + var messageListener = provider.Resolve(); + return new DnsServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, serviceExecutor); + + }).As(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/DnsServiceExecutor.cs b/src/Surging.Core/Surging.Core.DNS/DnsServiceExecutor.cs new file mode 100644 index 000000000..7ab391152 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/DnsServiceExecutor.cs @@ -0,0 +1,113 @@ +using DotNetty.Codecs.DNS; +using DotNetty.Codecs.DNS.Records; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Transport; +using Surging.Core.DNS.Extensions; +using Surging.Core.DNS.Runtime; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DNS +{ + public class DnsServiceExecutor : IServiceExecutor + { + #region Field + + private readonly IDnsServiceEntryProvider _dnsServiceEntryProvider; + private readonly ILogger _logger; + + #endregion Field + + #region Constructor + + public DnsServiceExecutor(IDnsServiceEntryProvider dnsServiceEntryProvider, + ILogger logger) + { + _dnsServiceEntryProvider = dnsServiceEntryProvider; + _logger = logger; + } + + #endregion Constructor + + #region Implementation of IServiceExecutor + + /// + /// 执行。 + /// + /// 消息发送者。 + /// 调用消息。 + public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) + { + if (_logger.IsEnabled(LogLevel.Trace)) + _logger.LogTrace("服务提供者接收到消息。"); + + if (!message.IsDnsResultMessage()) + return; + DnsTransportMessage dnsTransportMessage; + try + { + dnsTransportMessage = message.GetContent(); + } + catch (Exception exception) + { + _logger.LogError(exception, "将接收到的消息反序列化成 TransportMessage 时发送了错误。"); + return; + } + var entry = _dnsServiceEntryProvider.GetEntry(); + if (entry == null) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"未实现DnsBehavior实例。"); + return; + } + + await LocalExecuteAsync(entry, dnsTransportMessage); + await SendRemoteInvokeResult(sender, dnsTransportMessage); + } + + #endregion Implementation of IServiceExecutor + + #region Private Method + + + private async Task LocalExecuteAsync(DnsServiceEntry entry, DnsTransportMessage message) + { + HttpResultMessage resultMessage = new HttpResultMessage(); + try + { + var dnsQuestion = message.DnsQuestion; + message.Address= await entry.Behavior.DomainResolve(dnsQuestion.Name); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "执行本地逻辑时候发生了错误。"); + } + return message; + } + + private async Task SendRemoteInvokeResult(IMessageSender sender, DnsTransportMessage resultMessage) + { + try + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("准备发送响应消息。"); + + await sender.SendAndFlushAsync(new TransportMessage(resultMessage)); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("响应消息发送成功。"); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "发送响应消息时候发生了异常。"); + } + } + + #endregion Private Method + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/DnsServiceHost.cs b/src/Surging.Core/Surging.Core.DNS/DnsServiceHost.cs new file mode 100644 index 000000000..3d81547af --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/DnsServiceHost.cs @@ -0,0 +1,64 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DNS +{ + public class DnsServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public DnsServiceHost(Func> messageListenerFactory, IServiceExecutor serviceExecutor) : base(serviceExecutor) + { + _messageListenerFactory = messageListenerFactory; + } + + #region Overrides of ServiceHostAbstract + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(endPoint); + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + public override async Task StartAsync(string ip, int port) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip),53)); + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + #endregion Overrides of ServiceHostAbstract + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/DnsTransportMessage.cs b/src/Surging.Core/Surging.Core.DNS/DnsTransportMessage.cs new file mode 100644 index 000000000..0a95cab7c --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/DnsTransportMessage.cs @@ -0,0 +1,18 @@ +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Codecs.DNS.Records; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Surging.Core.DNS +{ + public class DnsTransportMessage + { + public IDnsResponse DnsResponse { get; set; } + + public IDnsQuestion DnsQuestion { get; set; } + + public IPAddress Address { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/DotNettyDnsServerMessageListener.cs b/src/Surging.Core/Surging.Core.DNS/DotNettyDnsServerMessageListener.cs new file mode 100644 index 000000000..5f189b6ed --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/DotNettyDnsServerMessageListener.cs @@ -0,0 +1,145 @@ +using ARSoft.Tools.Net; +using ARSoft.Tools.Net.Dns; +using DotNetty.Buffers; +using DotNetty.Codecs; +using DotNetty.Codecs.DNS; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Codecs.DNS.Records; +using DotNetty.Transport.Bootstrapping; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Sockets; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Codec; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DNS +{ + class DotNettyDnsServerMessageListener : IMessageListener, IDisposable + { + #region Field + + private readonly ILogger _logger; + private readonly ITransportMessageDecoder _transportMessageDecoder; + private readonly ITransportMessageEncoder _transportMessageEncoder; + private IChannel _channel; + + public event ReceivedDelegate Received; + + #endregion Field + + #region Constructor + + public DotNettyDnsServerMessageListener(ILogger logger, ITransportMessageCodecFactory codecFactory) + { + _logger = logger; + _transportMessageEncoder = codecFactory.GetEncoder(); + _transportMessageDecoder = codecFactory.GetDecoder(); + } + + #endregion Constructor + + public async Task StartAsync(EndPoint endPoint) + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); + + var group = new MultithreadEventLoopGroup(); + var bootstrap = new Bootstrap(); + bootstrap + .Group(group) + .Channel() + .Handler(new ActionChannelInitializer(channel => + { + IChannelPipeline pipeline = channel.Pipeline; + pipeline.AddLast(new DatagramDnsQueryDecoder()); + pipeline.AddLast(new DatagramDnsResponseEncoder()); + pipeline.AddLast(new ServerHandler(async (contenxt, message) => + { + var sender = new DotNettyDnsServerMessageSender(_transportMessageEncoder, contenxt); + await OnReceived(sender, message); + }, _logger)); + })).Option(ChannelOption.SoBroadcast, true); + try + { + + _channel = await bootstrap.BindAsync(endPoint); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"DNS服务主机启动成功,监听地址:{endPoint}。"); + } + catch + { + _logger.LogError($"DNS服务主机启动失败,监听地址:{endPoint}。 "); + } + + } + + public void CloseAsync() + { + Task.Run(async () => + { + await _channel.EventLoop.ShutdownGracefullyAsync(); + await _channel.CloseAsync(); + }).Wait(); + } + + #region Implementation of IDisposable + + + public void Dispose() + { + Task.Run(async () => + { + await _channel.DisconnectAsync(); + }).Wait(); + } + + public async Task OnReceived(IMessageSender sender, TransportMessage message) + { + if (Received == null) + return; + await Received(sender, message); + } + + #endregion Implementation of IDisposable + + private class ServerHandler : SimpleChannelInboundHandler + { + + private readonly Action _readAction; + private readonly ILogger _logger; + + public ServerHandler(Action readAction, ILogger logger) + { + _readAction = readAction; + _logger = logger; + } + + protected override void ChannelRead0(IChannelHandlerContext ctx, DatagramDnsQuery query) + { + + DatagramDnsResponse response = new DatagramDnsResponse(query.Recipient, query.Sender, query.Id); + DefaultDnsQuestion dnsQuestion = query.GetRecord(DnsSection.QUESTION); + response.AddRecord(DnsSection.QUESTION, dnsQuestion); + _readAction(ctx, new TransportMessage(new DnsTransportMessage + { + DnsResponse = response, + DnsQuestion = dnsQuestion + })); + } + + public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) + { + context.CloseAsync(); + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, $"与服务器:{context.Channel.RemoteAddress}通信时发送了错误。"); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/DotNettyDnsServerMessageSender.cs b/src/Surging.Core/Surging.Core.DNS/DotNettyDnsServerMessageSender.cs new file mode 100644 index 000000000..243c0dcb9 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/DotNettyDnsServerMessageSender.cs @@ -0,0 +1,110 @@ +using System.Net; +using System.Threading.Tasks; +using ARSoft.Tools.Net.Dns; +using DotNetty.Buffers; +using DotNetty.Codecs.DNS; +using DotNetty.Codecs.DNS.Messages; +using DotNetty.Codecs.DNS.Records; +using DotNetty.Transport.Channels; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.DNS.Extensions; +using Surging.Core.DNS.Utilities; +using Surging.Core.DotNetty; + +namespace Surging.Core.DNS +{ + class DotNettyDnsServerMessageSender : DotNettyMessageSender, IMessageSender + { + private readonly IChannelHandlerContext _context; + + public DotNettyDnsServerMessageSender(ITransportMessageEncoder transportMessageEncoder, IChannelHandlerContext context) : base(transportMessageEncoder) + { + _context = context; + } + + public async Task SendAndFlushAsync(TransportMessage message) + { + var response=await WriteResponse(message); + await _context.WriteAndFlushAsync(response); + } + + public async Task SendAsync(TransportMessage message) + { + var response = await WriteResponse(message); + await _context.WriteAsync(response); + } + + private IDnsResponse GetDnsResponse(TransportMessage message) + { + if (message.Content !=null && !message.IsDnsResultMessage()) + return null; + + var transportMessage = message.GetContent(); + return transportMessage.DnsResponse; + } + + private IDnsQuestion GetDnsQuestion(TransportMessage message) + { + if (message.Content != null && !message.IsDnsResultMessage()) + return null; + + var transportMessage = message.GetContent(); + return transportMessage.DnsQuestion; + } + + private IPAddress GetIpAddr(TransportMessage message) + { + if (message.Content != null && !message.IsDnsResultMessage()) + return null; + + var transportMessage = message.GetContent(); + return transportMessage.Address; + } + + private async Task WriteResponse(TransportMessage message) + { + var response = GetDnsResponse(message); + var dnsQuestion = GetDnsQuestion(message); + var ipAddr = GetIpAddr(message); + if (response != null && dnsQuestion != null) + { + if (ipAddr != null) + { + var buf = Unpooled.WrappedBuffer(ipAddr.GetAddressBytes()); + response.AddRecord(DnsSection.ANSWER, new DefaultDnsRawRecord(dnsQuestion.Name, DnsRecordType.A, 100, buf)); + } + else + { + var dnsMessage =await GetDnsMessage(dnsQuestion.Name, dnsQuestion.Type); + if (dnsMessage != null) + { + foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords) + { + var aRecord = dnsRecord as ARecord; + var buf = Unpooled.Buffer(); + if (dnsRecord.RecordType == RecordType.Ptr) + { + var ptrRecord = dnsRecord as PtrRecord; + response.AddRecord(DnsSection.ANSWER, new DefaultDnsPtrRecord(ptrRecord.Name.ToString(), (DnsRecordClass)(int)ptrRecord.RecordClass, ptrRecord.TimeToLive, ptrRecord.PointerDomainName.ToString())); + } + if (aRecord != null) + { + buf = Unpooled.WrappedBuffer(aRecord.Address.GetAddressBytes()); + response.AddRecord(DnsSection.ANSWER, new DefaultDnsRawRecord(dnsQuestion.Name, DnsRecordType.From((int)dnsRecord.RecordType), (DnsRecordClass)(int)aRecord.RecordClass, dnsRecord.TimeToLive, buf)); + } + } + } + } + } + return response; + } + + public async Task GetDnsMessage(string name, DnsRecordType recordType) + { + return await DnsClientProvider.Instance().Resolve(name, recordType); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Extensions/TransportMessageExtensions.cs b/src/Surging.Core/Surging.Core.DNS/Extensions/TransportMessageExtensions.cs new file mode 100644 index 000000000..6d07cdbab --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Extensions/TransportMessageExtensions.cs @@ -0,0 +1,16 @@ +using Surging.Core.CPlatform.Messages; +using System.Runtime.CompilerServices; + + +namespace Surging.Core.DNS.Extensions +{ + public static class TransportMessageExtensions + { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsDnsResultMessage(this TransportMessage message) + { + return message.ContentType == typeof(DnsTransportMessage).FullName; + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Runtime/DnsBehavior.cs b/src/Surging.Core/Surging.Core.DNS/Runtime/DnsBehavior.cs new file mode 100644 index 000000000..65a88ff15 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Runtime/DnsBehavior.cs @@ -0,0 +1,135 @@ +using Org.BouncyCastle.Asn1.Ocsp; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Net; +using Surging.Core.CPlatform.Utilities; +using ServiceLocator = Surging.Core.CPlatform.Utilities.ServiceLocator; +using Autofac; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.Module; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Messages; + +namespace Surging.Core.DNS.Runtime +{ + public abstract class DnsBehavior : IServiceBehavior + { + private ServerReceivedDelegate received; + public event ServerReceivedDelegate Received + { + add + { + if (received == null) + { + received += value; + } + } + remove + { + received -= value; + } + } + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await received(message); + } + public T CreateProxy(string key) where T : class + { + return ServiceLocator.GetService().CreateProxy(key); + } + + public object CreateProxy(Type type) + { + return ServiceLocator.GetService().CreateProxy(type); + } + + public object CreateProxy(string key, Type type) + { + return ServiceLocator.GetService().CreateProxy(key, type); + } + + public T CreateProxy() where T : class + { + return ServiceLocator.GetService().CreateProxy(); + } + + public T GetService(string key) where T : class + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return ServiceLocator.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public T GetService() where T : class + { + if (ServiceLocator.Current.IsRegistered()) + return ServiceLocator.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return ServiceLocator.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return ServiceLocator.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + public abstract Task Resolve(string domainName); + + + internal async Task DomainResolve(string domainName) + { + domainName = domainName.TrimEnd('.'); + var prefixLen = domainName.IndexOf("."); + IPAddress result = null; + if (prefixLen > 0) + { + var prefixName = domainName.Substring(0, prefixLen).ToString(); + var pathLen= domainName.LastIndexOf(".") - prefixLen - 1; + if (pathLen > 0) + { + var routePath = domainName.Substring(prefixLen + 1, pathLen).Replace(".", "/").ToString(); + if (routePath.IndexOf("/") < 0 && routePath[0] != '/') + routePath = $"/{routePath}"; + var address = await GetService().Locate(prefixName, routePath); + if (!string.IsNullOrEmpty(address.WanIp)) + result = IPAddress.Parse(address.WanIp); + } + } + result = await Resolve(domainName) ?? result; + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Runtime/DnsServiceEntry.cs b/src/Surging.Core/Surging.Core.DNS/Runtime/DnsServiceEntry.cs new file mode 100644 index 000000000..32ef644c3 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Runtime/DnsServiceEntry.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DNS.Runtime +{ + public class DnsServiceEntry + { + public string Path { get; set; } + + public Type Type { get; set; } + + public DnsBehavior Behavior { get; set; } + + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Runtime/IDnsServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.DNS/Runtime/IDnsServiceEntryProvider.cs new file mode 100644 index 000000000..8220b4ce2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Runtime/IDnsServiceEntryProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DNS.Runtime +{ + public interface IDnsServiceEntryProvider + { + DnsServiceEntry GetEntry(); + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Runtime/Implementation/DefaultDnsServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.DNS/Runtime/Implementation/DefaultDnsServiceEntryProvider.cs new file mode 100644 index 000000000..e9352fb5a --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Runtime/Implementation/DefaultDnsServiceEntryProvider.cs @@ -0,0 +1,87 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.DNS.Runtime.Implementation +{ + public class DefaultDnsServiceEntryProvider:IDnsServiceEntryProvider + { + #region Field + + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private DnsServiceEntry _dnsServiceEntry; + + #endregion Field + + #region Constructor + + public DefaultDnsServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of IServiceEntryProvider + + /// + /// 获取服务条目集合。 + /// + /// 服务条目集合。 + public DnsServiceEntry GetEntry() + { + var services = _types.ToArray(); + if (_dnsServiceEntry == null) + { + _dnsServiceEntry =new DnsServiceEntry(); + foreach (var service in services) + { + var entry = CreateServiceEntry(service); + if (entry != null) + { + _dnsServiceEntry = entry; + break; + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下dns服务:{_dnsServiceEntry.Type.FullName}。"); + } + } + return _dnsServiceEntry; + } + #endregion + + public DnsServiceEntry CreateServiceEntry(Type service) + { + DnsServiceEntry result = null; + var routeTemplate = service.GetCustomAttribute(); + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as DnsBehavior; + var path = RoutePatternParser.Parse(routeTemplate.RouteTemplate, service.Name); + if (path.Length > 0 && path[0] != '/') + path = $"/{path}"; + if (behavior != null) + result = new DnsServiceEntry + { + Behavior = behavior, + Type = behavior.GetType(), + Path = path, + }; + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.DNS/Surging.Core.DNS.csproj b/src/Surging.Core/Surging.Core.DNS/Surging.Core.DNS.csproj new file mode 100644 index 000000000..68f720fd8 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Surging.Core.DNS.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.DNS/Utilities/DnsClientProvider.cs b/src/Surging.Core/Surging.Core.DNS/Utilities/DnsClientProvider.cs new file mode 100644 index 000000000..953ef2156 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DNS/Utilities/DnsClientProvider.cs @@ -0,0 +1,29 @@ +using ARSoft.Tools.Net; +using ARSoft.Tools.Net.Dns; +using DotNetty.Codecs.DNS.Records; +using System.Net; +using System.Threading.Tasks; + +namespace Surging.Core.DNS.Utilities +{ + public class DnsClientProvider + { + public async Task Resolve(string name, DnsRecordType recordType , DnsRecordClass recordClass = DnsRecordClass.IN) + { + var dnsMessage =await GetDnsClient().ResolveAsync(DomainName.Parse(name), (RecordType)recordType.IntValue,(RecordClass)(int)recordClass); + return dnsMessage; + } + + public DnsClient GetDnsClient() + { + var dnsOption = AppConfig.DnsOption; + DnsClient dnsClient = new DnsClient(IPAddress.Parse(dnsOption.RootDnsAddress), dnsOption.QueryTimeout); + return dnsClient; + } + + public static DnsClientProvider Instance() + { + return new DnsClientProvider(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DotNetty/Adapter/TransportMessageChannelHandlerAdapter.cs b/src/Surging.Core/Surging.Core.DotNetty/Adapter/TransportMessageChannelHandlerAdapter.cs index 975f790a3..ae6b76c9c 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/Adapter/TransportMessageChannelHandlerAdapter.cs +++ b/src/Surging.Core/Surging.Core.DotNetty/Adapter/TransportMessageChannelHandlerAdapter.cs @@ -1,5 +1,4 @@ using DotNetty.Buffers; -using DotNetty.Codecs.Http; using DotNetty.Common.Utilities; using DotNetty.Transport.Channels; using Surging.Core.CPlatform.Transport.Codec; diff --git a/src/Surging.Core/Surging.Core.DotNetty/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.DotNetty/ContainerBuilderExtensions.cs index 580c01a9e..8f03a5574 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.DotNetty/ContainerBuilderExtensions.cs @@ -1,6 +1,7 @@ using Autofac; using Microsoft.Extensions.Logging; using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Runtime.Server.Implementation; using Surging.Core.CPlatform.Transport; @@ -28,7 +29,8 @@ public static IServiceBuilder UseDotNettyTransport(this IServiceBuilder builder) if (provider.IsRegistered(typeof(IServiceExecutor))) serviceExecutor = provider.Resolve(); return new DotNettyTransportClientFactory(provider.Resolve(), - provider.Resolve>(), + provider.Resolve(), + provider.Resolve>(), serviceExecutor); }).As(typeof(ITransportClientFactory)).SingleInstance(); if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.Tcp || diff --git a/src/Surging.Core/Surging.Core.DotNetty/DotNettyMessageSender.cs b/src/Surging.Core/Surging.Core.DotNetty/DotNettyMessageSender.cs index 731e8c7b5..1698fe71d 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/DotNettyMessageSender.cs +++ b/src/Surging.Core/Surging.Core.DotNetty/DotNettyMessageSender.cs @@ -8,7 +8,7 @@ namespace Surging.Core.DotNetty { - /// + /// /// 基于DotNetty的消息发送者基类。 /// public abstract class DotNettyMessageSender @@ -59,22 +59,23 @@ public void Dispose() /// 发送消息。 /// /// 消息内容。 - /// 一个任务。 + /// 一个任务。 public async Task SendAsync(TransportMessage message) { - var buffer = GetByteBuffer(message); + var buffer = GetByteBuffer(message); await _channel.WriteAndFlushAsync(buffer); + } /// /// 发送消息并清空缓冲区。 /// /// 消息内容。 - /// 一个任务。 + /// 一个任务。 public async Task SendAndFlushAsync(TransportMessage message) { - var buffer = GetByteBuffer(message); - await _channel.WriteAndFlushAsync(buffer); + var buffer = GetByteBuffer(message); + await _channel.WriteAndFlushAsync(buffer); } #endregion Implementation of IMessageSender @@ -98,24 +99,24 @@ public DotNettyServerMessageSender(ITransportMessageEncoder transportMessageEnco /// 发送消息。 /// /// 消息内容。 - /// 一个任务。 + /// 一个任务。 public async Task SendAsync(TransportMessage message) { - var buffer = GetByteBuffer(message); - await _context.WriteAsync(buffer); + var buffer = GetByteBuffer(message); + await _context.WriteAsync(buffer); } /// /// 发送消息并清空缓冲区。 /// /// 消息内容。 - /// 一个任务。 + /// 一个任务。 public async Task SendAndFlushAsync(TransportMessage message) { - var buffer = GetByteBuffer(message); + var buffer = GetByteBuffer(message); await _context.WriteAndFlushAsync(buffer); } #endregion Implementation of IMessageSender } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.DotNetty/DotNettyModule.cs b/src/Surging.Core/Surging.Core.DotNetty/DotNettyModule.cs index ebfcc0913..dd9b00d5f 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/DotNettyModule.cs +++ b/src/Surging.Core/Surging.Core.DotNetty/DotNettyModule.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using Surging.Core.CPlatform; using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Runtime.Server.Implementation; using Surging.Core.CPlatform.Transport; @@ -11,9 +12,9 @@ namespace Surging.Core.DotNetty { public class DotNettyModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } /// @@ -29,6 +30,7 @@ protected override void RegisterBuilder(ContainerBuilderWrapper builder) if (provider.IsRegistered(typeof(IServiceExecutor))) serviceExecutor = provider.Resolve(); return new DotNettyTransportClientFactory(provider.Resolve(), + provider.Resolve(), provider.Resolve>(), serviceExecutor); }).As(typeof(ITransportClientFactory)).SingleInstance(); diff --git a/src/Surging.Core/Surging.Core.DotNetty/DotNettyServerMessageListener.cs b/src/Surging.Core/Surging.Core.DotNetty/DotNettyServerMessageListener.cs index a2fbb1652..7e166393b 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/DotNettyServerMessageListener.cs +++ b/src/Surging.Core/Surging.Core.DotNetty/DotNettyServerMessageListener.cs @@ -3,7 +3,9 @@ using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; +using DotNetty.Transport.Libuv; using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; using Surging.Core.CPlatform.Messages; using Surging.Core.CPlatform.Transport; using Surging.Core.CPlatform.Transport.Codec; @@ -59,22 +61,36 @@ public async Task StartAsync(EndPoint endPoint) { if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); - - var bossGroup = new MultithreadEventLoopGroup(1); - var workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 + IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1); + IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 var bootstrap = new ServerBootstrap(); + IEventLoopGroup eventExecutor = new MultithreadEventLoopGroup(); + if (AppConfig.ServerOptions.Libuv) + { + var dispatcher = new DispatcherEventLoopGroup(); + bossGroup = dispatcher; + workerGroup = new WorkerEventLoopGroup(dispatcher); + var dispatcherExecutor = new DispatcherEventLoopGroup(); + eventExecutor = new WorkerEventLoopGroup(dispatcherExecutor); + bootstrap.Channel(); + } + else + { + bossGroup = new MultithreadEventLoopGroup(1); + workerGroup = new MultithreadEventLoopGroup(); + bootstrap.Channel(); + } bootstrap - .Group(bossGroup, workerGroup) - .Channel() - .Option(ChannelOption.SoBacklog, 100) + .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default) - .ChildHandler(new ActionChannelInitializer(channel => + .Group(bossGroup, workerGroup) + .ChildHandler(new ActionChannelInitializer(channel => { var pipeline = channel.Pipeline; pipeline.AddLast(new LengthFieldPrepender(4)); pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4)); - pipeline.AddLast(new TransportMessageChannelHandlerAdapter(_transportMessageDecoder)); - pipeline.AddLast(new ServerHandler(async (contenxt, message) => + pipeline.AddLast(eventExecutor, "HandlerAdapter", new TransportMessageChannelHandlerAdapter(_transportMessageDecoder)); + pipeline.AddLast(eventExecutor, "ServerHandler", new ServerHandler(async (contenxt, message) => { var sender = new DotNettyServerMessageSender(_transportMessageEncoder, contenxt); await OnReceived(sender, message); @@ -130,12 +146,9 @@ public ServerHandler(Action readAction #region Overrides of ChannelHandlerAdapter public override void ChannelRead(IChannelHandlerContext context, object message) - { - Task.Run(() => - { - var transportMessage = (TransportMessage)message; - _readAction(context, transportMessage); - }); + { + var transportMessage = (TransportMessage)message; + _readAction(context, transportMessage); } public override void ChannelReadComplete(IChannelHandlerContext context) @@ -155,4 +168,4 @@ public override void ExceptionCaught(IChannelHandlerContext context, Exception e #endregion Help Class } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.DotNetty/DotNettyTransportClientFactory.cs b/src/Surging.Core/Surging.Core.DotNetty/DotNettyTransportClientFactory.cs index 5d711b922..445cf69b2 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/DotNettyTransportClientFactory.cs +++ b/src/Surging.Core/Surging.Core.DotNetty/DotNettyTransportClientFactory.cs @@ -4,9 +4,12 @@ using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; +using DotNetty.Transport.Libuv; using Microsoft.Extensions.Logging; using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Address; using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Transport; using Surging.Core.CPlatform.Transport.Codec; @@ -18,6 +21,7 @@ using System.Linq; using System.Net; using System.Text; +using System.Threading.Tasks; namespace Surging.Core.DotNetty { @@ -32,7 +36,8 @@ public class DotNettyTransportClientFactory : ITransportClientFactory, IDisposab private readonly ITransportMessageDecoder _transportMessageDecoder; private readonly ILogger _logger; private readonly IServiceExecutor _serviceExecutor; - private readonly ConcurrentDictionary> _clients = new ConcurrentDictionary>(); + private readonly IHealthCheckService _healthCheckService; + private readonly ConcurrentDictionary>> _clients = new ConcurrentDictionary>>(); private readonly Bootstrap _bootstrap; private static readonly AttributeKey messageSenderKey = AttributeKey.ValueOf(typeof(DotNettyTransportClientFactory), nameof(IMessageSender)); @@ -43,16 +48,17 @@ public class DotNettyTransportClientFactory : ITransportClientFactory, IDisposab #region Constructor - public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory, ILogger logger) - : this(codecFactory, logger, null) + public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory, IHealthCheckService healthCheckService, ILogger logger) + : this(codecFactory, healthCheckService, logger, null) { } - public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory, ILogger logger, IServiceExecutor serviceExecutor) + public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory, IHealthCheckService healthCheckService, ILogger logger, IServiceExecutor serviceExecutor) { _transportMessageEncoder = codecFactory.GetEncoder(); _transportMessageDecoder = codecFactory.GetDecoder(); _logger = logger; + _healthCheckService = healthCheckService; _serviceExecutor = serviceExecutor; _bootstrap = GetBootstrap(); _bootstrap.Handler(new ActionChannelInitializer(c => @@ -74,31 +80,42 @@ public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory /// /// 终结点。 /// 传输客户端实例。 - public ITransportClient CreateClient(EndPoint endPoint) + public async Task CreateClientAsync(EndPoint endPoint) { var key = endPoint; if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"准备为服务端地址:{key}创建客户端。"); try { - return _clients.GetOrAdd(key - , k => new Lazy(() => + return await _clients.GetOrAdd(key + , k => new Lazy>(async () => { + //客户端对象 var bootstrap = _bootstrap; - var channel = bootstrap.ConnectAsync(k).Result; + //异步连接返回channel + var channel = await bootstrap.ConnectAsync(k); var messageListener = new MessageListener(); + //设置监听 channel.GetAttribute(messageListenerKey).Set(messageListener); + //实例化发送者 var messageSender = new DotNettyMessageClientSender(_transportMessageEncoder, channel); + //设置channel属性 channel.GetAttribute(messageSenderKey).Set(messageSender); channel.GetAttribute(origEndPointKey).Set(k); + //创建客户端 var client = new TransportClient(messageSender, messageListener, _logger, _serviceExecutor); return client; } - )).Value; + )).Value;//返回实例 } catch { + //移除 _clients.TryRemove(key, out var value); + var ipEndPoint = endPoint as IPEndPoint; + //标记这个地址是失败的请求 + if (ipEndPoint != null) + await _healthCheckService.MarkFailure(new IpAddressModel(ipEndPoint.Address.ToString(), ipEndPoint.Port)); throw; } } @@ -110,9 +127,9 @@ public ITransportClient CreateClient(EndPoint endPoint) /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. public void Dispose() { - foreach (var client in _clients.Values.Where(i => i.IsValueCreated)) + foreach (var client in _clients.Values) { - (client.Value as IDisposable)?.Dispose(); + (client as IDisposable)?.Dispose(); } } @@ -120,12 +137,24 @@ public void Dispose() private static Bootstrap GetBootstrap() { + IEventLoopGroup group; + var bootstrap = new Bootstrap(); + if (AppConfig.ServerOptions.Libuv) + { + group = new EventLoopGroup(); + bootstrap.Channel(); + } + else + { + group = new MultithreadEventLoopGroup(); + bootstrap.Channel(); + } bootstrap .Channel() .Option(ChannelOption.TcpNodelay, true) - .Option(ChannelOption.Allocator, PooledByteBufferAllocator.Default) - .Group(new MultithreadEventLoopGroup(1)); + .Option(ChannelOption.Allocator,new UnpooledByteBufferAllocator(false,false)) + .Group(group); return bootstrap; } @@ -158,4 +187,4 @@ public override void ChannelRead(IChannelHandlerContext context, object message) #endregion Overrides of ChannelHandlerAdapter } } -} \ No newline at end of file +} diff --git a/src/Surging.Core/Surging.Core.DotNetty/Surging.Core.DotNetty.csproj b/src/Surging.Core/Surging.Core.DotNetty/Surging.Core.DotNetty.csproj index 30752d1de..15ca46fde 100644 --- a/src/Surging.Core/Surging.Core.DotNetty/Surging.Core.DotNetty.csproj +++ b/src/Surging.Core/Surging.Core.DotNetty/Surging.Core.DotNetty.csproj @@ -1,26 +1,26 @@  - netcoreapp2.1 - 0.8.0.2 + net6.0 + 1.1.0.0 surging Micro Service Framework fanly Copyright © fanly All Rights Reserved. https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging - 1.Service host support multiple protocols -2.Exclude interface registration service + 1.multiple register center cluster +2. fix bug MicroService surging surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec - 0.8.0.2 - 0.8.0.2 + 1.1.0.0 + 1.1.0.0 - - - + + + diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/Attributes/BehaviorContractAttribute.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/Attributes/BehaviorContractAttribute.cs new file mode 100644 index 000000000..78326ed05 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/Attributes/BehaviorContractAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DotNettyWSServer.Attributes +{ + public class BehaviorContractAttribute: Attribute + { + + public string Protocol { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/DotNettyWSMessageListener.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/DotNettyWSMessageListener.cs new file mode 100644 index 000000000..35b013b96 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/DotNettyWSMessageListener.cs @@ -0,0 +1,187 @@ +using DotNetty.Buffers; +using DotNetty.Codecs; +using DotNetty.Codecs.Http; +using DotNetty.Codecs.Http.WebSockets; +using DotNetty.Handlers.Streams; +using DotNetty.Handlers.Timeout; +using DotNetty.Transport.Bootstrapping; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Groups; +using DotNetty.Transport.Channels.Sockets; +using DotNetty.Transport.Libuv; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.DotNettyWSServer.Runtime; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DotNettyWSServer +{ + public class DotNettyWSMessageListener : IMessageListener, IDisposable + { + #region Field + + private readonly ILogger _logger; + private IChannel _channel; + private List _wSServiceEntries; + public event ReceivedDelegate Received; + + #endregion Field + + #region Constructor + public DotNettyWSMessageListener(ILogger logger + , IWSServiceEntryProvider wsServiceEntryProvider) + { + _logger = logger; + _wSServiceEntries = wsServiceEntryProvider.GetEntries().ToList(); + } + + public async Task StartAsync(EndPoint endPoint) + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); + + + IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1); + IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 + var bootstrap = new ServerBootstrap(); + + if (AppConfig.ServerOptions.Libuv) + { + var dispatcher = new DispatcherEventLoopGroup(); + bossGroup = dispatcher; + workerGroup = new WorkerEventLoopGroup(dispatcher); + bootstrap.Channel(); + } + else + { + bossGroup = new MultithreadEventLoopGroup(1); + workerGroup = new MultithreadEventLoopGroup(); + bootstrap.Channel(); + } + bootstrap + .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) + .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default) + .ChildOption(ChannelOption.WriteBufferHighWaterMark,1024*1024*8) + .Group(bossGroup, workerGroup) + .ChildHandler(new ActionChannelInitializer(channel => + { + var pipeline = channel.Pipeline; + pipeline.AddLast("readTimeout", new ReadTimeoutHandler(45)); + pipeline.AddLast("HttpServerCodec", new HttpServerCodec()); + pipeline.AddLast("ChunkedWriter", new ChunkedWriteHandler()); + pipeline.AddLast("HttpAggregator", new HttpObjectAggregator(65535)); + _wSServiceEntries.ForEach(p => + { + pipeline.AddLast("WsProtocolHandler", + new WebSocketServerProtocolHandler(p.Path, p.Behavior.Protocol, true)); + }); + + pipeline.AddLast("WSBinaryDecoder", new WebSocketFrameDecoder()); + pipeline.AddLast("WSEncoder", new WebSocketFramePrepender()); + pipeline.AddLast(new ServerHandler( _logger)); + })).Option(ChannelOption.SoBroadcast, true); + try + { + + _channel = await bootstrap.BindAsync(endPoint); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"WS服务主机启动成功,监听地址:{endPoint}。"); + } + catch (Exception ex) + { + _logger.LogError($"WS服务主机启动失败,监听地址:{endPoint}。 "); + } + + } + + public async Task OnReceived(IMessageSender sender, TransportMessage message) + { + if (Received == null) + return; + await Received(sender, message); + } + + + public void CloseAsync() + { + Task.Run(async () => + { + await _channel.EventLoop.ShutdownGracefullyAsync(); + await _channel.CloseAsync(); + }).Wait(); + } + + public void Dispose() + { + Task.Run(async () => + { + await _channel.DisconnectAsync(); + }).Wait(); + } + + #endregion + + public class WebSocketFrameDecoder : MessageToMessageDecoder { + + protected override void Decode(IChannelHandlerContext ctx, WebSocketFrame msg, List output) + { + var buff = msg.Content; + byte[] messageBytes = new byte[buff.ReadableBytes]; + buff.ReadBytes(messageBytes); + var bytebuf = PooledByteBufferAllocator.Default.Buffer(); + bytebuf.WriteBytes(messageBytes); + output.Add(bytebuf.Retain()); + } + } + + public class WebSocketFramePrepender : MessageToMessageDecoder + { + + protected override void Decode(IChannelHandlerContext ctx, IByteBuffer msg, List output) + { + WebSocketFrame webSocketFrame = new BinaryWebSocketFrame(msg); + output.Add(webSocketFrame); + } + } + + + private class ServerHandler : SimpleChannelInboundHandler + { + private readonly ILogger _logger; + + public ServerHandler(ILogger logger) + { + _logger = logger; + } + + public override void ChannelActive(IChannelHandlerContext ctx) + { + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("ws 连接 ctx:" + ctx); + if (PlayerGroup.ChannelGroup == null) PlayerGroup.ChannelGroup = new DefaultChannelGroup(ctx.Executor); + PlayerGroup.AddChannel(ctx.Channel); + } + + public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) + { + context.CloseAsync(); + PlayerGroup.RemoveChannel(context.Channel); + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, $"与服务器:{context.Channel.RemoteAddress}通信时发送了错误。"); + } + + protected override void ChannelRead0(IChannelHandlerContext ctx, TextWebSocketFrame msg) + { + + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/DotNettyWSModule.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/DotNettyWSModule.cs new file mode 100644 index 000000000..683c51f59 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/DotNettyWSModule.cs @@ -0,0 +1,85 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.DotNettyWSServer.Runtime; +using Surging.Core.DotNettyWSServer.Runtime.Implementation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DotNettyWSServer +{ + public class DotNettyWSModule : EnginePartModule + { + public override void Initialize(AppModuleContext serviceProvider) + { + base.Initialize(serviceProvider); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.Register(provider => + { + return new DefaultWSServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(IWSServiceEntryProvider)).SingleInstance(); + if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.WS) + { + RegisterDefaultProtocol(builder); + } + else if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterWSProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + + builder.Register(provider => + { + return new DotNettyWSMessageListener( + provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new DefaultServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, null); + + }).As(); + } + + private static void RegisterWSProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DotNettyWSMessageListener(provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new WSServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }); + + }).As(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/PlayerGroup.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/PlayerGroup.cs new file mode 100644 index 000000000..a08bacffa --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/PlayerGroup.cs @@ -0,0 +1,41 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Http.WebSockets; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Groups; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DotNettyWSServer +{ + public class PlayerGroup + { + public static IChannelGroup ChannelGroup { get; set; } + + public static void AddChannel(IChannel channel) + { + ChannelGroup.Add(channel); + } + + public static void RemoveChannel(IChannel channel) + { + ChannelGroup.Remove(channel); + } + + public static async Task BroadCast(IByteBuffer message) + { + if (ChannelGroup == null) return; + + BinaryWebSocketFrame frame = new BinaryWebSocketFrame(message); + message.Retain(); + await ChannelGroup.WriteAndFlushAsync(frame); + } + + public static async Task Destory() + { + if (ChannelGroup == null) return; + await ChannelGroup.CloseAsync(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/IWSServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/IWSServiceEntryProvider.cs new file mode 100644 index 000000000..2ae0b56b5 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/IWSServiceEntryProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DotNettyWSServer.Runtime +{ + public interface IWSServiceEntryProvider + { + IEnumerable GetEntries(); + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/Implementation/DefaultWSServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/Implementation/DefaultWSServiceEntryProvider.cs new file mode 100644 index 000000000..27db9dd1d --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/Implementation/DefaultWSServiceEntryProvider.cs @@ -0,0 +1,90 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using Surging.Core.DotNettyWSServer.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.DotNettyWSServer.Runtime.Implementation +{ + public class DefaultWSServiceEntryProvider : IWSServiceEntryProvider + { + #region Field + + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private List _wSServiceEntries; + + #endregion Field + + #region Constructor + + public DefaultWSServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of IUdpServiceEntryProvider + + /// + /// 获取服务条目集合。 + /// + /// 服务条目集合。 + public IEnumerable GetEntries() + { + var services = _types.ToArray(); + if (_wSServiceEntries == null) + { + _wSServiceEntries = new List(); + foreach (var service in services) + { + var entry = CreateServiceEntry(service); + if (entry != null) + { + _wSServiceEntries.Add(entry); + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下WS服务:{string.Join(",", _wSServiceEntries.Select(i => i.Type.FullName))}。"); + } + } + return _wSServiceEntries; + } + public WSServiceEntry CreateServiceEntry(Type service) + { + WSServiceEntry result = null; + var routeTemplate = service.GetCustomAttribute(); + var behaviorContract = service.GetCustomAttribute(); + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as WSBehavior; + var path = RoutePatternParser.Parse(routeTemplate.RouteTemplate, service.Name); + if (path.Length > 0 && path[0] != '/') + path = $"/{path}"; + if (behavior != null) + { + behavior.Protocol = behaviorContract?.Protocol; + result = new WSServiceEntry + { + Behavior = behavior, + Type = behavior.GetType(), + Path = path, + }; + } + return result; + } + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/WSBehavior.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/WSBehavior.cs new file mode 100644 index 000000000..f063626d0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/WSBehavior.cs @@ -0,0 +1,118 @@ +using Autofac; +using DotNetty.Buffers; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DotNettyWSServer.Runtime +{ + public class WSBehavior : IServiceBehavior + { + private ServerReceivedDelegate received; + public event ServerReceivedDelegate Received + { + add + { + if (received == null) + { + received += value; + } + } + remove + { + received -= value; + } + } + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await received(message); + } + public T CreateProxy(string key) where T : class + { + return ServiceLocator.GetService().CreateProxy(key); + } + + public object CreateProxy(Type type) + { + return ServiceLocator.GetService().CreateProxy(type); + } + + public object CreateProxy(string key, Type type) + { + return ServiceLocator.GetService().CreateProxy(key, type); + } + + public T CreateProxy() where T : class + { + return ServiceLocator.GetService().CreateProxy(); + } + + public T GetService(string key) where T : class + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return ServiceLocator.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public T GetService() where T : class + { + if (ServiceLocator.Current.IsRegistered()) + return ServiceLocator.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public string Protocol { get; set; } + + public async Task BroadCast(byte[] bytes) + { + var bytebuf = PooledByteBufferAllocator.Default.Buffer(); + bytebuf.WriteBytes(bytes); + await PlayerGroup.BroadCast(bytebuf); + } + + public object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return ServiceLocator.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return ServiceLocator.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/WSServiceEntry.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/WSServiceEntry.cs new file mode 100644 index 000000000..779385c1d --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/Runtime/WSServiceEntry.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.DotNettyWSServer.Runtime +{ + public class WSServiceEntry + { + public string Path { get; set; } + + public Type Type { get; set; } + + public WSBehavior Behavior { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/Surging.Core.DotNettyWSServer.csproj b/src/Surging.Core/Surging.Core.DotNettyWSServer/Surging.Core.DotNettyWSServer.csproj new file mode 100644 index 000000000..d0849dd1d --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/Surging.Core.DotNettyWSServer.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.DotNettyWSServer/WSServiceHost.cs b/src/Surging.Core/Surging.Core.DotNettyWSServer/WSServiceHost.cs new file mode 100644 index 000000000..049d5ae72 --- /dev/null +++ b/src/Surging.Core/Surging.Core.DotNettyWSServer/WSServiceHost.cs @@ -0,0 +1,56 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.DotNettyWSServer +{ + public class WSServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public WSServiceHost(Func> messageListenerFactory) : base(null) + { + _messageListenerFactory = messageListenerFactory; + } + + #region Overrides of ServiceHostAbstract + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(endPoint); + + } + + public override async Task StartAsync(string ip, int port) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.WSPort)); + } + + #endregion Overrides of ServiceHostAbstract + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Appconfig.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Appconfig.cs index 57b13e0b9..8b6a6fcee 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Appconfig.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Appconfig.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Configuration; +using Surging.Core.EventBusKafka.Configurations; using System; using System.Collections.Generic; using System.Linq; @@ -11,6 +12,8 @@ public class AppConfig public static IConfigurationRoot Configuration { get; set; } + public static KafkaOptions Options { get; internal set; } + private static IEnumerable> _kafkaConsumerConfig; diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/EventBusConfigurationExtensions.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/EventBusConfigurationExtensions.cs index f7aa6f972..93dda75d2 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/EventBusConfigurationExtensions.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/EventBusConfigurationExtensions.cs @@ -12,20 +12,25 @@ public static class EventBusConfigurationExtensions { public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path) { - return AddEventBusFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + return AddEventBusFile(builder, provider: null, path: path, basePath: null, optional: false, reloadOnChange: false); } public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path, bool optional) { - return AddEventBusFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + return AddEventBusFile(builder, provider: null, path: path, basePath: null, optional: optional, reloadOnChange: false); } public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { - return AddEventBusFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + return AddEventBusFile(builder, provider: null, path: path, basePath:null, optional: optional, reloadOnChange: reloadOnChange); } - public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path,string basePath, bool optional, bool reloadOnChange) + { + return AddEventBusFile(builder, provider: null, path: path, basePath:basePath, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, IFileProvider provider, string path,string basePath, bool optional, bool reloadOnChange) { Check.NotNull(builder, "builder"); Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); @@ -34,7 +39,7 @@ public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder b { provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); path = Path.GetFileName(path); - } + } var source = new EventBusConfigurationSource { FileProvider = provider, @@ -43,6 +48,8 @@ public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder b ReloadOnChange = reloadOnChange }; builder.Add(source); + if (!string.IsNullOrEmpty(basePath)) + builder.SetBasePath(basePath); AppConfig.Configuration = builder.Build(); return builder; } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/KafkaOptions.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/KafkaOptions.cs index 39aec9def..5f1e0034b 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/KafkaOptions.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/KafkaOptions.cs @@ -11,12 +11,26 @@ public class KafkaOptions public int MaxQueueBuffering { get; set; } = 10; - public int MaxSocketBlocking { get; set; }= 10; + public int MaxSocketBlocking { get; set; } = 10; public bool EnableAutoCommit { get; set; } = false; public bool LogConnectionClose { get; set; } = false; + public int Timeout { get; set; } = 100; + + public int CommitInterval { get; set; } = 1000; + + public OffsetResetMode OffsetReset { get; set; } = OffsetResetMode.Earliest; + + public int SessionTimeout { get; set; } = 36000; + + public string Acks { get; set; } = "all"; + + public int Retries { get; set; } + + public int Linger { get; set; } = 1; + public string GroupID { get; set; } = "suringdemo"; public KafkaOptions Value => this; @@ -29,6 +43,9 @@ public IEnumerable> GetConsumerConfig() configs.Add(new KeyValuePair("socket.blocking.max.ms", MaxSocketBlocking.ToString())); configs.Add(new KeyValuePair("enable.auto.commit", EnableAutoCommit.ToString())); configs.Add(new KeyValuePair("log.connection.close", LogConnectionClose.ToString())); + configs.Add(new KeyValuePair("auto.commit.interval.ms", CommitInterval)); + configs.Add(new KeyValuePair("auto.offset.reset", OffsetReset.ToString().ToLower())); + configs.Add(new KeyValuePair("session.timeout.ms", SessionTimeout)); configs.Add(new KeyValuePair("group.id", GroupID)); return configs; } @@ -37,6 +54,9 @@ public IEnumerable> GetProducerConfig() { var configs = new List>(); configs.Add(new KeyValuePair("bootstrap.servers", Servers)); + configs.Add(new KeyValuePair("acks", Acks)); + configs.Add(new KeyValuePair("retries", Retries)); + configs.Add(new KeyValuePair("linger.ms", Linger)); return configs; } } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/OffsetResetMode.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/OffsetResetMode.cs new file mode 100644 index 000000000..e6297042d --- /dev/null +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Configurations/OffsetResetMode.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.EventBusKafka.Configurations +{ + public enum OffsetResetMode + { + Earliest, + Latest, + None, + } +} diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.EventBusKafka/ContainerBuilderExtensions.cs index 2db02f556..831c4c1ce 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/ContainerBuilderExtensions.cs @@ -25,15 +25,15 @@ public static class ContainerBuilderExtensions /// 服务构建者。 public static IServiceBuilder UseKafkaMQTransport(this IServiceBuilder builder,Action options) { - var kafkaOptions = new KafkaOptions(); + AppConfig.Options = new KafkaOptions(); var section = CPlatform.AppConfig.GetSection("Kafka"); if (section.Exists()) - kafkaOptions = section.Get(); + AppConfig.Options = section.Get(); else if (AppConfig.Configuration != null) - kafkaOptions = AppConfig.Configuration.Get(); - options.Invoke(kafkaOptions); - AppConfig.KafkaConsumerConfig = kafkaOptions.GetConsumerConfig(); - AppConfig.KafkaProducerConfig = kafkaOptions.GetProducerConfig(); + AppConfig.Options = AppConfig.Configuration.Get(); + options.Invoke(AppConfig.Options); + AppConfig.KafkaConsumerConfig = AppConfig.Options.GetConsumerConfig(); + AppConfig.KafkaProducerConfig = AppConfig.Options.GetProducerConfig(); var services = builder.Services; builder.Services.RegisterType(typeof(Implementation.EventBusKafka)).As(typeof(IEventBus)).SingleInstance(); builder.Services.RegisterType(typeof(DefaultConsumeConfigurator)).As(typeof(IConsumeConfigurator)).SingleInstance(); diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/EventBusKafkaModule.cs b/src/Surging.Core/Surging.Core.EventBusKafka/EventBusKafkaModule.cs index 6a8d12fa2..6ab2d7d5c 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/EventBusKafkaModule.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/EventBusKafkaModule.cs @@ -9,15 +9,23 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Engines; +using System.Threading.Tasks; namespace Surging.Core.EventBusKafka { public class EventBusKafkaModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); serviceProvider.GetInstances().SubscribeAt(); + serviceProvider.GetInstances().ServiceEngineStarted.Register(() => + { + KafkaConsumerPersistentConnection connection = serviceProvider.GetInstances(KafkaConnectionType.Consumer.ToString()) as KafkaConsumerPersistentConnection; + connection.Listening(TimeSpan.FromMilliseconds(AppConfig.Options.Timeout)); + }); } /// @@ -32,14 +40,14 @@ protected override void RegisterBuilder(ContainerBuilderWrapper builder) public EventBusKafkaModule UseKafkaMQTransport(ContainerBuilderWrapper builder) { - var kafkaOptions = new KafkaOptions(); + AppConfig.Options = new KafkaOptions(); var section = CPlatform.AppConfig.GetSection("EventBus_Kafka"); if (section.Exists()) - kafkaOptions = section.Get(); + AppConfig.Options = section.Get(); else if (AppConfig.Configuration != null) - kafkaOptions = AppConfig.Configuration.Get(); - AppConfig.KafkaConsumerConfig = kafkaOptions.GetConsumerConfig(); - AppConfig.KafkaProducerConfig = kafkaOptions.GetProducerConfig(); + AppConfig.Options = AppConfig.Configuration.Get(); + AppConfig.KafkaConsumerConfig = AppConfig.Options.GetConsumerConfig(); + AppConfig.KafkaProducerConfig = AppConfig.Options.GetProducerConfig(); builder.RegisterType(typeof(Implementation.EventBusKafka)).As(typeof(IEventBus)).SingleInstance(); builder.RegisterType(typeof(DefaultConsumeConfigurator)).As(typeof(IConsumeConfigurator)).SingleInstance(); builder.RegisterType(typeof(InMemoryEventBusSubscriptionsManager)).As(typeof(IEventBusSubscriptionsManager)).SingleInstance(); diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/IConsumeConfigurator.cs b/src/Surging.Core/Surging.Core.EventBusKafka/IConsumeConfigurator.cs index f63a3ee24..1bda6e9dc 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/IConsumeConfigurator.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/IConsumeConfigurator.cs @@ -7,5 +7,7 @@ namespace Surging.Core.EventBusKafka public interface IConsumeConfigurator { void Configure(List consumers); + + void Unconfigure(List consumers); } } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/DefaultConsumeConfigurator.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/DefaultConsumeConfigurator.cs index 66f75d4b1..93e5e1b8f 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/DefaultConsumeConfigurator.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/DefaultConsumeConfigurator.cs @@ -48,6 +48,34 @@ public void Configure(List consumers) } } + public void Unconfigure(List consumers) + { + foreach (var consumer in consumers) + { + if (consumer.GetTypeInfo().IsGenericType) + { + continue; + } + var consumerType = consumer.GetInterfaces() + .Where( + d => + d.GetTypeInfo().IsGenericType && + d.GetGenericTypeDefinition() == typeof(IIntegrationEventHandler<>)) + .Select(d => d.GetGenericArguments().Single()) + .First(); + try + { + var type = consumer; + this.FastInvoke(new[] { consumerType, consumer }, + x => x.RemoveConsumer>()); + } + catch (Exception ex) + { + throw ex; + } + } + } + protected void ConsumerTo() where TConsumer : IIntegrationEventHandler where TEvent : class @@ -55,6 +83,13 @@ protected void ConsumerTo() _eventBus.Subscribe (() => (TConsumer)_container.GetInstances(typeof(TConsumer))); } + + protected void RemoveConsumer() + where TConsumer : IIntegrationEventHandler + where TEvent : class + { + _eventBus.Unsubscribe(); + } } } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/EventBusKafka.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/EventBusKafka.cs index b64e8c5bb..cd8f9e9ed 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/EventBusKafka.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/EventBusKafka.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Surging.Core.EventBusKafka.Implementation @@ -21,6 +22,8 @@ public class EventBusKafka : IEventBus, IDisposable private readonly IKafkaPersisterConnection _producerConnection; private readonly IKafkaPersisterConnection _consumerConnection; + public event EventHandler OnShutdown; + public EventBusKafka( ILogger logger, IEventBusSubscriptionsManager subsManager, CPlatformContainer serviceProvider) @@ -57,31 +60,24 @@ public void Dispose() public void Publish(IntegrationEvent @event) { - if (!_producerConnection.IsConnected) { _producerConnection.TryConnect(); } - var eventName = @event.GetType() .Name; - - var message = JsonConvert.SerializeObject(@event); - var body =message; - + var body = JsonConvert.SerializeObject(@event); var policy = RetryPolicy.Handle() .WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => { _logger.LogWarning(ex.ToString()); }); - using (var conn = _producerConnection.CreateConnect() as Producer) - { - policy.Execute(() => - { - conn.ProduceAsync(eventName, null, body).GetAwaiter().GetResult(); - }); - } + var conn = _producerConnection.CreateConnect() as Producer; + policy.Execute(() => + { + conn.ProduceAsync(eventName, null, body).GetAwaiter().GetResult(); + }); } public void Subscribe(Func handler) where TH : IIntegrationEventHandler @@ -90,54 +86,25 @@ public void Subscribe(Func handler) where TH : IIntegrationEventHandl var containsKey = _subsManager.HasSubscriptionsForEvent(); if (!containsKey) { - if (!_consumerConnection.IsConnected) - { - _consumerConnection.TryConnect(); - } - - using (var channel = _consumerConnection.CreateConnect() as Consumer) - { - channel.OnMessage += ConsumerClient_OnMessage; - channel.Subscribe(eventName); - channel.Poll(TimeSpan.FromMilliseconds(100)); - } + var channel = _consumerConnection.CreateConnect() as Consumer; + channel.OnMessage += ConsumerClient_OnMessage; + channel.Subscribe(eventName); } - _subsManager.AddSubscription(handler,null); - - - + _subsManager.AddSubscription(handler, null); } - + public void Unsubscribe() where TH : IIntegrationEventHandler { _subsManager.RemoveSubscription(); } - - //private void CreateConsumerChannel() - //{ - // if (!_consumerConnection.IsConnected) - // { - // _consumerConnection.TryConnect(); - // } - - // using (var channel = _consumerConnection.CreateConnect() as Consumer) - // { - - // channel.OnMessage += ConsumerClient_OnMessage; - - // } - //} - - + private void ConsumerClient_OnMessage(object sender, Message e) { ProcessEvent(e.Topic, e.Value).Wait(); } - - + private async Task ProcessEvent(string eventName, string message) { - if (_subsManager.HasSubscriptionsForEvent(eventName)) { var eventType = _subsManager.GetEventTypeByName(eventName); @@ -146,9 +113,15 @@ private async Task ProcessEvent(string eventName, string message) foreach (var handlerfactory in handlers) { - var handler = handlerfactory.DynamicInvoke(); - var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); - await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); + try + { + var handler = handlerfactory.DynamicInvoke(); + var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); + await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); + } + catch + { + } } } } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaConsumerPersistentConnection.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaConsumerPersistentConnection.cs index 49d368e11..e7149674f 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaConsumerPersistentConnection.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaConsumerPersistentConnection.cs @@ -2,15 +2,18 @@ using Confluent.Kafka.Serialization; using Microsoft.Extensions.Logging; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading; namespace Surging.Core.EventBusKafka.Implementation { - public class KafkaConsumerPersistentConnection : KafkaPersistentConnectionBase + public class KafkaConsumerPersistentConnection : KafkaPersistentConnectionBase { private readonly ILogger _logger; + private ConcurrentBag> _consumerClients; private Consumer _consumerClient; private readonly IDeserializer _stringDeserializer; bool _disposed; @@ -20,6 +23,7 @@ public KafkaConsumerPersistentConnection(ILogger>(); } public override bool IsConnected => _consumerClient != null && !_disposed; @@ -29,13 +33,41 @@ public override Action Connection(IEnumerable> opti return () => { _consumerClient = new Consumer(options, null, _stringDeserializer); - _consumerClient.OnConsumeError += OnConsumeError; + _consumerClient.OnConsumeError += OnConsumeError; _consumerClient.OnError += OnConnectionException; + _consumerClients.Add(_consumerClient); + }; } + public void Listening(TimeSpan timeout) + { + if (!IsConnected) + { + TryConnect(); + } + while (true) + { + foreach (var client in _consumerClients) + { + + client.Poll(timeout); + + if (!client.Consume(out Message msg, (int)timeout.TotalMilliseconds)) + { + continue; + } + if (msg.Offset % 5 == 0) + { + var committedOffsets = client.CommitAsync(msg).Result; + } + } + } + } + public override object CreateConnect() { + TryConnect(); return _consumerClient; } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaPersistentConnectionBase.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaPersistentConnectionBase.cs index a67a55709..5d0a6d25b 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaPersistentConnectionBase.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaPersistentConnectionBase.cs @@ -58,7 +58,6 @@ public bool TryConnect() public abstract Action Connection(IEnumerable> options); - public abstract object CreateConnect(); public abstract void Dispose(); } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaProducerPersistentConnection.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaProducerPersistentConnection.cs index 9f8cdd7ce..33221eeab 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaProducerPersistentConnection.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaProducerPersistentConnection.cs @@ -12,14 +12,14 @@ public class KafkaProducerPersistentConnection : KafkaPersistentConnectionBase { private Producer _connection; private readonly ILogger _logger; - private readonly ISerializer _stringDeserializer; + private readonly ISerializer _stringSerializer; bool _disposed; public KafkaProducerPersistentConnection(ILogger logger) :base(logger,AppConfig.KafkaProducerConfig) - { - _logger = logger; - _stringDeserializer = new StringSerializer(Encoding.UTF8); + { + _logger = logger; + _stringSerializer = new StringSerializer(Encoding.UTF8); } public override bool IsConnected => _connection != null && !_disposed; @@ -28,15 +28,15 @@ public KafkaProducerPersistentConnection(ILogger> options) { return () => - { - _connection = new Producer(options,null, _stringDeserializer); - _connection.OnError += OnConnectionException; - + { + _connection = new Producer(options,null, _stringSerializer); + _connection.OnError += OnConnectionException; }; } public override object CreateConnect() { + TryConnect(); return _connection; } diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaSubscriptionAdapt.cs b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaSubscriptionAdapt.cs index 9df027943..2b93e42f8 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaSubscriptionAdapt.cs +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Implementation/KafkaSubscriptionAdapt.cs @@ -21,6 +21,11 @@ public void SubscribeAt() _consumeConfigurator.Configure(GetQueueConsumers()); } + public void Unsubscribe() + { + _consumeConfigurator.Unconfigure(GetQueueConsumers()); + } + #region 私有方法 private List GetQueueConsumers() { diff --git a/src/Surging.Core/Surging.Core.EventBusKafka/Surging.Core.EventBusKafka.csproj b/src/Surging.Core/Surging.Core.EventBusKafka/Surging.Core.EventBusKafka.csproj index 38499c706..f49ac7f50 100644 --- a/src/Surging.Core/Surging.Core.EventBusKafka/Surging.Core.EventBusKafka.csproj +++ b/src/Surging.Core/Surging.Core.EventBusKafka/Surging.Core.EventBusKafka.csproj @@ -1,8 +1,8 @@ - + - netcoreapp2.1 - 0.8.0.1 + net6.0 + 1.1.0.0 fanly fanly surging Micro Service Framework @@ -10,27 +10,17 @@ Copyright © fanly All Rights Reserved. https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component + 1.multiple register center cluster +2. fix bug MicroService surging - 0.8.0.1 - 0.8.0.1 + 1.1.0.0 + 1.1.0.0 - - - + + + diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/AppConfig.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/AppConfig.cs index e28657c1c..b10f74ddf 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/AppConfig.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/AppConfig.cs @@ -12,6 +12,8 @@ public static class AppConfig public static string BrokerName { get; internal set; } + public static ushort PrefetchCount { get; set; } + public static int RetryCount { get; internal set; } = 3; public static int FailCount { get; internal set; } = 3; diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusConfigurationExtensions.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusConfigurationExtensions.cs index cdf6b2c17..a155a4f42 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusConfigurationExtensions.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusConfigurationExtensions.cs @@ -12,20 +12,25 @@ public static class EventBusConfigurationExtensions { public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path) { - return AddEventBusFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + return AddEventBusFile(builder, provider: null, path: path, basePath: null, optional: false, reloadOnChange: false); } public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path, bool optional) { - return AddEventBusFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + return AddEventBusFile(builder, provider: null, path: path, basePath: null, optional: optional, reloadOnChange: false); } public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { - return AddEventBusFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + return AddEventBusFile(builder, provider: null, path: path,basePath:null, optional: optional, reloadOnChange: reloadOnChange); } - public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, string path,string basePath, bool optional, bool reloadOnChange) + { + return AddEventBusFile(builder, provider: null, path: path, basePath:basePath, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder builder, IFileProvider provider, string path,string basePath, bool optional, bool reloadOnChange) { Check.NotNull(builder, "builder"); Check.CheckCondition(() => string.IsNullOrEmpty(path), "path"); @@ -34,6 +39,7 @@ public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder b provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); path = Path.GetFileName(path); } + var source = new EventBusConfigurationSource { FileProvider = provider, @@ -42,6 +48,8 @@ public static IConfigurationBuilder AddEventBusFile(this IConfigurationBuilder b ReloadOnChange = reloadOnChange }; builder.Add(source); + if (!string.IsNullOrEmpty(basePath)) + builder.SetBasePath(basePath); AppConfig.Configuration = builder.Build(); return builder; } diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusOption.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusOption.cs index 6f9021c1c..7ca210181 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusOption.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Configurations/EventBusOption.cs @@ -22,6 +22,8 @@ public class EventBusOption public int FailCount { get; set; } = 3; + public ushort PrefetchCount { get; set; } + public int MessageTTL { get; set; } = 30 * 1000; } } diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ContainerBuilderExtensions.cs index 4a9c3ac0e..dce04495f 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ContainerBuilderExtensions.cs @@ -49,6 +49,7 @@ public static IServiceBuilder UseRabbitMQTransport(this IServiceBuilder builder) AppConfig.MessageTTL = option.MessageTTL; AppConfig.RetryCount = option.RetryCount; AppConfig.FailCount = option.FailCount; + AppConfig.PrefetchCount = option.PrefetchCount; return new DefaultRabbitMQPersistentConnection(factory, logger); }).As(); return builder; diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/EventBusRabbitMQModule.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/EventBusRabbitMQModule.cs index fa8b294f8..b8d2a43ed 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/EventBusRabbitMQModule.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/EventBusRabbitMQModule.cs @@ -12,15 +12,25 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Routing; namespace Surging.Core.EventBusRabbitMQ { public class EventBusRabbitMQModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); - serviceProvider.GetInstances().SubscribeAt(); + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); + new ServiceRouteWatch(serviceProvider.GetInstances(), () => + { + var subscriptionAdapt = serviceProvider.GetInstances(); + serviceProvider.GetInstances().OnShutdown += (sender, args) => + { + subscriptionAdapt.Unsubscribe(); + }; + serviceProvider.GetInstances().SubscribeAt(); + }); } /// @@ -60,6 +70,7 @@ public EventBusRabbitMQModule UseRabbitMQTransport(ContainerBuilderWrapper build AppConfig.BrokerName = option.BrokerName; AppConfig.MessageTTL = option.MessageTTL; AppConfig.RetryCount = option.RetryCount; + AppConfig.PrefetchCount = option.PrefetchCount; AppConfig.FailCount = option.FailCount; return new DefaultRabbitMQPersistentConnection(factory, logger); }).As(); diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IConsumeConfigurator.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IConsumeConfigurator.cs index 0c67dcd34..451299996 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IConsumeConfigurator.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IConsumeConfigurator.cs @@ -7,5 +7,7 @@ namespace Surging.Core.EventBusRabbitMQ public interface IConsumeConfigurator { void Configure(List consumers); + + void Unconfigure(List consumers); } } diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IRabbitMQPersisterConnection.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IRabbitMQPersisterConnection.cs index 9938e1682..1b32ccf92 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IRabbitMQPersisterConnection.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/IRabbitMQPersisterConnection.cs @@ -13,5 +13,7 @@ public interface IRabbitMQPersistentConnection bool TryConnect(); IModel CreateModel(); + + event EventHandler OnRabbitConnectionShutdown; } } \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultConsumeConfigurator.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultConsumeConfigurator.cs index b7575194d..485b3cb4b 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultConsumeConfigurator.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultConsumeConfigurator.cs @@ -46,7 +46,35 @@ public void Configure(List consumers) } } } - + + public void Unconfigure(List consumers) + { + foreach (var consumer in consumers) + { + if (consumer.GetTypeInfo().IsGenericType) + { + continue; + } + var consumerType = consumer.GetInterfaces() + .Where( + d => + d.GetTypeInfo().IsGenericType && + d.GetGenericTypeDefinition() == typeof(IIntegrationEventHandler<>)) + .Select(d => d.GetGenericArguments().Single()) + .First(); + try + { + var type = consumer; + this.FastInvoke(new[] { consumerType, consumer }, + x => x.RemoveConsumer>()); + } + catch (Exception ex) + { + throw ex; + } + } + } + protected void ConsumerTo() where TConsumer : IIntegrationEventHandler where TEvent : class @@ -54,5 +82,12 @@ protected void ConsumerTo() _eventBus.Subscribe (() => (TConsumer)_container.GetInstances(typeof(TConsumer))); } + + protected void RemoveConsumer() + where TConsumer : IIntegrationEventHandler + where TEvent : class + { + _eventBus.Unsubscribe(); + } } } diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultRabbitMQPersisterConnection.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultRabbitMQPersisterConnection.cs index 2aa010de9..b9eb5c86e 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultRabbitMQPersisterConnection.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/DefaultRabbitMQPersisterConnection.cs @@ -4,6 +4,7 @@ using RabbitMQ.Client; using RabbitMQ.Client.Events; using RabbitMQ.Client.Exceptions; +using Surging.Core.CPlatform.EventBus; using System; using System.Collections.Generic; using System.IO; @@ -17,13 +18,15 @@ public class DefaultRabbitMQPersistentConnection { private readonly IConnectionFactory _connectionFactory; private readonly ILogger _logger; - IConnection _connection; bool _disposed; object sync_root = new object(); - public DefaultRabbitMQPersistentConnection(IConnectionFactory connectionFactory, ILogger logger) + public event EventHandler OnRabbitConnectionShutdown; + + public DefaultRabbitMQPersistentConnection(IConnectionFactory connectionFactory, + ILogger logger) { _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -81,6 +84,7 @@ public bool TryConnect() { _connection = _connectionFactory .CreateConnection(); + }); if (IsConnected) @@ -124,7 +128,7 @@ void OnConnectionShutdown(object sender, ShutdownEventArgs reason) if (_disposed) return; _logger.LogWarning("A RabbitMQ connection is on shutdown. Trying to re-connect..."); - + OnRabbitConnectionShutdown(sender, reason); TryConnect(); } } diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/EventBusRabbitMQ.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/EventBusRabbitMQ.cs index 92254653a..20aa268bc 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/EventBusRabbitMQ.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Implementation/EventBusRabbitMQ.cs @@ -6,9 +6,11 @@ using RabbitMQ.Client.Events; using RabbitMQ.Client.Exceptions; using RabbitMQ.Client.Framing; +using Surging.Core.CPlatform.DependencyResolution; using Surging.Core.CPlatform.EventBus; using Surging.Core.CPlatform.EventBus.Events; using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Utilities; using Surging.Core.EventBusRabbitMQ.Attributes; using System; using System.Collections.Generic; @@ -17,6 +19,7 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; +using static Surging.Core.CPlatform.Utilities.FastInvoke; namespace Surging.Core.EventBusRabbitMQ.Implementation { @@ -26,21 +29,24 @@ public class EventBusRabbitMQ : IEventBus, IDisposable private readonly int _messageTTL; private readonly int _retryCount; private readonly int _rollbackCount; + private readonly ushort _prefetchCount; private readonly IRabbitMQPersistentConnection _persistentConnection; private readonly ILogger _logger; private readonly IEventBusSubscriptionsManager _subsManager; private readonly IDictionary _exchanges; - private IDictionary _consumerChannels; - private string _queueName; + private IDictionary, IModel> _consumerChannels; + + public event EventHandler OnShutdown; public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger logger, IEventBusSubscriptionsManager subsManager) { BROKER_NAME = AppConfig.BrokerName; _messageTTL = AppConfig.MessageTTL; _retryCount = AppConfig.RetryCount; + _prefetchCount = AppConfig.PrefetchCount; _rollbackCount = AppConfig.FailCount; - _consumerChannels = new Dictionary(); + _consumerChannels = new Dictionary, IModel>(); _exchanges = new Dictionary(); _exchanges.Add(QueueConsumerMode.Normal, BROKER_NAME); _exchanges.Add(QueueConsumerMode.Retry, $"{BROKER_NAME}@{QueueConsumerMode.Retry.ToString()}"); @@ -48,7 +54,7 @@ public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILog _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); - + _persistentConnection.OnRabbitConnectionShutdown += PersistentConnection_OnEventShutDown; _subsManager.OnEventRemoved += SubsManager_OnEventRemoved; } @@ -64,15 +70,6 @@ private void SubsManager_OnEventRemoved(object sender, ValueTuple(Func handler) foreach (var modeName in _modeNames) { var mode = Enum.Parse(modeName); - _consumerChannels.Add(mode, CreateConsumerChannel(queueConsumerAttr, eventName, mode)); + string queueName = ""; if (mode != QueueConsumerMode.Normal) queueName = $"{queueConsumerAttr.QueueName}@{mode.ToString()}"; else queueName = queueConsumerAttr.QueueName; + var key = new Tuple(queueName, mode); + if (_consumerChannels.ContainsKey(key)) + { + _consumerChannels[key].Close(); + _consumerChannels.Remove(key); + } + _consumerChannels.Add(key, + CreateConsumerChannel(queueConsumerAttr, eventName, mode)); channel.QueueBind(queue: queueName, exchange: _exchanges[mode], - routingKey: eventName); + routingKey: eventName); } } } - _subsManager.AddSubscription(handler, queueConsumerAttr.QueueName); + if (!_subsManager.HasSubscriptionsForEvent()) + _subsManager.AddSubscription(handler, queueConsumerAttr.QueueName); } public void Unsubscribe() where TH : IIntegrationEventHandler { - _subsManager.RemoveSubscription(); + if (_subsManager.HasSubscriptionsForEvent()) + _subsManager.RemoveSubscription(); } private static Func FindHandlerByType(Type handlerType, IEnumerable> handlers) @@ -212,6 +219,7 @@ private IModel CreateConsumerChannel(QueueConsumerAttribute queueConsumer, strin private IModel CreateConsumerChannel(string queueName, bool bindConsumer) { + var mode = QueueConsumerMode.Normal; if (!_persistentConnection.IsConnected) { _persistentConnection.TryConnect(); @@ -228,23 +236,30 @@ private IModel CreateConsumerChannel(string queueName, bool bindConsumer) consumer.Received += async (model, ea) => { var eventName = ea.RoutingKey; - await ProcessEvent(eventName, ea.Body, ea.BasicProperties); + await ProcessEvent(eventName, ea.Body, mode, ea.BasicProperties); channel.BasicAck(ea.DeliveryTag, false); }; if (bindConsumer) + { + channel.BasicQos(0, _prefetchCount, false); channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer); - channel.CallbackException += (sender, ea) => - { - _consumerChannels[QueueConsumerMode.Normal].Dispose(); - _consumerChannels[QueueConsumerMode.Normal] = CreateConsumerChannel(queueName, bindConsumer); - }; + channel.CallbackException += (sender, ea) => + { + var key = new Tuple(queueName, mode); + _consumerChannels[key].Dispose(); + _consumerChannels[key] = CreateConsumerChannel(queueName, bindConsumer); + }; + } + else + channel.Close(); return channel; } private IModel CreateRetryConsumerChannel(string queueName, string routeKey, bool bindConsumer) { + var mode = QueueConsumerMode.Retry; if (!_persistentConnection.IsConnected) { _persistentConnection.TryConnect(); @@ -254,60 +269,76 @@ private IModel CreateRetryConsumerChannel(string queueName, string routeKey, boo arguments.Add("x-message-ttl", _messageTTL); arguments.Add("x-dead-letter-routing-key", routeKey); var channel = _persistentConnection.CreateModel(); - var retryQueueName = $"{queueName}@{QueueConsumerMode.Retry.ToString()}"; - channel.ExchangeDeclare(exchange: _exchanges[QueueConsumerMode.Retry], + var retryQueueName = $"{queueName}@{mode.ToString()}"; + channel.ExchangeDeclare(exchange: _exchanges[mode], type: "direct"); channel.QueueDeclare(retryQueueName, true, false, false, arguments); var consumer = new EventingBasicConsumer(channel); consumer.Received += async (model, ea) => { var eventName = ea.RoutingKey; - await ProcessEvent(eventName, ea.Body, ea.BasicProperties); + await ProcessEvent(eventName, ea.Body, mode,ea.BasicProperties); channel.BasicAck(ea.DeliveryTag, false); }; if (bindConsumer) + { + channel.BasicQos(0, _prefetchCount, false); channel.BasicConsume(queue: retryQueueName, autoAck: false, consumer: consumer); - channel.CallbackException += (sender, ea) => - { - _consumerChannels[QueueConsumerMode.Retry].Dispose(); - _consumerChannels[QueueConsumerMode.Retry] = CreateRetryConsumerChannel(queueName, routeKey, bindConsumer); - }; + channel.CallbackException += (sender, ea) => + { + var key = new Tuple(queueName, mode); + _consumerChannels[key].Dispose(); + _consumerChannels[key] = CreateRetryConsumerChannel(queueName, routeKey, bindConsumer); + }; + } + else + channel.Close(); + + return channel; } private IModel CreateFailConsumerChannel(string queueName, bool bindConsumer) { + var mode = QueueConsumerMode.Fail; if (!_persistentConnection.IsConnected) { _persistentConnection.TryConnect(); } var channel = _persistentConnection.CreateModel(); - channel.ExchangeDeclare(exchange: _exchanges[QueueConsumerMode.Fail], + channel.ExchangeDeclare(exchange: _exchanges[mode], type: "direct"); - var failQueueName = $"{queueName}@{QueueConsumerMode.Fail.ToString()}"; + var failQueueName = $"{queueName}@{mode.ToString()}"; channel.QueueDeclare(failQueueName, true, false, false, null); var consumer = new EventingBasicConsumer(channel); consumer.Received += async (model, ea) => { var eventName = ea.RoutingKey; - await ProcessEvent(eventName, ea.Body, ea.BasicProperties); + await ProcessEvent(eventName, ea.Body, mode, ea.BasicProperties); channel.BasicAck(ea.DeliveryTag, false); }; if (bindConsumer) + { + channel.BasicQos(0, _prefetchCount, false); channel.BasicConsume(queue: failQueueName, autoAck: false, consumer: consumer); - channel.CallbackException += (sender, ea) => - { - _consumerChannels[QueueConsumerMode.Fail].Dispose(); - _consumerChannels[QueueConsumerMode.Fail] = CreateFailConsumerChannel(queueName, bindConsumer); - }; + channel.CallbackException += (sender, ea) => + { + var key = new Tuple(queueName, mode); + _consumerChannels[key].Dispose(); + _consumerChannels[key] = CreateFailConsumerChannel(queueName, bindConsumer); + }; + } + else + channel.Close(); + return channel; } - private async Task ProcessEvent(string eventName, byte[] body, IBasicProperties properties) + private async Task ProcessEvent(string eventName, byte[] body, QueueConsumerMode mode, IBasicProperties properties) { var message = Encoding.UTF8.GetString(body); if (_subsManager.HasSubscriptionsForEvent(eventName)) @@ -315,14 +346,15 @@ private async Task ProcessEvent(string eventName, byte[] body, IBasicProperties var eventType = _subsManager.GetEventTypeByName(eventName); var integrationEvent = JsonConvert.DeserializeObject(message, eventType); var handlers = _subsManager.GetHandlersForEvent(eventName); - + var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); foreach (var handlerfactory in handlers) { + var handler = handlerfactory.DynamicInvoke(); + long retryCount = 1; try { - var handler = handlerfactory.DynamicInvoke(); - var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); - await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); + var fastInvoker = GetHandler($"{concreteType.FullName}.Handle", concreteType.GetMethod("Handle")); + await (Task)fastInvoker(handler, new object[] { integrationEvent }); } catch { @@ -330,7 +362,7 @@ private async Task ProcessEvent(string eventName, byte[] body, IBasicProperties { _persistentConnection.TryConnect(); } - long retryCount = GetRetryCount(properties); + retryCount = GetRetryCount(properties); using (var channel = _persistentConnection.CreateModel()) { if (retryCount > _retryCount) @@ -342,7 +374,9 @@ private async Task ProcessEvent(string eventName, byte[] body, IBasicProperties IDictionary headers = new Dictionary(); if (!headers.ContainsKey("x-orig-routing-key")) headers.Add("x-orig-routing-key", GetOrigRoutingKey(properties, eventName)); + retryCount = rollbackCount; channel.BasicPublish(_exchanges[QueueConsumerMode.Fail], eventName, CreateOverrideProperties(properties, headers), body); + } } else @@ -353,12 +387,26 @@ private async Task ProcessEvent(string eventName, byte[] body, IBasicProperties headers = new Dictionary(); } if (!headers.ContainsKey("x-orig-routing-key")) - headers.Add("x-orig-routing-key", GetOrigRoutingKey(properties, eventName)); - + headers.Add("x-orig-routing-key", GetOrigRoutingKey(properties, eventName)); channel.BasicPublish(_exchanges[QueueConsumerMode.Retry], eventName, CreateOverrideProperties(properties, headers), body); } } } + finally + { + var baseConcreteType = typeof(BaseIntegrationEventHandler<>).MakeGenericType(eventType); + if (handler.GetType().BaseType== baseConcreteType) + { + var context = new EventContext() + { + Content= integrationEvent, + Count = retryCount, + Type = mode.ToString() + }; + var fastInvoker = GetHandler($"{baseConcreteType.FullName}.Handled", baseConcreteType.GetMethod("Handled")); + await (Task)fastInvoker(handler, new object[] { context }); + } + } } } } @@ -452,5 +500,21 @@ private long GetRetryCount(IBasicProperties properties, IDictionary GetQueueConsumers() { diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ServiceHostBuilderExtensions.cs b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ServiceHostBuilderExtensions.cs index bee3161b7..626ba2ef3 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ServiceHostBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/ServiceHostBuilderExtensions.cs @@ -2,6 +2,9 @@ using Surging.Core.ServiceHosting.Internal; using Autofac; using Surging.Core.CPlatform.Engines; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.EventBus.Implementation; namespace Surging.Core.EventBusRabbitMQ { @@ -14,6 +17,15 @@ public static IServiceHostBuilder SubscribeAt(this IServiceHostBuilder hostBuild mapper.Resolve().ServiceEngineStarted.Register(() => { mapper.Resolve().SubscribeAt(); + new ServiceRouteWatch(mapper.Resolve(), () => + { + var subscriptionAdapt = mapper.Resolve(); + mapper.Resolve().OnShutdown += (sender, args) => + { + subscriptionAdapt.Unsubscribe(); + }; + mapper.Resolve().SubscribeAt(); + }); }); }); } diff --git a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Surging.Core.EventBusRabbitMQ.csproj b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Surging.Core.EventBusRabbitMQ.csproj index 13498e576..6c8b38f31 100644 --- a/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Surging.Core.EventBusRabbitMQ.csproj +++ b/src/Surging.Core/Surging.Core.EventBusRabbitMQ/Surging.Core.EventBusRabbitMQ.csproj @@ -1,9 +1,9 @@  - netcoreapp2.1 + net6.0 surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec - 0.8.0.1 + 1.1.0.0 fanly surging Micro Service Framework @@ -11,27 +11,17 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 0.8.0.1 - 0.8.0.1 - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component + 1.1.0.0 + 1.1.0.0 + 1.multiple register center cluster +2. fix bug - - - - + + + + diff --git a/src/Surging.Core/Surging.Core.Grpc/GrpcModule.cs b/src/Surging.Core/Surging.Core.Grpc/GrpcModule.cs new file mode 100644 index 000000000..8fb35105b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/GrpcModule.cs @@ -0,0 +1,82 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.Grpc.Runtime; +using Surging.Core.Grpc.Runtime.Implementation; + +namespace Surging.Core.Grpc +{ + public class GrpcModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DefaultGrpcServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(IGrpcServiceEntryProvider)).SingleInstance(); + if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.WS) + { + RegisterDefaultProtocol(builder); + } + else if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterGrpcProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + + builder.Register(provider => + { + return new GrpcServerMessageListener( + provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new DefaultServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, null); + + }).As(); + } + + private static void RegisterGrpcProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new GrpcServerMessageListener(provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new GrpcServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }); + + }).As(); + } + } +} + \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Grpc/GrpcServerMessageListener.cs b/src/Surging.Core/Surging.Core.Grpc/GrpcServerMessageListener.cs new file mode 100644 index 000000000..adf920cd5 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/GrpcServerMessageListener.cs @@ -0,0 +1,84 @@ +using Grpc.Core; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport; +using Surging.Core.Grpc.Runtime; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Grpc +{ + public class GrpcServerMessageListener: IMessageListener, IDisposable + { + private Server _server; + private readonly ILogger _logger; + private readonly IGrpcServiceEntryProvider _grpcServiceEntryProvider; + + public GrpcServerMessageListener(ILogger logger, + IGrpcServiceEntryProvider grpcServiceEntryProvider) + { + _logger = logger; + _grpcServiceEntryProvider = grpcServiceEntryProvider; + } + public Task StartAsync(EndPoint endPoint) + { + var ipEndPoint = endPoint as IPEndPoint; + _server = new Server() { Ports = { new ServerPort(ipEndPoint.Address.ToString(), ipEndPoint.Port, ServerCredentials.Insecure) } }; + + try + { + var entries = _grpcServiceEntryProvider.GetEntries(); + + var serverServiceDefinitions = new List(); + foreach (var entry in entries) + { + + var baseType = entry.Type.BaseType.BaseType; + var definitionType = baseType?.DeclaringType; + + var methodInfo = definitionType?.GetMethod("BindService", new Type[] { baseType }); + if (methodInfo != null) + { + var serviceDescriptor = methodInfo.Invoke(null, new object[] { entry.Behavior }) as ServerServiceDefinition; + if (serviceDescriptor != null) + { + _server.Services.Add(serviceDescriptor); + continue; + } + } + } + _server.Start(); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"Grpc服务主机启动成功,监听地址:{endPoint}。"); + } + catch + { + _logger.LogError($"Grpc服务主机启动失败,监听地址:{endPoint}。 "); + } + return Task.CompletedTask; + } + + public Server Server + { + get + { + return _server; + } + } + + public event ReceivedDelegate Received; + + public Task OnReceived(IMessageSender sender, TransportMessage message) + { + return Task.CompletedTask; + } + + public void Dispose() + { + _server.ShutdownAsync(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Grpc/GrpcServiceHost.cs b/src/Surging.Core/Surging.Core.Grpc/GrpcServiceHost.cs new file mode 100644 index 000000000..ba5e9616a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/GrpcServiceHost.cs @@ -0,0 +1,56 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Grpc +{ + public class GrpcServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public GrpcServiceHost(Func> messageListenerFactory) : base(null) + { + _messageListenerFactory = messageListenerFactory; + } + + #region Overrides of ServiceHostAbstract + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(endPoint); + + } + + public override async Task StartAsync(string ip, int port) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.GrpcPort)); + } + + #endregion Overrides of ServiceHostAbstract + } +} diff --git a/src/Surging.Core/Surging.Core.Grpc/Runtime/GrpcServiceEntry.cs b/src/Surging.Core/Surging.Core.Grpc/Runtime/GrpcServiceEntry.cs new file mode 100644 index 000000000..c6e480319 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/Runtime/GrpcServiceEntry.cs @@ -0,0 +1,15 @@ +using Surging.Core.CPlatform.Ioc; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Grpc.Runtime +{ + public class GrpcServiceEntry + { + + public Type Type { get; set; } + + public IServiceBehavior Behavior { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Grpc/Runtime/IGrpcServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Grpc/Runtime/IGrpcServiceEntryProvider.cs new file mode 100644 index 000000000..41cf1e5ae --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/Runtime/IGrpcServiceEntryProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Grpc.Runtime +{ + public interface IGrpcServiceEntryProvider + { + List GetEntries(); + } +} diff --git a/src/Surging.Core/Surging.Core.Grpc/Runtime/Implementation/DefaultGrpcServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Grpc/Runtime/Implementation/DefaultGrpcServiceEntryProvider.cs new file mode 100644 index 000000000..7a9a623c2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/Runtime/Implementation/DefaultGrpcServiceEntryProvider.cs @@ -0,0 +1,81 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.Grpc.Runtime.Implementation +{ + public class DefaultGrpcServiceEntryProvider: IGrpcServiceEntryProvider + { + #region Field + + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private List _grpcServiceEntries; + + #endregion Field + + #region Constructor + + public DefaultGrpcServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of IUdpServiceEntryProvider + + /// + /// 获取服务条目集合。 + /// + /// 服务条目集合。 + public List GetEntries() + { + var services = _types.ToArray(); + if (_grpcServiceEntries == null) + { + _grpcServiceEntries = new List(); + foreach (var service in services) + { + var entry = CreateServiceEntry(service); + if (entry != null) + { + _grpcServiceEntries.Add(entry); + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下grpc服务:{string.Join(",", _grpcServiceEntries.Select(i => i.Type.FullName))}。"); ; + } + } + return _grpcServiceEntries; + } + + public GrpcServiceEntry CreateServiceEntry(Type service) + { + GrpcServiceEntry result = null; + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as IServiceBehavior; + if (behavior != null) + result = new GrpcServiceEntry + { + Behavior = behavior, + Type = behavior.GetType() + }; + return result; + } + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.Grpc/Surging.Core.Grpc.csproj b/src/Surging.Core/Surging.Core.Grpc/Surging.Core.Grpc.csproj new file mode 100644 index 000000000..a9530bf8c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Grpc/Surging.Core.Grpc.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Kestrel.Log4net/KestrelLog4netModule.cs b/src/Surging.Core/Surging.Core.Kestrel.Log4net/KestrelLog4netModule.cs new file mode 100644 index 000000000..01ef24233 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Kestrel.Log4net/KestrelLog4netModule.cs @@ -0,0 +1,45 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.KestrelHttpServer; +using Surging.Core.Log4net; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Kestrel.Log4net +{ + + public class KestrelLog4netModule : KestrelHttpModule + { + private string log4NetConfigFile = "${LogPath}|log4net.config"; + public override void Initialize(AppModuleContext context) + { + + } + + public override void RegisterBuilder(WebHostContext context) + { + } + + public override void Initialize(ApplicationInitializationContext context) + { + var serviceProvider = context.Builder.ApplicationServices; + base.Initialize(context); + var section = CPlatform.AppConfig.GetSection("Logging"); + log4NetConfigFile = EnvironmentHelper.GetEnvironmentVariable(log4NetConfigFile); + serviceProvider.GetService().AddProvider(new Log4NetProvider(log4NetConfigFile)); + } + + public override void RegisterBuilder(ConfigurationContext context) + { + context.Services.AddLogging(); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + + } + } +} diff --git a/src/Surging.Core/Surging.Core.Kestrel.Log4net/Surging.Core.Kestrel.Log4net.csproj b/src/Surging.Core/Surging.Core.Kestrel.Log4net/Surging.Core.Kestrel.Log4net.csproj new file mode 100644 index 000000000..3baee7a8e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Kestrel.Log4net/Surging.Core.Kestrel.Log4net.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Kestrel.Nlog/KestrelNLogModule.cs b/src/Surging.Core/Surging.Core.Kestrel.Nlog/KestrelNLogModule.cs new file mode 100644 index 000000000..b322c2e4c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Kestrel.Nlog/KestrelNLogModule.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.KestrelHttpServer; +using Surging.Core.Nlog; + + + +namespace Surging.Core.Kestrel.Nlog +{ + public class KestrelNLogModule : KestrelHttpModule + { + private string nlogConfigFile = "${LogPath}|NLog.config"; + public override void Initialize(AppModuleContext context) + { + + } + + public override void RegisterBuilder(WebHostContext context) + { + } + + public override void Initialize(ApplicationInitializationContext context) + { + var serviceProvider = context.Builder.ApplicationServices; + base.Initialize(context); + var section = AppConfig.GetSection("Logging"); + nlogConfigFile = EnvironmentHelper.GetEnvironmentVariable(nlogConfigFile); + + NLog.LogManager.LoadConfiguration(nlogConfigFile); + serviceProvider.GetService().AddProvider(new NLogProvider()); + } + + public override void RegisterBuilder(ConfigurationContext context) + { + context.Services.AddLogging(); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + + } + } +} diff --git a/src/Surging.Core/Surging.Core.Kestrel.Nlog/Surging.Core.Kestrel.Nlog.csproj b/src/Surging.Core/Surging.Core.Kestrel.Nlog/Surging.Core.Kestrel.Nlog.csproj new file mode 100644 index 000000000..249d51b9b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Kestrel.Nlog/Surging.Core.Kestrel.Nlog.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ActionContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ActionContext.cs new file mode 100644 index 000000000..55eac5bbf --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ActionContext.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Server; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer +{ + public class ActionContext + { + public ActionContext() + { + + } + + public HttpContext HttpContext { get; set; } + + public TransportMessage Message { get; set; } + + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ActionResult.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ActionResult.cs new file mode 100644 index 000000000..04e15f703 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ActionResult.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer +{ + public abstract class ActionResult: IActionResult + { + public virtual Task ExecuteResultAsync(ActionContext context) + { + ExecuteResult(context); + return Task.CompletedTask; + } + + + public virtual void ExecuteResult(ActionContext context) + { + } + } +} diff --git a/samples/OrgServer/Application.Interface.Org/DTO/EmployeePermission.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ContentResult.cs similarity index 55% rename from samples/OrgServer/Application.Interface.Org/DTO/EmployeePermission.cs rename to src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ContentResult.cs index 71978f5a5..db68d73bd 100644 --- a/samples/OrgServer/Application.Interface.Org/DTO/EmployeePermission.cs +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/ContentResult.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace Application.Interface.Org.DTO +namespace Surging.Core.KestrelHttpServer { - class EmployeePermission + class ContentResult { } } diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/FileContentResult.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/FileContentResult.cs new file mode 100644 index 000000000..86a04fa6d --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/FileContentResult.cs @@ -0,0 +1,90 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Net.Http.Headers; +using System.IO; +using Surging.Core.KestrelHttpServer.Internal; + +namespace Surging.Core.KestrelHttpServer +{ + public class FileContentResult : FileResult + { + private byte[] _fileContents; + protected const int BufferSize = 64 * 1024; + + public FileContentResult(byte[] fileContents, string contentType) + : this(fileContents, MediaTypeHeaderValue.Parse(contentType)) + { + if (fileContents == null) + { + throw new ArgumentNullException(nameof(fileContents)); + } + } + + public FileContentResult(byte[] fileContents, string contentType,string fileDownloadName) + : this(fileContents, MediaTypeHeaderValue.Parse(contentType)) + { + if (fileContents == null) + { + throw new ArgumentNullException(nameof(fileContents)); + } + if (fileDownloadName == null) + { + throw new ArgumentNullException(nameof(fileDownloadName)); + } + this.FileDownloadName = fileDownloadName; + } + + public FileContentResult(byte[] fileContents, MediaTypeHeaderValue contentType) + : base(contentType?.ToString()) + { + if (fileContents == null) + { + throw new ArgumentNullException(nameof(fileContents)); + } + + FileContents = fileContents; + } + + public byte[] FileContents + { + get => _fileContents; + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _fileContents = value; + } + } + + public override async Task ExecuteResultAsync(ActionContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + try + { + var contentDisposition = new ContentDispositionHeaderValue("attachment"); + contentDisposition.SetHttpFileName(FileDownloadName); + var httpResponse = context.HttpContext.Response; + + httpResponse.Headers.Add("Content-Type", this.ContentType); + httpResponse.Headers.Add("Content-Length", FileContents.Length.ToString()); + httpResponse.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString(); + using (var stream = new MemoryStream(FileContents)) + await StreamCopyOperation.CopyToAsync(stream, httpResponse.Body, count: null, bufferSize: BufferSize, cancel: context.HttpContext.RequestAborted); + } + catch (OperationCanceledException) + { + context.HttpContext.Abort(); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/FileResult.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/FileResult.cs new file mode 100644 index 000000000..0f1a74a5f --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/FileResult.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer +{ + public abstract class FileResult: ActionResult + { + private string _fileDownloadName; + + protected FileResult(string contentType) + { + if (contentType == null) + { + throw new ArgumentNullException(nameof(contentType)); + } + + ContentType = contentType; + } + + public string ContentType { get; } + + + public string FileDownloadName + { + get { return _fileDownloadName ?? string.Empty; } + set { _fileDownloadName = value; } + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/IActionResult.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/IActionResult.cs new file mode 100644 index 000000000..ced3e7bbd --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Abstractions/IActionResult.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer +{ + public interface IActionResult + { + Task ExecuteResultAsync(ActionContext context); + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/ApplicationInitializationContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/ApplicationInitializationContext.cs new file mode 100644 index 000000000..2eebb8ed7 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/ApplicationInitializationContext.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer +{ + public class ApplicationInitializationContext + { + public ApplicationInitializationContext(IApplicationBuilder builder, + List modules, + string[] virtualPaths, + IConfigurationRoot configuration) + { + Builder = Check.NotNull(builder, nameof(builder)); + Modules = Check.NotNull(modules, nameof(modules)); + VirtualPaths = Check.NotNull(virtualPaths, nameof(virtualPaths)); + Configuration = Check.NotNull(configuration, nameof(configuration)); + } + + public IApplicationBuilder Builder { get; } + + public IConfigurationRoot Configuration { get; } + + public List Modules { get; } + + public string[] VirtualPaths { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/ConfigurationContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/ConfigurationContext.cs new file mode 100644 index 000000000..0132a761f --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/ConfigurationContext.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer +{ + public class ConfigurationContext + { + public ConfigurationContext( IServiceCollection services, + List modules, + string[] virtualPaths, + IConfigurationRoot configuration) + { + Services = Check.NotNull(services, nameof(services)); + Modules = Check.NotNull(modules, nameof(modules)); + VirtualPaths = Check.NotNull(virtualPaths, nameof(virtualPaths)); + Configuration = Check.NotNull(configuration, nameof(configuration)); + } + + public IConfigurationRoot Configuration { get; } + public IServiceCollection Services { get; } + + public List Modules { get; } + + public string[] VirtualPaths { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/DefaultHttpServiceHost.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/DefaultHttpServiceHost.cs new file mode 100644 index 000000000..ac4994520 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/DefaultHttpServiceHost.cs @@ -0,0 +1,61 @@ +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer +{ + public class DefaultHttpServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public DefaultHttpServiceHost(Func> messageListenerFactory, IServiceExecutor serviceExecutor, HttpMessageListener httpMessageListener) : base(serviceExecutor) + { + _messageListenerFactory = messageListenerFactory; + _serverMessageListener = httpMessageListener; + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + #region Overrides of ServiceHostAbstract + + + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + await _messageListenerFactory(endPoint); + } + + public override async Task StartAsync(string ip, int port) + { + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), port)); + } + + #endregion Overrides of ServiceHostAbstract + + private async Task MessageListener_Received(IMessageSender sender, CPlatform.Messages.TransportMessage message) + { + await ServiceExecutor.ExecuteAsync(sender, message); + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Diagnostics/RestTransportCarrierHeaderCollection.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Diagnostics/RestTransportCarrierHeaderCollection.cs new file mode 100644 index 000000000..5b1bad360 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Diagnostics/RestTransportCarrierHeaderCollection.cs @@ -0,0 +1,33 @@ +using Surging.Core.CPlatform.Diagnostics; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Diagnostics +{ + public class RestTransportCarrierHeaderCollection : ICarrierHeaderCollection + { + private readonly TracingHeaders _tracingHeaders; + + public RestTransportCarrierHeaderCollection(TracingHeaders tracingHeaders) + { + _tracingHeaders = tracingHeaders; + } + + public IEnumerator> GetEnumerator() + { + return _tracingHeaders.GetEnumerator(); + } + + public void Add(string key, string value) + { + _tracingHeaders.Add(key, value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _tracingHeaders.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Diagnostics/RestTransportDiagnosticProcessor.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Diagnostics/RestTransportDiagnosticProcessor.cs new file mode 100644 index 000000000..2383f0755 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Diagnostics/RestTransportDiagnosticProcessor.cs @@ -0,0 +1,94 @@ +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Concurrent; +using System.Text; +using SurgingEvents = Surging.Core.CPlatform.Diagnostics.DiagnosticListenerExtensions; + +namespace Surging.Core.KestrelHttpServer.Diagnostics +{ + public class RestTransportDiagnosticProcessor : ITracingDiagnosticProcessor + { + private Func _transportOperationNameResolver; + public string ListenerName => SurgingEvents.DiagnosticListenerName; + + + private readonly ConcurrentDictionary _resultDictionary = + new ConcurrentDictionary(); + + private readonly ISerializer _serializer; + private readonly ITracingContext _tracingContext; + + public Func TransportOperationNameResolver + { + get + { + return _transportOperationNameResolver ?? + (_transportOperationNameResolver = (data) => "Rest-Transport:: " + data.Message.MessageName); + } + set => _transportOperationNameResolver = + value ?? throw new ArgumentNullException(nameof(TransportOperationNameResolver)); + } + + public RestTransportDiagnosticProcessor(ITracingContext tracingContext,ISerializer serializer) + { + _tracingContext = tracingContext; + _serializer = serializer; + } + + [DiagnosticName(SurgingEvents.SurgingBeforeTransport, TransportType.Rest)] + public void TransportBefore([Object] TransportEventData eventData) + { + var message = eventData.Message.GetContent(); + var operationName = TransportOperationNameResolver(eventData); + var context = _tracingContext.CreateEntrySegmentContext(operationName, + new RestTransportCarrierHeaderCollection(eventData.Headers)); + context.TraceId = ConvertUniqueId(eventData); + context.Span.AddLog(LogEvent.Message($"Worker running at: {DateTime.Now}")); + context.Span.SpanLayer = SpanLayer.HTTP; + context.Span.Peer = new StringOrIntValue(eventData.RemoteAddress); + context.Span.AddTag(Tags.REST_METHOD, eventData.Method.ToString()); + context.Span.AddTag(Tags.REST_PARAMETERS, _serializer.Serialize(message.Parameters)); + context.Span.AddTag(Tags.REST_LOCAL_ADDRESS, NetUtils.GetHostAddress().ToString()); + _resultDictionary.TryAdd(eventData.OperationId.ToString(), context); + } + + [DiagnosticName(SurgingEvents.SurgingAfterTransport, TransportType.Rest)] + public void TransportAfter([Object] ReceiveEventData eventData) + { + _resultDictionary.TryRemove(eventData.OperationId.ToString(), out SegmentContext context); + if (context != null) + { + _tracingContext.Release(context); + } + } + + [DiagnosticName(SurgingEvents.SurgingErrorTransport, TransportType.Rest)] + public void TransportError([Object] TransportErrorEventData eventData) + { + _resultDictionary.TryRemove(eventData.OperationId.ToString(), out SegmentContext context); + if (context != null) + { + context.Span.ErrorOccurred(eventData.Exception); + _tracingContext.Release(context); + } + } + + public UniqueId ConvertUniqueId(TransportEventData eventData) + { + long part1 = 0, part2 = 0, part3 = 0; + UniqueId uniqueId = new UniqueId(); + var bytes = Encoding.Default.GetBytes(eventData.TraceId); + part1 = BitConverter.ToInt64(bytes, 0); + if (eventData.TraceId.Length > 8) + part2 = BitConverter.ToInt64(bytes, 8); + if (eventData.TraceId.Length > 16) + part3 = BitConverter.ToInt64(bytes, 16); + if (!string.IsNullOrEmpty(eventData.TraceId)) + uniqueId = new UniqueId(part1, part2, part3); + return uniqueId; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Extensions/ModuleProviderExtensions.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Extensions/ModuleProviderExtensions.cs new file mode 100644 index 000000000..6ba357311 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Extensions/ModuleProviderExtensions.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Surging.Core.CPlatform.Module; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Extensions +{ + public static class ModuleProviderExtensions + { + public static void Initialize(this IModuleProvider moduleProvider, ApplicationInitializationContext builder) + { + moduleProvider.Modules.ForEach(p => + { + try + { + using (var abstractModule = p) + if (abstractModule.Enable) + { + var module = abstractModule as KestrelHttpModule; + module?.Initialize(builder); + } + } + catch (Exception ex) + { + throw ex; + } + }); + } + + public static void ConfigureServices(this IModuleProvider moduleProvider, ConfigurationContext context) + { + moduleProvider.Modules.ForEach(p => + { + try + { + if (p.Enable) + { + var module = p as KestrelHttpModule; + module?.RegisterBuilder(context); + } + } + catch (Exception ex) + { + throw ex; + } + }); + } + + public static void ConfigureHost(this IModuleProvider moduleProvider, WebHostContext context) + { + moduleProvider.Modules.ForEach(p => + { + try + { + if (p.Enable) + { + var module = p as KestrelHttpModule; + module?.RegisterBuilder(context); + } + } + catch (Exception ex) + { + throw ex; + } + }); + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Extensions/ServiceCollectionExtensions.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..1020bf985 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.DependencyInjection; +using Surging.Core.KestrelHttpServer.Filters; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Extensions +{ + public static class ServiceCollectionExtensions + { + public static void AddFilters(this IServiceCollection serviceCollection, Type filter) + { + if (typeof(IAuthorizationFilter).IsAssignableFrom(filter)) + { + serviceCollection.AddSingleton(typeof(IAuthorizationFilter), filter); + } + else if (typeof(IActionFilter).IsAssignableFrom(filter)) + { + serviceCollection.AddSingleton(typeof(IActionFilter), filter); + } + else if (typeof(IExceptionFilter).IsAssignableFrom(filter)) + { + serviceCollection.AddSingleton(typeof(IExceptionFilter), filter); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IActionFilter.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IActionFilter.cs new file mode 100644 index 000000000..4660218f6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IActionFilter.cs @@ -0,0 +1,15 @@ +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer.Filters +{ + public interface IActionFilter + { + Task OnActionExecuting(ActionExecutingContext filterContext); + + Task OnActionExecuted(ActionExecutedContext filterContext); + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IAuthorizationFilter.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IAuthorizationFilter.cs new file mode 100644 index 000000000..c4c92611b --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IAuthorizationFilter.cs @@ -0,0 +1,11 @@ + +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer.Filters +{ + public interface IAuthorizationFilter : IFilter + { + Task OnAuthorization(AuthorizationFilterContext serviceRouteContext); + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IExceptionFilter.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IExceptionFilter.cs new file mode 100644 index 000000000..0cecb7465 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IExceptionFilter.cs @@ -0,0 +1,13 @@ +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer.Filters +{ + public interface IExceptionFilter + { + Task OnException(ExceptionContext context); + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IFilter.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IFilter.cs new file mode 100644 index 000000000..b885d10cc --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/IFilter.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Filters +{ + public interface IFilter + { + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ActionExecutedContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ActionExecutedContext.cs new file mode 100644 index 000000000..df1e2b5a2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ActionExecutedContext.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class ActionExecutedContext + { + public HttpMessage Message { get; internal set; } + public HttpResultMessage ResultMessage { get; internal set; } + public HttpContext Context { get; internal set; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ActionExecutingContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ActionExecutingContext.cs new file mode 100644 index 000000000..3012134aa --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ActionExecutingContext.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Routing; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class ActionExecutingContext + { + public HttpMessage Message { get; internal set; } + + public ServiceRoute Route { get; internal set; } + + public HttpResultMessage Result { get; set; } + + public HttpContext Context { get; internal set; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/AuthorizationFilterContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/AuthorizationFilterContext.cs new file mode 100644 index 000000000..68304cc33 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/AuthorizationFilterContext.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Routing; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class AuthorizationFilterContext + { + public ServiceRoute Route { get; internal set; } + + public string Path { get; set; } + + public HttpResultMessage Result { get; set; } + + public HttpContext Context { get; internal set; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/CustomerExceptionFilterAttribute.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/CustomerExceptionFilterAttribute.cs new file mode 100644 index 000000000..1456f8eec --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/CustomerExceptionFilterAttribute.cs @@ -0,0 +1,23 @@ +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class CustomerExceptionFilterAttribute : IExceptionFilter + { + public Task OnException(ExceptionContext context) + { + context.Result = new HttpResultMessage + { + Entity = null, + StatusCode = 400, + IsSucceed = false, + Message = context.Exception.Message + }; + return Task.CompletedTask; + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ExceptionContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ExceptionContext.cs new file mode 100644 index 000000000..422c817f0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ExceptionContext.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class ExceptionContext + { + public string RoutePath { get; internal set; } + + public Exception Exception { get; internal set; } + + public HttpResultMessage Result { get; set; } + + public HttpContext Context { get; internal set; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/HttpRequestFilterAttribute.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/HttpRequestFilterAttribute.cs new file mode 100644 index 000000000..12f2f612e --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/HttpRequestFilterAttribute.cs @@ -0,0 +1,64 @@ +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Runtime.Server; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.Linq; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Utilities; +using Autofac; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class HttpRequestFilterAttribute : IActionFilter + { + internal const string Http405EndpointDisplayName = "405 HTTP Method Not Supported"; + internal const int Http405EndpointStatusCode = 405; + private readonly IServiceRouteProvider _serviceRouteProvider; + private readonly IServiceEntryLocate _serviceEntryLocate; + public HttpRequestFilterAttribute() + { + _serviceRouteProvider = ServiceLocator.Current.Resolve(); ; + _serviceEntryLocate = ServiceLocator.Current.Resolve(); ; + } + public Task OnActionExecuted(ActionExecutedContext filterContext) + { + return Task.CompletedTask; + } + + public async Task OnActionExecuting(ActionExecutingContext filterContext) + { + var serviceEntry= _serviceEntryLocate.Locate(filterContext.Message); + if (serviceEntry != null) + { + var httpMethods = serviceEntry.Methods; + if (httpMethods.Count()>0 && !httpMethods.Any(p => String.Compare(p, filterContext.Context.Request.Method, true) == 0)) + { + filterContext.Result = new HttpResultMessage + { + IsSucceed = false, + StatusCode = Http405EndpointStatusCode, + Message = Http405EndpointDisplayName + }; + } + } + else + { + var serviceRoute = await _serviceRouteProvider.GetRouteByPath(filterContext.Message.RoutePath); + var httpMethods = serviceRoute.ServiceDescriptor.HttpMethod(); + if (!string.IsNullOrEmpty(httpMethods) && !httpMethods.Contains(filterContext.Context.Request.Method)) + { + filterContext.Result = new HttpResultMessage + { + IsSucceed = false, + StatusCode = Http405EndpointStatusCode, + Message = Http405EndpointDisplayName + }; + } + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ServiceExceptionFilter.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ServiceExceptionFilter.cs new file mode 100644 index 000000000..68a5ce05f --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Filters/Implementation/ServiceExceptionFilter.cs @@ -0,0 +1,16 @@ +using Surging.Core.CPlatform.Exceptions; +using Surging.Core.CPlatform.Filters.Implementation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Filters.Implementation +{ + public class ServiceExceptionFilter : ExceptionFilterAttribute + { + public override void OnException(RpcActionExecutedContext context) + { + throw new Exception(context.Exception.Message, context.Exception); + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpExecutor.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpExecutor.cs new file mode 100644 index 000000000..c6b77585b --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpExecutor.cs @@ -0,0 +1,233 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Convertibles; +using Surging.Core.CPlatform.Filters; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.ProxyGenerator; +using System; +using System.Linq; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static Surging.Core.CPlatform.Utilities.FastInvoke; +using System.Diagnostics; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Exceptions; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.KestrelHttpServer.Internal; +using Newtonsoft.Json; + +namespace Surging.Core.KestrelHttpServer +{ + public class HttpExecutor : IServiceExecutor + { + #region Field + private readonly IServiceEntryLocate _serviceEntryLocate; + private readonly ILogger _logger; + private readonly IServiceRouteProvider _serviceRouteProvider; + private readonly IAuthorizationFilter _authorizationFilter; + private readonly CPlatformContainer _serviceProvider; + private readonly ITypeConvertibleService _typeConvertibleService; + private readonly IServiceProxyProvider _serviceProxyProvider; + private readonly ConcurrentDictionary> _concurrent = + new ConcurrentDictionary>(); + private readonly DiagnosticListener _diagnosticListener; + #endregion Field + + #region Constructor + + public HttpExecutor(IServiceEntryLocate serviceEntryLocate, IServiceRouteProvider serviceRouteProvider, + IAuthorizationFilter authorizationFilter, + ILogger logger, CPlatformContainer serviceProvider, IServiceProxyProvider serviceProxyProvider, ITypeConvertibleService typeConvertibleService) + { + _serviceEntryLocate = serviceEntryLocate; + _logger = logger; + _serviceProvider = serviceProvider; + _typeConvertibleService = typeConvertibleService; + _serviceRouteProvider = serviceRouteProvider; + _authorizationFilter = authorizationFilter; + _serviceProxyProvider = serviceProxyProvider; + _diagnosticListener = new DiagnosticListener(DiagnosticListenerExtensions.DiagnosticListenerName); + } + #endregion Constructor + + #region Implementation of IExecutor + + public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) + { + if (_logger.IsEnabled(LogLevel.Trace)) + _logger.LogTrace("服务提供者接收到消息。"); + + if (!message.IsHttpMessage()) + return; + HttpMessage httpMessage; + try + { + httpMessage = message.GetContent(); + } + catch (Exception exception) + { + _logger.LogError(exception, "将接收到的消息反序列化成 TransportMessage 时发送了错误。"); + return; + } + if (httpMessage.Attachments != null) + { + foreach (var attachment in httpMessage.Attachments) + RpcContext.GetContext().SetAttachment(attachment.Key, attachment.Value); + } + WirteDiagnosticBefore(message); + var entry = _serviceEntryLocate.Locate(httpMessage); + + HttpResultMessage httpResultMessage = new HttpResultMessage() { }; + + if (entry!=null && _serviceProvider.IsRegisteredWithKey(httpMessage.ServiceKey, entry.Type)) + { + //执行本地代码。 + httpResultMessage = await LocalExecuteAsync(entry, httpMessage); + } + else + { + httpResultMessage = await RemoteExecuteAsync(httpMessage); + } + await SendRemoteInvokeResult(sender,message.Id, httpResultMessage); + } + + + #endregion Implementation of IServiceExecutor + + #region Private Method + + private async Task> RemoteExecuteAsync(HttpMessage httpMessage) + { + HttpResultMessage resultMessage = new HttpResultMessage(); + try + { + var entity = await _serviceProxyProvider.Invoke(httpMessage.Parameters, httpMessage.RoutePath, httpMessage.ServiceKey); + if (entity != null && AppConfig.ServerOptions.EnableObjectConvert) + entity = JsonConvert.DeserializeObject(entity.ToString(), typeof(Object)); + resultMessage.Entity = entity; + resultMessage.IsSucceed = resultMessage.Entity != default; + resultMessage.StatusCode = resultMessage.IsSucceed ? (int)StatusCode.Success : (int)StatusCode.RequestError; + } + catch (Exception ex) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(ex, "执行远程调用逻辑时候发生了错误。"); + resultMessage = new HttpResultMessage { Entity = null, Message = "执行发生了错误。", StatusCode = (int)StatusCode.RequestError }; + } + return resultMessage; + } + + private async Task> LocalExecuteAsync(ServiceEntry entry, HttpMessage httpMessage) + { + HttpResultMessage resultMessage = new HttpResultMessage(); + try + { + var result = await entry.Func(httpMessage.ServiceKey, httpMessage.Parameters); + var task = result as Task; + + if (task == null) + { + resultMessage.Entity = result; + } + else + { + task.Wait(); + var taskType = task.GetType().GetTypeInfo(); + if (taskType.IsGenericType) + resultMessage.Entity = taskType.GetProperty("Result").GetValue(task); + } + + resultMessage.IsSucceed = resultMessage.Entity != null; + resultMessage.StatusCode = + resultMessage.IsSucceed ? (int) StatusCode.Success : (int) StatusCode.RequestError; + } + catch (ValidateException validateException) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(validateException, "执行本地逻辑时候发生了错误。", validateException); + + resultMessage.Message = validateException.Message; + resultMessage.StatusCode = validateException.HResult; + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "执行本地逻辑时候发生了错误。"); + resultMessage.Message = "执行发生了错误。"; + resultMessage.StatusCode = exception.HResult; + } + return resultMessage; + } + + private async Task SendRemoteInvokeResult(IMessageSender sender,string messageId, HttpResultMessage resultMessage) + { + try + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("准备发送响应消息。"); + + await sender.SendAndFlushAsync(new TransportMessage(messageId,resultMessage)); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("响应消息发送成功。"); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "发送响应消息时候发生了异常。"); + } + finally + { + RpcContext.RemoveContext(); + } + } + + private static string GetExceptionMessage(Exception exception) + { + if (exception == null) + return string.Empty; + + var message = exception.Message; + if (exception.InnerException != null) + { + message += "|InnerException:" + GetExceptionMessage(exception.InnerException); + } + return message; + } + + private void WirteDiagnosticBefore(TransportMessage message) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + RpcContext.GetContext().SetAttachment("TraceId", message.Id); + var remoteInvokeMessage = message.GetContent(); + _diagnosticListener.WriteTransportBefore(TransportType.Rest, new TransportEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id, + MessageName = remoteInvokeMessage.RoutePath + }, TransportType.Rest.ToString(), + message.Id, + RestContext.GetContext().GetAttachment("RemoteIpAddress")?.ToString())); + } + else + { + var parameters = RpcContext.GetContext().GetContextParameters(); + RpcContext.GetContext().SetContextParameters(parameters); + } + + } + + #endregion Private Method + + } +} + diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpMessageListener.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpMessageListener.cs new file mode 100644 index 000000000..544dbcafe --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpMessageListener.cs @@ -0,0 +1,305 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using Surging.Core.KestrelHttpServer.Internal; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; +using System.Web; + +namespace Surging.Core.KestrelHttpServer +{ + public abstract class HttpMessageListener : IMessageListener + { + public event ReceivedDelegate Received; + private readonly ILogger _logger; + private readonly ISerializer _serializer; + private event RequestDelegate Requested; + private readonly IServiceRouteProvider _serviceRouteProvider; + private readonly string[] _serviceKeys = { "serviceKey", "servicekey"}; + + public HttpMessageListener(ILogger logger, ISerializer serializer, IServiceRouteProvider serviceRouteProvider) + { + _logger = logger; + _serializer = serializer; + _serviceRouteProvider = serviceRouteProvider; + } + + public async Task OnReceived(IMessageSender sender, TransportMessage message) + { + if (Received == null) + return; + await Received(sender, message); + } + + public async Task OnReceived(IMessageSender sender,string messageId, HttpContext context, IEnumerable actionFilters, ReplaySubject> subject) + { + var serviceRoute = RestContext.GetContext().GetAttachment("route") as ServiceRoute; + RestContext.GetContext().RemoveContextParameters("route"); + var path = (RestContext.GetContext().GetAttachment("path") + ?? HttpUtility.UrlDecode(GetRoutePath(context.Request.Path.ToString()))) as string; + if (serviceRoute == null) + { + serviceRoute = await _serviceRouteProvider.GetRouteByPathRegex(path); + } + IDictionary parameters = context.Request.Query.ToDictionary(p => p.Key, p => (object)p.Value.ToString()); + object serviceKey = null; + foreach (var key in _serviceKeys) + { + parameters.Remove(key, out object value); + if (value != null) + { + serviceKey = value; + break; + } + } + + if (String.Compare(serviceRoute.ServiceDescriptor.RoutePath, path, true) != 0) + { + var @params = RouteTemplateSegmenter.Segment(serviceRoute.ServiceDescriptor.RoutePath, path); + foreach (var param in @params) + { + parameters.Add(param.Key, param.Value); + } + } + var httpMessage = new HttpMessage + { + Parameters = parameters, + RoutePath = serviceRoute.ServiceDescriptor.RoutePath, + ServiceKey = serviceKey?.ToString() + }; + + if (context.Request.HasFormContentType) + { + var collection = await GetFormCollection(context.Request); + foreach (var item in collection) + { + httpMessage.Parameters.Add(item.Key, item.Value); + } + if (!await OnActionExecuting(new ActionExecutingContext { Context = context, Route = serviceRoute, Message = httpMessage }, + sender, messageId, actionFilters)) return; + httpMessage.Attachments = RestContext.GetContext().GetContextParameters(); + await Received(sender, new TransportMessage(messageId,httpMessage)); + } + else + { + StreamReader streamReader = new StreamReader(context.Request.Body); + var data = await streamReader.ReadToEndAsync(); + if (context.Request.Method == "POST") + { + var bodyParams = _serializer.Deserialize>(data) ?? new Dictionary(); + foreach (var param in bodyParams) + httpMessage.Parameters.Add(param.Key, param.Value); + if (!await OnActionExecuting(new ActionExecutingContext { Context = context, Route = serviceRoute, Message = httpMessage }, + sender, messageId, actionFilters)) return; + httpMessage.Attachments = RestContext.GetContext().GetContextParameters(); + await Received(sender, new TransportMessage(messageId,httpMessage)); + } + else + { + if (!await OnActionExecuting(new ActionExecutingContext { Context = context, Route = serviceRoute, Message = httpMessage }, + sender, messageId, actionFilters)) return; + httpMessage.Attachments = RestContext.GetContext().GetContextParameters(); + await Received(sender, new TransportMessage(messageId,httpMessage)); + } + } + + subject.Subscribe(async (message) => + { + await OnActionExecuted(context, httpMessage, message, actionFilters); + }); + } + + public async Task OnActionExecuting(ActionExecutingContext filterContext, IMessageSender sender, string messageId, IEnumerable filters) + { + foreach (var fiter in filters) + { + await fiter.OnActionExecuting(filterContext); + if (filterContext.Result != null) + { + await sender.SendAndFlushAsync(new TransportMessage(messageId,filterContext.Result)); + return false; + } + } + return true; + } + + public async Task OnActionExecuted(HttpContext context, HttpMessage message, HttpResultMessage resultMessage, IEnumerable filters) + { + foreach (var fiter in filters) + { + var filterContext = new ActionExecutedContext() + { + Context = context, + ResultMessage = resultMessage, + Message = message + }; + await fiter.OnActionExecuted(filterContext); + } + } + + public async Task OnAuthorization(HttpContext context, HttpServerMessageSender sender,string messageId, IEnumerable filters) + { + foreach (var filter in filters) + { + var path = HttpUtility.UrlDecode(GetRoutePath(context.Request.Path.ToString())); + var serviceRoute = await _serviceRouteProvider.GetRouteByPathRegex(path); + if (serviceRoute == null) serviceRoute = await _serviceRouteProvider.GetLocalRouteByPathRegex(path); + RestContext.GetContext().SetAttachment("route", serviceRoute); + var filterContext = new AuthorizationFilterContext + { + Path = path, + Context = context, + Route = serviceRoute + }; + await filter.OnAuthorization(filterContext); + if (filterContext.Result != null) + { + await sender.SendAndFlushAsync(new TransportMessage(messageId,filterContext.Result)); + return false; + } + } + return true; + } + + public async Task OnException(HttpContext context, HttpServerMessageSender sender, string messageId, Exception exception, IEnumerable filters) + { + foreach (var filter in filters) + { + var path = HttpUtility.UrlDecode(GetRoutePath(context.Request.Path.ToString())); + var filterContext = new ExceptionContext + { + RoutePath = path, + Context = context, + Exception = exception + }; + await filter.OnException(filterContext); + if (filterContext.Result != null) + { + await sender.SendAndFlushAsync(new TransportMessage(messageId, filterContext.Result)); + return false; + } + } + return true; + } + + private async Task> GetFormCollection(HttpRequest request) + { + var boundary = GetName("boundary=", request.ContentType); + var reader = new MultipartReader(boundary, request.Body); + var collection = await GetMultipartForm(reader); + + return collection.ToDictionary(item => item.Key, item => + { + var fieldsDict = new Dictionary(); + if (item.Value.Fields.HasValue) + { + fieldsDict.Add(item.Key, item.Value.Fields.Value); + } + + return new HttpFormCollection(fieldsDict, item.Value.HttpFormFileCollection); + }); + } + + private async Task> GetMultipartForm(MultipartReader reader) + { + var section = await reader.ReadNextSectionAsync(); + var collection = new Dictionary(); + if (section != null) + { + var name = GetName("name=", section.ContentDisposition); + var fileName = GetName("filename=", section.ContentDisposition); + var buffer = new MemoryStream(); + await section.Body.CopyToAsync(buffer); + if (string.IsNullOrEmpty(fileName)) + { + var fields = new Dictionary(); + StreamReader streamReader = new StreamReader(buffer); + fields.Add(name, new StringValues(Encoding.Default.GetString(buffer.GetBuffer(), 0, (int)buffer.Length))); + collection.Add(name, (fields[name], null)); + } + else + { + var fileCollection = new HttpFormFileCollection(); + StreamReader streamReader = new StreamReader(buffer); + fileCollection.Add(new HttpFormFile(buffer.Length, name, fileName, buffer.GetBuffer())); + collection.Add(name, (null, fileCollection)); + } + var formCollection = await GetMultipartForm(reader); + foreach (var item in formCollection) + { + if (!collection.ContainsKey(item.Key)) + collection.Add(item.Key, item.Value); + else + { + var (fields, httpFormFileCollection) = collection[item.Key]; + if (item.Value.Fields.HasValue && !fields.HasValue) + { + fields = item.Value.Fields.Value; + } + + if (httpFormFileCollection == null) + { + httpFormFileCollection = item.Value.HttpFormFileCollection; + } + else + { + var formFiles = + item.Value.HttpFormFileCollection.Where(v => + !httpFormFileCollection.Exists(p => p.FileName == v.FileName)); + httpFormFileCollection.AddRange(formFiles); + } + + collection[item.Key] = (fields, httpFormFileCollection); + } + } + } + return collection; + } + + private string GetName(string type,string content) + { + var elements = content.Split(';'); + var element = elements.Where(entry => entry.Trim().StartsWith(type)).FirstOrDefault()?.Trim(); + var name = element?.Substring(type.Length); + if (!string.IsNullOrEmpty(name) && name.Length >= 2 && name[0] == '"' && name[name.Length - 1] == '"') + { + name = name.Substring(1, name.Length - 2); + } + return name; + } + + private string GetRoutePath(string path) + { + string routePath = ""; + var urlSpan = path.AsSpan(); + var len = urlSpan.IndexOf("?"); + if (urlSpan.LastIndexOf("/") == 0) + { + routePath = path; + } + else + { + if (len == -1) + routePath = urlSpan.TrimStart("/").ToString().ToLower(); + else + routePath = urlSpan.Slice(0, len).TrimStart("/").ToString().ToLower(); + } + return routePath; + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpServerMessageSender.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpServerMessageSender.cs new file mode 100644 index 000000000..6771fee49 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpServerMessageSender.cs @@ -0,0 +1,96 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Implementation; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer +{ + public class HttpServerMessageSender : IMessageSender + { + private readonly ISerializer _serializer; + private readonly HttpContext _context; + private readonly DiagnosticListener _diagnosticListener; + private readonly ReplaySubject> _subject = null; + public HttpServerMessageSender(ISerializer serializer,HttpContext httpContext) + { + _serializer = serializer; + _context = httpContext; + _diagnosticListener = new DiagnosticListener(DiagnosticListenerExtensions.DiagnosticListenerName); + } + + internal HttpServerMessageSender(ISerializer serializer, HttpContext httpContext, DiagnosticListener diagnosticListener, ReplaySubject> subject) + { + _serializer = serializer; + _context = httpContext; + _diagnosticListener = diagnosticListener; + _subject = subject; + } + + public async Task SendAndFlushAsync(TransportMessage message) + { + var httpMessage = message.GetContent>(); + var actionResult= httpMessage.Entity as IActionResult; + WirteDiagnostic(message); + if (actionResult == null) + { + var text = _serializer.Serialize(message.Content); + var data = Encoding.UTF8.GetBytes(text); + var contentLength = data.Length; + _context.Response.Headers.Add("Content-Type", "application/json;charset=utf-8"); + _context.Response.Headers.Add("Content-Length", contentLength.ToString()); + await _context.Response.WriteAsync(text); + } + else + { + await actionResult.ExecuteResultAsync(new ActionContext + { + HttpContext = _context, + Message = message + }); + } + if (_subject != null) + _subject.OnNext(httpMessage); + } + + public async Task SendAsync(TransportMessage message) + { + await this.SendAndFlushAsync(message); + } + + private void WirteDiagnostic(TransportMessage message) + { + if (!CPlatform.AppConfig.ServerOptions.DisableDiagnostic) + { + + var remoteInvokeResultMessage = message.GetContent(); + if (remoteInvokeResultMessage.IsSucceed) + { + _diagnosticListener.WriteTransportAfter(TransportType.Rest, new ReceiveEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id + })); + } + else + { + _diagnosticListener.WriteTransportError(TransportType.Rest, new TransportErrorEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id + }, new Exception(remoteInvokeResultMessage.Message))); + } + } + } + + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpServiceHost.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpServiceHost.cs new file mode 100644 index 000000000..ab93ffb2a --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/HttpServiceHost.cs @@ -0,0 +1,63 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer +{ + public class HttpServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public HttpServiceHost(Func> messageListenerFactory, IServiceExecutor serviceExecutor, HttpMessageListener httpMessageListener) : base(serviceExecutor) + { + _messageListenerFactory = messageListenerFactory; + _serverMessageListener = httpMessageListener; + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + #region Overrides of ServiceHostAbstract + + + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + await _messageListenerFactory(endPoint); + } + + public override async Task StartAsync(string ip, int port) + { + await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.HttpPort??0)); + } + + #endregion Overrides of ServiceHostAbstract + + private async Task MessageListener_Received(IMessageSender sender, TransportMessage message) + { + await ServiceExecutor.ExecuteAsync(sender, message); + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/DateTimeConverter.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/DateTimeConverter.cs new file mode 100644 index 000000000..f0d3ae93c --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/DateTimeConverter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + public class DateTimeNullConverter : JsonConverter + { + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => string.IsNullOrEmpty(reader.GetString()) ? default(DateTime?) : DateTime.Parse(reader.GetString()); + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + => writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm")); + } + + public class DateTimeConverter : JsonConverter + { + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => DateTime.Parse(reader.GetString()); + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm")); + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/FileStreamResult.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/FileStreamResult.cs new file mode 100644 index 000000000..f331d1431 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/FileStreamResult.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http.Headers; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + public class FileStreamResult : FileResult + { + private Stream _fileStream; + + public FileStreamResult(Stream fileStream, string contentType) + : this(fileStream, MediaTypeHeaderValue.Parse(contentType)) + { + } + + public FileStreamResult(Stream fileStream, MediaTypeHeaderValue contentType) + : base(contentType?.ToString()) + { + if (fileStream == null) + { + throw new ArgumentNullException(nameof(fileStream)); + } + + FileStream = fileStream; + } + + public Stream FileStream + { + get => _fileStream; + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _fileStream = value; + } + } + + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormCollection.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormCollection.cs new file mode 100644 index 000000000..09ff41719 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormCollection.cs @@ -0,0 +1,183 @@ +using Microsoft.Extensions.Primitives; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + public class HttpFormCollection : IEnumerable>, IEnumerable + { + public static readonly HttpFormCollection Empty = new HttpFormCollection(); + private static readonly string[] EmptyKeys = Array.Empty(); + private static readonly StringValues[] EmptyValues = Array.Empty(); + private static readonly Enumerator EmptyEnumerator = new Enumerator(); + private static readonly IEnumerator> EmptyIEnumeratorType = EmptyEnumerator; + private static readonly IEnumerator EmptyIEnumerator = EmptyEnumerator; + + private static HttpFormFileCollection EmptyFiles = new HttpFormFileCollection(); + + private HttpFormFileCollection _files; + + private HttpFormCollection() + { + } + + public HttpFormCollection(Dictionary fields, HttpFormFileCollection files = null) + { + Store = fields; + _files = files; + } + + public HttpFormFileCollection Files + { + get + { + return _files ?? EmptyFiles; + } + private set { _files = value; } + } + + private Dictionary Store { get; set; } + + + public StringValues this[string key] + { + get + { + if (Store == null) + { + return StringValues.Empty; + } + + StringValues value; + if (TryGetValue(key, out value)) + { + return value; + } + return StringValues.Empty; + } + } + + + public int Count + { + get + { + return Store?.Count ?? 0; + } + } + + public ICollection Keys + { + get + { + if (Store == null) + { + return EmptyKeys; + } + return Store.Keys; + } + } + + + public bool ContainsKey(string key) + { + if (Store == null) + { + return false; + } + return Store.ContainsKey(key); + } + + public bool TryGetValue(string key, out StringValues value) + { + if (Store == null) + { + value = default(StringValues); + return false; + } + return Store.TryGetValue(key, out value); + } + + public Enumerator GetEnumerator() + { + if (Store == null || Store.Count == 0) + { + return EmptyEnumerator; + } + return new Enumerator(Store.GetEnumerator()); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + if (Store == null || Store.Count == 0) + { + return EmptyIEnumeratorType; + } + return Store.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + if (Store == null || Store.Count == 0) + { + return EmptyIEnumerator; + } + return Store.GetEnumerator(); + } + } + + public struct Enumerator : IEnumerator> + { + private Dictionary.Enumerator _dictionaryEnumerator; + private bool _notEmpty; + + internal Enumerator(Dictionary.Enumerator dictionaryEnumerator) + { + _dictionaryEnumerator = dictionaryEnumerator; + _notEmpty = true; + } + + public bool MoveNext() + { + if (_notEmpty) + { + return _dictionaryEnumerator.MoveNext(); + } + return false; + } + + public KeyValuePair Current + { + get + { + if (_notEmpty) + { + return _dictionaryEnumerator.Current; + } + return default(KeyValuePair); + } + } + + public void Dispose() + { + } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + void IEnumerator.Reset() + { + if (_notEmpty) + { + ((IEnumerator)_dictionaryEnumerator).Reset(); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormFile.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormFile.cs new file mode 100644 index 000000000..8ab494609 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormFile.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + public class HttpFormFile + { + public HttpFormFile(long length, string name, string fileName,byte[] file) + { + Length = length; + Name = name; + FileName = fileName; + File = file; + } + public long Length { get; } + + public string Name { get; } + + public string FileName { get; } + + public byte[] File { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormFileCollection.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormFileCollection.cs new file mode 100644 index 000000000..4b1350905 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/HttpFormFileCollection.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + public class HttpFormFileCollection : List + { + public HttpFormFile this[string name] => GetFile(name); + + public HttpFormFile GetFile(string name) + { + foreach (var file in this) + { + if (string.Equals(name, file.Name, StringComparison.OrdinalIgnoreCase)) + { + return file; + } + } + + return null; + } + + public IReadOnlyList GetFiles(string name) + { + var files = new List(); + + foreach (var file in this) + { + if (string.Equals(name, file.Name, StringComparison.OrdinalIgnoreCase)) + { + files.Add(file); + } + } + + return files; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/RestContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/RestContext.cs new file mode 100644 index 000000000..09afdc758 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/RestContext.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.DependencyInjection; +using Surging.Core.CPlatform.Utilities; +using System.Linq; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + public class RestContext + { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetAttachment(string key, object value) + { + Check.NotNull(serviceProvider, "serviceProvider"); + var htpContextAccessor = serviceProvider.GetRequiredService(); + htpContextAccessor.HttpContext.Items.Add(key,value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public object GetAttachment(string key) + { + Check.NotNull(serviceProvider, "serviceProvider"); + var htpContextAccessor = serviceProvider.GetRequiredService(); + htpContextAccessor.HttpContext.Items.TryGetValue(key, out object value); + return value; + } + + public void RemoveContextParameters(string key) + { + Check.NotNull(serviceProvider, "serviceProvider"); + var htpContextAccessor = serviceProvider.GetRequiredService(); + if (htpContextAccessor.HttpContext.Items.ContainsKey(key)) + htpContextAccessor.HttpContext.Items.Remove(key); + + } + + public Dictionary GetContextParameters() + { + Check.NotNull(serviceProvider, "serviceProvider"); + var htpContextAccessor = serviceProvider.GetRequiredService(); + return htpContextAccessor.HttpContext.Items.ToDictionary(p => p.Key.ToString(), m => m.Value); + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetContextParameters(IDictionary contextParameters) + { + Check.NotNull(serviceProvider, "serviceProvider"); + var htpContextAccessor = serviceProvider.GetRequiredService(); + htpContextAccessor.HttpContext.Items= contextParameters; + } + + private static IServiceProvider serviceProvider; + + internal void Initialize(IServiceProvider provider) + { + serviceProvider= provider; + } + + public static RestContext GetContext() + { + + return new RestContext(); + } + + public static void RemoveContext() + { + Check.NotNull(serviceProvider, "serviceProvider"); + var htpContextAccessor = serviceProvider.GetRequiredService(); + htpContextAccessor.HttpContext.Items.Clear(); + + } + + + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/StreamCopyOperation.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/StreamCopyOperation.cs new file mode 100644 index 000000000..b01886a86 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Internal/StreamCopyOperation.cs @@ -0,0 +1,239 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.KestrelHttpServer.Internal +{ + internal class StreamCopyOperation + { + private const int DefaultBufferSize = 1024 * 16; + + private readonly TaskCompletionSource _tcs; + private readonly Stream _source; + private readonly Stream _destination; + private readonly byte[] _buffer; + private readonly AsyncCallback _readCallback; + private readonly AsyncCallback _writeCallback; + + private long? _bytesRemaining; + private CancellationToken _cancel; + + internal StreamCopyOperation(Stream source, Stream destination, long? bytesRemaining, CancellationToken cancel) + : this(source, destination, bytesRemaining, DefaultBufferSize, cancel) + { + } + + internal StreamCopyOperation(Stream source, Stream destination, long? bytesRemaining, int bufferSize, CancellationToken cancel) + : this(source, destination, bytesRemaining, new byte[bufferSize], cancel) + { + } + + internal StreamCopyOperation(Stream source, Stream destination, long? bytesRemaining, byte[] buffer, CancellationToken cancel) + { + Contract.Assert(source != null); + Contract.Assert(destination != null); + Contract.Assert(!bytesRemaining.HasValue || bytesRemaining.Value >= 0); + Contract.Assert(buffer != null); + + _source = source; + _destination = destination; + _bytesRemaining = bytesRemaining; + _cancel = cancel; + _buffer = buffer; + + _tcs = new TaskCompletionSource(); + _readCallback = new AsyncCallback(ReadCallback); + _writeCallback = new AsyncCallback(WriteCallback); + } + + public static async Task CopyToAsync(Stream source, Stream destination, long? count, int bufferSize, CancellationToken cancel) + { + long? bytesRemaining = count; + + var buffer = ArrayPool.Shared.Rent(bufferSize); + try + { + Debug.Assert(source != null); + Debug.Assert(destination != null); + Debug.Assert(!bytesRemaining.HasValue || bytesRemaining.Value >= 0); + Debug.Assert(buffer != null); + + while (true) + { + if (bytesRemaining.HasValue && bytesRemaining.Value <= 0) + { + return; + } + + cancel.ThrowIfCancellationRequested(); + + int readLength = buffer.Length; + if (bytesRemaining.HasValue) + { + readLength = (int)Math.Min(bytesRemaining.Value, (long)readLength); + } + int read = await source.ReadAsync(buffer, 0, readLength, cancel); + + if (bytesRemaining.HasValue) + { + bytesRemaining -= read; + } + + if (read <= 0) + { + return; + } + + cancel.ThrowIfCancellationRequested(); + + await destination.WriteAsync(buffer, 0, read); + } + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + internal Task Start() + { + ReadNextSegment(); + return _tcs.Task; + } + + private void Complete() + { + _tcs.TrySetResult(null); + } + + private bool CheckCancelled() + { + if (_cancel.IsCancellationRequested) + { + _tcs.TrySetCanceled(); + return true; + } + return false; + } + + private void Fail(Exception ex) + { + _tcs.TrySetException(ex); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting")] + private void ReadNextSegment() + { + // The natural end of the range. + if (_bytesRemaining.HasValue && _bytesRemaining.Value <= 0) + { + Complete(); + return; + } + + if (CheckCancelled()) + { + return; + } + + try + { + int readLength = _buffer.Length; + if (_bytesRemaining.HasValue) + { + readLength = (int)Math.Min(_bytesRemaining.Value, (long)readLength); + } + IAsyncResult async = _source.BeginRead(_buffer, 0, readLength, _readCallback, null); + + if (async.CompletedSynchronously) + { + int read = _source.EndRead(async); + WriteToOutputStream(read); + } + } + catch (Exception ex) + { + Fail(ex); + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting")] + private void ReadCallback(IAsyncResult async) + { + if (async.CompletedSynchronously) + { + return; + } + + try + { + int read = _source.EndRead(async); + WriteToOutputStream(read); + } + catch (Exception ex) + { + Fail(ex); + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting")] + private void WriteToOutputStream(int count) + { + if (_bytesRemaining.HasValue) + { + _bytesRemaining -= count; + } + + if (count == 0) + { + Complete(); + return; + } + + if (CheckCancelled()) + { + return; + } + + try + { + IAsyncResult async = _destination.BeginWrite(_buffer, 0, count, _writeCallback, null); + if (async.CompletedSynchronously) + { + _destination.EndWrite(async); + ReadNextSegment(); + } + } + catch (Exception ex) + { + Fail(ex); + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Redirecting")] + private void WriteCallback(IAsyncResult async) + { + if (async.CompletedSynchronously) + { + return; + } + + try + { + _destination.EndWrite(async); + ReadNextSegment(); + } + catch (Exception ex) + { + Fail(ex); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/KestrelHttpMessageListener.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/KestrelHttpMessageListener.cs new file mode 100644 index 000000000..35374c692 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/KestrelHttpMessageListener.cs @@ -0,0 +1,175 @@ +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Engines; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.KestrelHttpServer.Extensions; +using Surging.Core.KestrelHttpServer.Internal; +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Routing; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.CPlatform.Messages; +using System.Diagnostics; +using Surging.Core.CPlatform.Configurations; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Utilities; +using System.Reactive.Subjects; + +namespace Surging.Core.KestrelHttpServer +{ + public class KestrelHttpMessageListener : HttpMessageListener, IDisposable + { + private readonly ILogger _logger; + private IWebHost _host; + private bool _isCompleted; + private readonly ISerializer _serializer; + private readonly IServiceEngineLifetime _lifetime; + private readonly IModuleProvider _moduleProvider; + private readonly CPlatformContainer _container; + private readonly IServiceRouteProvider _serviceRouteProvider; + private readonly DiagnosticListener _diagnosticListener; + + public KestrelHttpMessageListener(ILogger logger, + ISerializer serializer, + IServiceEngineLifetime lifetime, + IModuleProvider moduleProvider, + IServiceRouteProvider serviceRouteProvider, + CPlatformContainer container) : base(logger, serializer, serviceRouteProvider) + { + _logger = logger; + _serializer = serializer; + _lifetime = lifetime; + _moduleProvider = moduleProvider; + _container = container; + _serviceRouteProvider = serviceRouteProvider; + _diagnosticListener = new DiagnosticListener(CPlatform.Diagnostics.DiagnosticListenerExtensions.DiagnosticListenerName); + } + + public async Task StartAsync(IPAddress address,int? port) + { + try + { + if (AppConfig.ServerOptions.DockerDeployMode == DockerDeployMode.Swarm) + { + address = IPAddress.Any; + } + + var hostBuilder = new WebHostBuilder() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseKestrel((context,options) => + { + options.Limits.MinRequestBodyDataRate = null; + options.Limits.MinResponseDataRate = null; + options.Limits.MaxRequestBodySize = null; + options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(30); + if (port != null && port > 0) + options.Listen(address, port.Value, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + }); + ConfigureHost(context, options, address); + + }) + .ConfigureServices(ConfigureServices) + .ConfigureLogging((logger) => + { + logger.AddConfiguration( + CPlatform.AppConfig.GetSection("Logging")); + }) + .Configure(AppResolve); + + if (Directory.Exists(CPlatform.AppConfig.ServerOptions.WebRootPath)) + hostBuilder = hostBuilder.UseWebRoot(CPlatform.AppConfig.ServerOptions.WebRootPath); + _host = hostBuilder.Build(); + _lifetime.ServiceEngineStarted.Register(async () => + { + await _host.RunAsync(); + }); + + } + catch + { + _logger.LogError($"http服务主机启动失败,监听地址:{address}:{port}。 "); + } + + } + + public void ConfigureHost(WebHostBuilderContext context, KestrelServerOptions options,IPAddress ipAddress) + { + _moduleProvider.ConfigureHost(new WebHostContext(context, options, ipAddress)); + } + + public void ConfigureServices(IServiceCollection services) + { + var builder = new ContainerBuilder(); + services.AddMvc(option => option.EnableEndpointRouting = false); + _moduleProvider.ConfigureServices(new ConfigurationContext(services, + _moduleProvider.Modules, + _moduleProvider.VirtualPaths, + AppConfig.Configuration)); + builder.Populate(services); + builder.Update(_container.Current.ComponentRegistry); + } + + private void AppResolve(IApplicationBuilder app) + { + app.UseStaticFiles(); + app.UseMvc(); + _moduleProvider.Initialize(new ApplicationInitializationContext(app, _moduleProvider.Modules, + _moduleProvider.VirtualPaths, + AppConfig.Configuration)); + app.Use(async (context,next) => + { + var messageId = Guid.NewGuid().ToString("N"); + var subject = new ReplaySubject>(); + var sender = new HttpServerMessageSender(_serializer, context,_diagnosticListener, subject); + try + { + var filters = app.ApplicationServices.GetServices(); + var isSuccess = await OnAuthorization(context, sender, messageId, filters); + if (isSuccess) + { + var actionFilters = app.ApplicationServices.GetServices(); + await OnReceived(sender, messageId, context, actionFilters, subject); + } + await next(); + } + catch (Exception ex) + { + var filters = app.ApplicationServices.GetServices(); + WirteDiagnosticError(messageId, ex); + await OnException(context, sender, messageId, ex, filters); + } + }); + app.Run( context=> Task.CompletedTask); + } + + private void WirteDiagnosticError(string messageId,Exception ex) + { + _diagnosticListener.WriteTransportError(CPlatform.Diagnostics.TransportType.Rest, new TransportErrorEventData(new DiagnosticMessage + { + Id = messageId + }, ex)); + } + + public void Dispose() + { + _host.Dispose(); + } + + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/KestrelHttpModule.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/KestrelHttpModule.cs new file mode 100644 index 000000000..feea26b50 --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/KestrelHttpModule.cs @@ -0,0 +1,121 @@ +using Autofac; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Engines; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.KestrelHttpServer.Diagnostics; +using Surging.Core.KestrelHttpServer.Extensions; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using Surging.Core.KestrelHttpServer.Internal; +using System.Net; + +namespace Surging.Core.KestrelHttpServer +{ + public class KestrelHttpModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + } + + public virtual void Initialize(ApplicationInitializationContext builder) + { + RestContext.GetContext().Initialize(builder.Builder.ApplicationServices); + } + + public virtual void RegisterBuilder(WebHostContext context) + { + } + + public virtual void RegisterBuilder(ConfigurationContext context) + { + context.Services.AddSingleton(); + context.Services.AddFilters(typeof(HttpRequestFilterAttribute)); + context.Services.AddFilters(typeof(CustomerExceptionFilterAttribute)); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.AddFilter(typeof(ServiceExceptionFilter)); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType(typeof(HttpExecutor)).As(typeof(IServiceExecutor)) + .Named(CommunicationProtocol.Http.ToString()).SingleInstance(); + if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.Http) + { + RegisterDefaultProtocol(builder); + } + else if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterHttpProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new KestrelHttpMessageListener( + provider.Resolve>(), + provider.Resolve>(), + provider.Resolve(), + provider.Resolve(), + provider.Resolve(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var executor = provider.ResolveKeyed(CommunicationProtocol.Http.ToString()); + var messageListener = provider.Resolve(); + return new DefaultHttpServiceHost(async endPoint => + { + var address = endPoint as IPEndPoint; + await messageListener.StartAsync(address?.Address, address?.Port); + return messageListener; + }, executor, messageListener); + + }).As(); + } + + private static void RegisterHttpProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new KestrelHttpMessageListener( + provider.Resolve>(), + provider.Resolve>(), + provider.Resolve(), + provider.Resolve(), + provider.Resolve(), + provider.Resolve() + + ); + }).SingleInstance(); + builder.Register(provider => + { + var executor = provider.ResolveKeyed(CommunicationProtocol.Http.ToString()); + var messageListener = provider.Resolve(); + return new HttpServiceHost(async endPoint => + { + var address = endPoint as IPEndPoint; + await messageListener.StartAsync(address?.Address, address?.Port); + return messageListener; + }, executor, messageListener); + + }).As(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/StatusCode.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/StatusCode.cs new file mode 100644 index 000000000..3296cfaec --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/StatusCode.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.KestrelHttpServer +{ + public enum StatusCode + { + Success = 200, + RequestError = 400, + AuthorizationFailed = 401, + } +} diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/Surging.Core.KestrelHttpServer.csproj b/src/Surging.Core/Surging.Core.KestrelHttpServer/Surging.Core.KestrelHttpServer.csproj new file mode 100644 index 000000000..4a084bc5b --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/Surging.Core.KestrelHttpServer.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + 1.1.0.0 + fanly + fanly + surging Micro Service Framework + surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec + Copyright © fanly All Rights Reserved. + https://github.com/dotnetcore/surging/blob/master/LICENSE + https://github.com/dotnetcore/surging + 1.multiple register center cluster +2. fix bug + MicroService surging + 1.1.0.0 + 1.1.0.0 + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.KestrelHttpServer/WebHostContext.cs b/src/Surging.Core/Surging.Core.KestrelHttpServer/WebHostContext.cs new file mode 100644 index 000000000..300a46eec --- /dev/null +++ b/src/Surging.Core/Surging.Core.KestrelHttpServer/WebHostContext.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Surging.Core.KestrelHttpServer +{ + public class WebHostContext + { + public WebHostContext(WebHostBuilderContext context, KestrelServerOptions options, IPAddress ipAddress) + { + WebHostBuilderContext = Check.NotNull(context, nameof(context)); + KestrelOptions = Check.NotNull(options, nameof(options)); + Address = ipAddress; + } + + public WebHostBuilderContext WebHostBuilderContext { get; } + + public KestrelServerOptions KestrelOptions { get; } + + public IPAddress Address { get; } + + } +} diff --git a/src/Surging.Core/Surging.Core.Log4net/Log4NetLogger.cs b/src/Surging.Core/Surging.Core.Log4net/Log4NetLogger.cs index ab707aea1..355c053b2 100644 --- a/src/Surging.Core/Surging.Core.Log4net/Log4NetLogger.cs +++ b/src/Surging.Core/Surging.Core.Log4net/Log4NetLogger.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using System.Xml; @@ -31,6 +32,7 @@ public IDisposable BeginScope(TState state) return NoopDisposable.Instance; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsEnabled(LogLevel logLevel) { switch (logLevel) diff --git a/src/Surging.Core/Surging.Core.Log4net/Log4netModule.cs b/src/Surging.Core/Surging.Core.Log4net/Log4netModule.cs index 0bccbbaa8..bbffd8721 100644 --- a/src/Surging.Core/Surging.Core.Log4net/Log4netModule.cs +++ b/src/Surging.Core/Surging.Core.Log4net/Log4netModule.cs @@ -8,9 +8,10 @@ namespace Surging.Core.Log4net public class Log4netModule : EnginePartModule { private string log4NetConfigFile = "${LogPath}|log4net.config"; - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); var section = CPlatform.AppConfig.GetSection("Logging"); log4NetConfigFile = EnvironmentHelper.GetEnvironmentVariable(log4NetConfigFile); serviceProvider.GetInstances().AddProvider(new Log4NetProvider(log4NetConfigFile)); diff --git a/src/Surging.Core/Surging.Core.Log4net/Surging.Core.Log4net.csproj b/src/Surging.Core/Surging.Core.Log4net/Surging.Core.Log4net.csproj index e6db7bebd..2f8c55887 100644 --- a/src/Surging.Core/Surging.Core.Log4net/Surging.Core.Log4net.csproj +++ b/src/Surging.Core/Surging.Core.Log4net/Surging.Core.Log4net.csproj @@ -1,8 +1,8 @@ - netcoreapp2.1 - 0.8.0.1 + net6.0 + 1.1.0.0 fanly surging Micro Service Framework @@ -11,27 +11,18 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component - 0.8.0.1 - 0.8.0.1 + 1.multiple register center cluster +2. fix bug + 1.1.0.0 + 1.1.0.0 - - - + + + + diff --git a/src/Surging.Core/Surging.Core.NLog/NLogModule.cs b/src/Surging.Core/Surging.Core.NLog/NLogModule.cs index b4a6ad10c..eee3dca34 100644 --- a/src/Surging.Core/Surging.Core.NLog/NLogModule.cs +++ b/src/Surging.Core/Surging.Core.NLog/NLogModule.cs @@ -11,9 +11,10 @@ namespace Surging.Core.Nlog public class NLogModule : EnginePartModule { private string nlogConfigFile = "${LogPath}|NLog.config"; - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); var section = AppConfig.GetSection("Logging"); nlogConfigFile = EnvironmentHelper.GetEnvironmentVariable(nlogConfigFile); NLog.LogManager.LoadConfiguration(nlogConfigFile); diff --git a/src/Surging.Core/Surging.Core.NLog/NLogger.cs b/src/Surging.Core/Surging.Core.NLog/NLogger.cs index 373fe8339..fbe99126d 100644 --- a/src/Surging.Core/Surging.Core.NLog/NLogger.cs +++ b/src/Surging.Core/Surging.Core.NLog/NLogger.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; -using System; +using System; +using System.Runtime.CompilerServices; namespace Surging.Core.Nlog { @@ -17,6 +18,7 @@ public IDisposable BeginScope(TState state) return NoopDisposable.Instance; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) { switch (logLevel) @@ -60,16 +62,16 @@ public void Log(Microsoft.Extensions.Logging.LogLevel logLevel, EventId switch (logLevel) { case LogLevel.Critical: - _log.Fatal(message); + _log.Fatal(exception, message); break; case LogLevel.Debug: - _log.Debug(message); + _log.Debug(exception, message); break; case LogLevel.Trace: - _log.Trace(message); + _log.Trace(exception, message); break; case LogLevel.Error: - _log.Error(message, exception,null); + _log.Error(exception, message); break; case LogLevel.Information: _log.Info(message); @@ -79,7 +81,7 @@ public void Log(Microsoft.Extensions.Logging.LogLevel logLevel, EventId break; default: _log.Warn($"遇到未知日志级别{logLevel}"); - _log.Info(message, exception,null); + _log.Info(message, exception, null); break; } } diff --git a/src/Surging.Core/Surging.Core.NLog/Surging.Core.Nlog.csproj b/src/Surging.Core/Surging.Core.NLog/Surging.Core.Nlog.csproj index 54ae26d6d..a70a91f8a 100644 --- a/src/Surging.Core/Surging.Core.NLog/Surging.Core.Nlog.csproj +++ b/src/Surging.Core/Surging.Core.NLog/Surging.Core.Nlog.csproj @@ -1,20 +1,10 @@ - netcoreapp2.1 - 1.consul and zookeeper add configuration file -2.Add zookeeper new calls -3.Add Environment variables -4.Build environment variables -5.Add Module Root Path Configuration -6.Add public host ip and port mapping configuration -7.Optimize service route and add EnableChildrenMonitor options -8.Restore version, optimizing register node monitor branch to development -9.Proxy build get the using namespace from the interface assembly -10. Add the UseConsoleLifetime Configuration Does Not Close After the Console Application Runs -11.Fix zookeeper configuration -12.Refactor log component - 0.8.0.1 + net6.0 + 1.multiple register center cluster +2. fix bug + 1.1.0.0 fanly fanly surging Micro Service Framework @@ -23,15 +13,15 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 0.8.0.1 - 0.8.0.1 + 1.1.0.0 + 1.0.0.0 - - - - + + + + diff --git a/src/Surging.Core/Surging.Core.Protocol.Http/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Protocol.Http/ContainerBuilderExtensions.cs index 4e484febb..69eb8a5ee 100644 --- a/src/Surging.Core/Surging.Core.Protocol.Http/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.Protocol.Http/ContainerBuilderExtensions.cs @@ -1,6 +1,7 @@ using Autofac; using Microsoft.Extensions.Logging; using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Runtime.Server.Implementation; using Surging.Core.CPlatform.Serialization; @@ -37,7 +38,8 @@ private static void RegisterDefaultProtocol(ContainerBuilder builder) { return new DotNettyHttpServerMessageListener(provider.Resolve>(), provider.Resolve(), - provider.Resolve>() + provider.Resolve>(), + provider.Resolve() ); }).SingleInstance(); builder.Register(provider => @@ -61,7 +63,8 @@ private static void RegisterHttpProtocol(ContainerBuilder builder) { return new DotNettyHttpServerMessageListener(provider.Resolve>(), provider.Resolve(), - provider.Resolve>() + provider.Resolve>(), + provider.Resolve() ); }).SingleInstance(); builder.Register(provider => diff --git a/src/Surging.Core/Surging.Core.Protocol.Http/DotNettyHttpServerMessageListener.cs b/src/Surging.Core/Surging.Core.Protocol.Http/DotNettyHttpServerMessageListener.cs index 8fac7557a..90719e779 100644 --- a/src/Surging.Core/Surging.Core.Protocol.Http/DotNettyHttpServerMessageListener.cs +++ b/src/Surging.Core/Surging.Core.Protocol.Http/DotNettyHttpServerMessageListener.cs @@ -4,7 +4,10 @@ using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Routing; +using Surging.Core.CPlatform.Routing.Template; using Surging.Core.CPlatform.Serialization; using Surging.Core.CPlatform.Transport; using Surging.Core.CPlatform.Transport.Codec; @@ -14,6 +17,8 @@ using System.Net; using System.Text; using System.Threading.Tasks; +using System.Web; +using TaskCompletionSource = DotNetty.Common.Concurrency.TaskCompletionSource; namespace Surging.Core.Protocol.Http { @@ -26,17 +31,22 @@ class DotNettyHttpServerMessageListener : IMessageListener, IDisposable private readonly ITransportMessageEncoder _transportMessageEncoder; private IChannel _channel; private readonly ISerializer _serializer; + private readonly IServiceRouteProvider _serviceRouteProvider; #endregion Field #region Constructor - public DotNettyHttpServerMessageListener(ILogger logger, ITransportMessageCodecFactory codecFactory, ISerializer serializer) + public DotNettyHttpServerMessageListener(ILogger logger, + ITransportMessageCodecFactory codecFactory, + ISerializer serializer, + IServiceRouteProvider serviceRouteProvider) { _logger = logger; _transportMessageEncoder = codecFactory.GetEncoder(); _transportMessageDecoder = codecFactory.GetDecoder(); _serializer = serializer; + _serviceRouteProvider = serviceRouteProvider; } #endregion Constructor @@ -70,10 +80,10 @@ public async Task StartAsync(EndPoint endPoint) var bootstrap = new ServerBootstrap(); bootstrap .Group(bossGroup, workerGroup) - .Channel() - .Option(ChannelOption.SoReuseport, true) + .Channel() + .Option(ChannelOption.SoReuseport, true) .ChildOption(ChannelOption.SoReuseaddr, true) - .Option(ChannelOption.SoBacklog, 8192) + .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) .ChildHandler(new ActionChannelInitializer(channel => { IChannelPipeline pipeline = channel.Pipeline; @@ -84,20 +94,20 @@ public async Task StartAsync(EndPoint endPoint) { var sender = new DotNettyHttpServerMessageSender(_transportMessageEncoder, contenxt, _serializer); await OnReceived(sender, message); - }, _logger, _serializer)); + }, _logger, _serializer, _serviceRouteProvider)); serverCompletion.TryComplete(); })); try { _channel = await bootstrap.BindAsync(endPoint); if (_logger.IsEnabled(LogLevel.Debug)) - _logger.LogDebug($"Http服务主机启动成功,监听地址:{endPoint}。"); + _logger.LogDebug($"Http服务主机启动成功,监听地址:{endPoint}。"); } catch { _logger.LogError($"Http服务主机启动失败,监听地址:{endPoint}。 "); } - + } public void CloseAsync() @@ -130,12 +140,17 @@ private class ServerHandler : SimpleChannelInboundHandler private readonly Action _readAction; private readonly ILogger _logger; private readonly ISerializer _serializer; + private readonly IServiceRouteProvider _serviceRouteProvider; - public ServerHandler(Action readAction, ILogger logger, ISerializer serializer) + public ServerHandler(Action readAction, + ILogger logger, + ISerializer serializer, + IServiceRouteProvider serviceRouteProvider) { _readAction = readAction; _logger = logger; _serializer = serializer; + _serviceRouteProvider = serviceRouteProvider; } public bool WaitForCompletion() @@ -149,26 +164,40 @@ protected override void ChannelRead0(IChannelHandlerContext ctx, IFullHttpReques var data = new byte[msg.Content.ReadableBytes]; msg.Content.ReadBytes(data); - var parameters = GetParameters(msg.Uri, out string routePath); - parameters.Remove("servicekey", out object serviceKey); - if (msg.Method.Name == "POST") + Task.Run(async () => { - _readAction(ctx, new TransportMessage(new HttpMessage + var parameters = GetParameters(HttpUtility.UrlDecode(msg.Uri), out string path); + var serviceRoute = await _serviceRouteProvider.GetRouteByPathRegex(path); + parameters.Remove("servicekey", out object serviceKey); + if (data.Length > 0) + parameters = _serializer.Deserialize>(System.Text.Encoding.ASCII.GetString(data)) ?? new Dictionary(); + if (String.Compare(serviceRoute.ServiceDescriptor.RoutePath, path, true) != 0) { - Parameters = _serializer.Deserialize>(System.Text.Encoding.ASCII.GetString(data)) ?? new Dictionary(), - RoutePath = routePath, - ServiceKey = serviceKey?.ToString() - })); - } - else - { - _readAction(ctx, new TransportMessage(new HttpMessage + var @params = RouteTemplateSegmenter.Segment(serviceRoute.ServiceDescriptor.RoutePath, path); + foreach (var param in @params) + { + parameters.Add(param.Key,param.Value); + } + } + if (msg.Method.Name == "POST") { - Parameters = parameters, - RoutePath = routePath, - ServiceKey = serviceKey?.ToString() - })); - } + _readAction(ctx, new TransportMessage(new HttpMessage + { + Parameters = parameters, + RoutePath = serviceRoute.ServiceDescriptor.RoutePath, + ServiceKey = serviceKey?.ToString() + })); + } + else + { + _readAction(ctx, new TransportMessage(new HttpMessage + { + Parameters = parameters, + RoutePath = serviceRoute.ServiceDescriptor.RoutePath, + ServiceKey = serviceKey?.ToString() + })); + } + }); } public IDictionary GetParameters(string msg, out string routePath) diff --git a/src/Surging.Core/Surging.Core.Protocol.Http/HttpProtocolModule.cs b/src/Surging.Core/Surging.Core.Protocol.Http/HttpProtocolModule.cs index 83711621f..dc57f236c 100644 --- a/src/Surging.Core/Surging.Core.Protocol.Http/HttpProtocolModule.cs +++ b/src/Surging.Core/Surging.Core.Protocol.Http/HttpProtocolModule.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using Surging.Core.CPlatform; using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Runtime.Server.Implementation; using Surging.Core.CPlatform.Serialization; @@ -14,9 +15,9 @@ namespace Surging.Core.Protocol.Http { public class HttpProtocolModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } /// @@ -44,7 +45,8 @@ private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) { return new DotNettyHttpServerMessageListener(provider.Resolve>(), provider.Resolve(), - provider.Resolve>() + provider.Resolve>(), + provider.Resolve() ); }).SingleInstance(); builder.Register(provider => @@ -68,7 +70,8 @@ private static void RegisterHttpProtocol(ContainerBuilderWrapper builder) { return new DotNettyHttpServerMessageListener(provider.Resolve>(), provider.Resolve(), - provider.Resolve>() + provider.Resolve>(), + provider.Resolve() ); }).SingleInstance(); builder.Register(provider => diff --git a/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceExecutor.cs b/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceExecutor.cs index a2b548af9..d1bbb7f5a 100644 --- a/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceExecutor.cs +++ b/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceExecutor.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using Surging.Core.CPlatform.Exceptions; using static Surging.Core.CPlatform.Utilities.FastInvoke; namespace Surging.Core.Protocol.Http @@ -137,6 +138,14 @@ private async Task> RemoteExecuteAsync(ServiceEntry en resultMessage.IsSucceed = resultMessage.Entity != null; resultMessage.StatusCode = resultMessage.IsSucceed ? (int)StatusCode.Success : (int)StatusCode.RequestError; } + catch (ValidateException validateException) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(validateException, "执行本地逻辑时候发生了错误。", validateException); + + resultMessage.Message = validateException.Message; + resultMessage.StatusCode = validateException.HResult; + } catch (Exception ex) { if (_logger.IsEnabled(LogLevel.Error)) @@ -168,6 +177,14 @@ private async Task> LocalExecuteAsync(ServiceEntry ent resultMessage.IsSucceed = resultMessage.Entity != null; resultMessage.StatusCode = resultMessage.IsSucceed ? (int)StatusCode.Success : (int)StatusCode.RequestError; } + catch (ValidateException validateException) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(validateException, "执行本地逻辑时候发生了错误。", validateException); + + resultMessage.Message = validateException.Message; + resultMessage.StatusCode = validateException.HResult; + } catch (Exception exception) { if (_logger.IsEnabled(LogLevel.Error)) diff --git a/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceHost.cs b/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceHost.cs index 1abc22a98..f193753ed 100644 --- a/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceHost.cs +++ b/src/Surging.Core/Surging.Core.Protocol.Http/HttpServiceHost.cs @@ -46,11 +46,8 @@ public override async Task StartAsync(EndPoint endPoint) return; _serverMessageListener = await _messageListenerFactory(endPoint); _serverMessageListener.Received += async (sender, message) => - { - await Task.Run(() => - { - MessageListener.OnReceived(sender, message); - }); + { + await MessageListener.OnReceived(sender, message); }; } @@ -58,13 +55,10 @@ public override async Task StartAsync(string ip,int port) { if (_serverMessageListener != null) return; - _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.HttpPort)); + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.HttpPort??0)); _serverMessageListener.Received += async (sender, message) => { - await Task.Run(() => - { - MessageListener.OnReceived(sender, message); - }); + await MessageListener.OnReceived(sender, message); }; } diff --git a/src/Surging.Core/Surging.Core.Protocol.Http/Surging.Core.Protocol.Http.csproj b/src/Surging.Core/Surging.Core.Protocol.Http/Surging.Core.Protocol.Http.csproj index 8472a309b..a860dc05c 100644 --- a/src/Surging.Core/Surging.Core.Protocol.Http/Surging.Core.Protocol.Http.csproj +++ b/src/Surging.Core/Surging.Core.Protocol.Http/Surging.Core.Protocol.Http.csproj @@ -1,8 +1,8 @@ - + - netcoreapp2.1 - 0.8.0.2 + net6.0 + 1.1.0.0 fanly fanly surging Micro Service Framework @@ -11,15 +11,15 @@ https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging MicroService surging - 1.Service host support multiple protocols -2.Exclude interface registration service - 0.8.0.2 - 0.8.0.2 + 1.multiple register center cluster +2. fix bug + 1.1.0.0 + 1.1.0.0 - - + + diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Diagnostics/MqttTransportCarrierHeaderCollection.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Diagnostics/MqttTransportCarrierHeaderCollection.cs new file mode 100644 index 000000000..6503555ff --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Diagnostics/MqttTransportCarrierHeaderCollection.cs @@ -0,0 +1,33 @@ +using Surging.Core.CPlatform.Diagnostics; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Diagnostics +{ + public class MqttTransportCarrierHeaderCollection : ICarrierHeaderCollection + { + private readonly TracingHeaders _tracingHeaders; + + public MqttTransportCarrierHeaderCollection(TracingHeaders tracingHeaders) + { + _tracingHeaders = tracingHeaders; + } + + public IEnumerator> GetEnumerator() + { + return _tracingHeaders.GetEnumerator(); + } + + public void Add(string key, string value) + { + _tracingHeaders.Add(key, value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _tracingHeaders.GetEnumerator(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Diagnostics/MqttTransportDiagnosticProcessor.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Diagnostics/MqttTransportDiagnosticProcessor.cs new file mode 100644 index 000000000..2f616c852 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Diagnostics/MqttTransportDiagnosticProcessor.cs @@ -0,0 +1,93 @@ +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; +using SurgingEvents = Surging.Core.CPlatform.Diagnostics.DiagnosticListenerExtensions; + +namespace Surging.Core.Protocol.Mqtt.Diagnostics +{ + public class MqttTransportDiagnosticProcessor: ITracingDiagnosticProcessor + { + private Func _transportOperationNameResolver; + public string ListenerName => SurgingEvents.DiagnosticListenerName; + + + private readonly ISerializer _serializer; + private readonly ITracingContext _tracingContext; + private readonly IEntrySegmentContextAccessor _segmentContextAccessor; + + public Func TransportOperationNameResolver + { + get + { + return _transportOperationNameResolver ?? + (_transportOperationNameResolver = (data) => "Mqtt-Transport:: " + data.Message.MessageName); + } + set => _transportOperationNameResolver = + value ?? throw new ArgumentNullException(nameof(TransportOperationNameResolver)); + } + + public MqttTransportDiagnosticProcessor(ITracingContext tracingContext, ISerializer serializer, IEntrySegmentContextAccessor contextAccessor) + { + _tracingContext = tracingContext; + _serializer = serializer; + _segmentContextAccessor = contextAccessor; + } + + [DiagnosticName(SurgingEvents.SurgingBeforeTransport, TransportType.Mqtt)] + public void TransportBefore([Object] TransportEventData eventData) + { + var message = eventData.Message.GetContent(); + var operationName = TransportOperationNameResolver(eventData); + var context = _tracingContext.CreateEntrySegmentContext(operationName, new MqttTransportCarrierHeaderCollection(eventData.Headers)); + if (!string.IsNullOrEmpty(eventData.TraceId)) + context.TraceId = ConvertUniqueId(eventData); + context.Span.AddLog(LogEvent.Message($"Worker running at: {DateTime.Now}")); + context.Span.SpanLayer = SpanLayer.RPC_FRAMEWORK; + context.Span.AddTag(Tags.MQTT_CLIENT_ID, eventData.TraceId.ToString()); + context.Span.AddTag(Tags.MQTT_METHOD, eventData.Method.ToString()); + context.Span.AddTag(Tags.REST_PARAMETERS, _serializer.Serialize(message.Parameters)); + context.Span.AddTag(Tags.MQTT_BROKER_ADDRESS, NetUtils.GetHostAddress().ToString()); + } + + [DiagnosticName(SurgingEvents.SurgingAfterTransport, TransportType.Mqtt)] + public void TransportAfter([Object] ReceiveEventData eventData) + { + var context = _segmentContextAccessor.Context; + if (context != null) + { + _tracingContext.Release(context); + } + } + + [DiagnosticName(SurgingEvents.SurgingErrorTransport, TransportType.Mqtt)] + public void TransportError([Object] TransportErrorEventData eventData) + { + var context = _segmentContextAccessor.Context; + if (context != null) + { + context.Span.ErrorOccurred(eventData.Exception); + _tracingContext.Release(context); + } + } + + public UniqueId ConvertUniqueId(TransportEventData eventData) + { + long part1 = 0, part2 = 0, part3 = 0; + UniqueId uniqueId = new UniqueId(); + var bytes = Encoding.Default.GetBytes($"{eventData.TraceId}-{nameof(MqttTransportDiagnosticProcessor)}"); + part1 = BitConverter.ToInt64(bytes, 0); + if (eventData.TraceId.Length > 8) + part2 = BitConverter.ToInt64(bytes, 8); + if (eventData.TraceId.Length > 16) + part3 = BitConverter.ToInt64(bytes, 16); + if (!string.IsNullOrEmpty(eventData.TraceId)) + uniqueId = new UniqueId(part1, part2, part3); + return uniqueId; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/DotNettyMqttServerMessageListener.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/DotNettyMqttServerMessageListener.cs new file mode 100644 index 000000000..457871e2f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/DotNettyMqttServerMessageListener.cs @@ -0,0 +1,213 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Mqtt; +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Common.Utilities; +using DotNetty.Transport.Bootstrapping; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Sockets; +using DotNetty.Transport.Libuv; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.Protocol.Mqtt.Implementation; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Runtime; +using Surging.Core.Protocol.Mqtt.Internal.Services; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt +{ + public class DotNettyMqttServerMessageListener : IMessageListener, IDisposable + { + #region Field + + private readonly ILogger _logger; + private IChannel _channel; + private readonly IChannelService _channelService; + private readonly IMqttBehaviorProvider _mqttBehaviorProvider; + private readonly DiagnosticListener _diagnosticListener; + #endregion Field + + public event ReceivedDelegate Received; + + #region Constructor + public DotNettyMqttServerMessageListener(ILogger logger, + IChannelService channelService, + IMqttBehaviorProvider mqttBehaviorProvider) + { + _logger = logger; + _channelService = channelService; + _mqttBehaviorProvider = mqttBehaviorProvider; + _diagnosticListener = new DiagnosticListener(DiagnosticListenerExtensions.DiagnosticListenerName); + } + #endregion + + public void Dispose() + { + throw new NotImplementedException(); + } + + public async Task OnReceived(IMessageSender sender, TransportMessage message) + { + if (Received == null) + return; + await Received(sender, message); + } + + public async Task StartAsync(EndPoint endPoint) + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备启动Mqtt服务主机,监听地址:{endPoint}。"); + IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1); + IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 + var bootstrap = new ServerBootstrap(); + if (AppConfig.ServerOptions.Libuv) + { + var dispatcher = new DispatcherEventLoopGroup(); + bossGroup = dispatcher; + workerGroup = new WorkerEventLoopGroup(dispatcher); + bootstrap.Channel(); + } + else + { + bossGroup = new MultithreadEventLoopGroup(1); + workerGroup = new MultithreadEventLoopGroup(); + bootstrap.Channel(); + } + bootstrap + .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) + .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default) + .Group(bossGroup, workerGroup) + .Option(ChannelOption.TcpNodelay, true) + .ChildHandler(new ActionChannelInitializer(channel => + { + IChannelPipeline pipeline = channel.Pipeline; + pipeline.AddLast(MqttEncoder.Instance, + new MqttDecoder(true, 256 * 1024), new ServerHandler(async (context, packetType, message) => + { + var mqttHandlerService = new ServerMqttHandlerService(_logger, _channelService, _mqttBehaviorProvider); + await ChannelWrite(context, message, packetType, mqttHandlerService); + }, _logger, _channelService, _mqttBehaviorProvider)); + })); + try + { + _channel = await bootstrap.BindAsync(endPoint); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"mqtt服务主机启动成功,监听地址:{endPoint}。"); + } + catch + { + _logger.LogError($"mqtt服务主机启动失败,监听地址:{endPoint}。 "); + } + } + + public async Task ChannelWrite(IChannelHandlerContext context,object message, PacketType packetType, ServerMqttHandlerService mqttHandlerService) + { + switch (packetType) + { + case PacketType.CONNECT: + await mqttHandlerService.Login(context, message as ConnectPacket); + break; + case PacketType.PUBLISH: + await mqttHandlerService.Publish(context, message as PublishPacket); + break; + case PacketType.PUBACK: + await mqttHandlerService.PubAck(context, message as PubAckPacket); + break; + case PacketType.PUBREC: + await mqttHandlerService.PubRec(context, message as PubRecPacket); + break; + case PacketType.PUBREL: + await mqttHandlerService.PubRel(context, message as PubRelPacket); + break; + case PacketType.PUBCOMP: + await mqttHandlerService.PubComp(context, message as PubCompPacket); + break; + case PacketType.SUBSCRIBE: + await mqttHandlerService.Subscribe(context, message as SubscribePacket); + break; + case PacketType.SUBACK: + await mqttHandlerService.SubAck(context, message as SubAckPacket); + break; + case PacketType.UNSUBSCRIBE: + await mqttHandlerService.Unsubscribe(context, message as UnsubscribePacket); + break; + case PacketType.UNSUBACK: + await mqttHandlerService.UnsubAck(context, message as UnsubAckPacket); + break; + case PacketType.PINGREQ: + await mqttHandlerService.PingReq(context, message as PingReqPacket); + break; + case PacketType.PINGRESP: + await mqttHandlerService.PingResp(context, message as PingRespPacket); + break; + case PacketType.DISCONNECT: + await mqttHandlerService.Disconnect(context, message as DisconnectPacket); + break; + } + } + + private class ServerHandler : ChannelHandlerAdapter + { + private readonly Action _readAction; + private readonly ILogger _logger; + + public ServerHandler(Action readAction, + ILogger logger, + IChannelService channelService, + IMqttBehaviorProvider mqttBehaviorProvider) + { + _readAction = readAction; + _logger = logger; + } + + public override void ChannelRead(IChannelHandlerContext context, object message) + { + var buffer = message as Packet; + _readAction(context, buffer.PacketType, buffer); + ReferenceCountUtil.Release(message); + } + + public override void ChannelInactive(IChannelHandlerContext context) + { + this.SetException(new InvalidOperationException("Channel is closed.")); + base.ChannelInactive(context); + } + + public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) { + _readAction.Invoke(context,PacketType.DISCONNECT,DisconnectPacket.Instance); + this.SetException(exception); + } + + void SetException(Exception ex) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"message:{ex.Message},Source:{ex.Source},Trace:{ex.StackTrace}"); + } + } + + private void WirteDiagnosticError(TransportMessage message) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + var remoteInvokeResultMessage = message.GetContent(); + _diagnosticListener.WriteTransportError(TransportType.Mqtt, new TransportErrorEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id + }, new Exception(remoteInvokeResultMessage.ExceptionMessage))); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Implementation/DefaultMqttServiceFactory.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Implementation/DefaultMqttServiceFactory.cs new file mode 100644 index 000000000..dd6f68a1b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Implementation/DefaultMqttServiceFactory.cs @@ -0,0 +1,61 @@ +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Mqtt; +using Surging.Core.CPlatform.Serialization; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Implementation +{ + public class DefaultMqttServiceFactory : IMqttServiceFactory + { + + private readonly ISerializer _serializer; + private readonly ConcurrentDictionary _addressModel = + new ConcurrentDictionary(); + + public DefaultMqttServiceFactory(ISerializer serializer) + { + _serializer = serializer; + } + + public Task> CreateMqttServiceRoutesAsync(IEnumerable descriptors) + { + if (descriptors == null) + throw new ArgumentNullException(nameof(descriptors)); + + descriptors = descriptors.ToArray(); + var routes = new List(descriptors.Count()); + + routes.AddRange(descriptors.Select(descriptor => new MqttServiceRoute + { + MqttEndpoint = CreateAddress(descriptor.AddressDescriptors), + MqttDescriptor = descriptor.MqttDescriptor + })); + + return Task.FromResult(routes.AsEnumerable()); + } + + + private IEnumerable CreateAddress(IEnumerable descriptors) + { + if (descriptors == null) + yield break; + + foreach (var descriptor in descriptors) + { + _addressModel.TryGetValue(descriptor.Value, out AddressModel address); + if (address == null) + { + address = (AddressModel)_serializer.Deserialize(descriptor.Value, typeof(IpAddressModel)); + _addressModel.TryAdd(descriptor.Value, address); + } + yield return address; + } + } + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Implementation/ServerMqttHandlerService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Implementation/ServerMqttHandlerService.cs new file mode 100644 index 000000000..cceeb2701 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Implementation/ServerMqttHandlerService.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections.Generic; +using System.Text; +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Transport.Channels; +using Microsoft.Extensions.Logging; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using System.Linq; +using Surging.Core.Protocol.Mqtt.Internal.Services; +using Surging.Core.Protocol.Mqtt.Internal.Runtime; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform; +using System.Diagnostics; +using Surging.Core.CPlatform.Diagnostics; + +namespace Surging.Core.Protocol.Mqtt.Implementation +{ + public class ServerMqttHandlerService + { + private readonly ILogger _logger; + private readonly IChannelService _channelService; + private readonly IMqttBehaviorProvider _mqttBehaviorProvider; + private readonly DiagnosticListener _diagnosticListener; + + public ServerMqttHandlerService( + ILogger logger, IChannelService channelService, IMqttBehaviorProvider mqttBehaviorProvider) + { + _logger = logger; + _channelService = channelService; + _mqttBehaviorProvider = mqttBehaviorProvider; + _diagnosticListener = new DiagnosticListener(DiagnosticListenerExtensions.DiagnosticListenerName); + } + + public async Task ConnAck(IChannelHandlerContext context, ConnAckPacket packet) + { + await context.WriteAndFlushAsync(packet); + } + + public async Task Login(IChannelHandlerContext context, ConnectPacket packet) + { + + string deviceId = packet.ClientId; + var message = TransportMessage.CreateInvokeMessage(new RemoteInvokeMessage() { ServiceId = $"Connect", Parameters = new Dictionary { { "packet", packet} } }); + WirteDiagnosticBefore(message,context.Channel.RemoteAddress.ToString(), deviceId, packet.PacketType); + if (string.IsNullOrEmpty(deviceId)) + { + await ConnAck(context, new ConnAckPacket + { + ReturnCode = ConnectReturnCode.RefusedIdentifierRejected + }); + return; + } + + var mqttBehavior = _mqttBehaviorProvider.GetMqttBehavior(); + if (mqttBehavior != null) + { + if (packet.HasPassword && packet.HasUsername + && await mqttBehavior.Authorized(packet.Username, packet.Password)) + { + var mqttChannel = _channelService.GetMqttChannel(deviceId); + if (mqttChannel == null || !await mqttChannel.IsOnine()) + { + byte[] bytes = null; + if (packet.WillMessage != null) + { + bytes = new byte[packet.WillMessage.ReadableBytes]; + packet.WillMessage.ReadBytes(bytes); + } + await _channelService.Login(context.Channel, deviceId, new ConnectMessage + { + CleanSession = packet.CleanSession, + ClientId = packet.ClientId, + Duplicate = packet.Duplicate, + HasPassword = packet.HasPassword, + HasUsername = packet.HasUsername, + HasWill = packet.HasWill, + KeepAliveInSeconds = packet.KeepAliveInSeconds, + Password = packet.Password, + ProtocolLevel = packet.ProtocolLevel, + ProtocolName = packet.ProtocolName, + Qos = (int)packet.QualityOfService, + RetainRequested = packet.RetainRequested, + Username = packet.Username, + WillMessage = bytes, + WillQualityOfService = (int)packet.WillQualityOfService, + WillRetain = packet.WillRetain, + WillTopic = packet.WillTopicName + + }); + } + } + else + { + await ConnAck(context, new ConnAckPacket + { + ReturnCode = ConnectReturnCode.RefusedBadUsernameOrPassword + }); + } + } + else + { + await ConnAck(context, new ConnAckPacket + { + ReturnCode = ConnectReturnCode.RefusedServerUnavailable + }); + } + WirteDiagnosticAfter(message); + } + + public async Task Disconnect(IChannelHandlerContext context, DisconnectPacket packet) + { + var deviceId = await _channelService.GetDeviceId(context.Channel); + var message = TransportMessage.CreateInvokeMessage(new RemoteInvokeMessage() { ServiceId = $"Disconnect", Parameters = new Dictionary { { "packet", packet } } }); + WirteDiagnosticBefore(message,context.Channel.RemoteAddress.ToString(), deviceId, packet.PacketType); + await _channelService.Close(deviceId, true); + WirteDiagnosticAfter(message); + + } + + public async Task PingReq(IChannelHandlerContext context, PingReqPacket packet) + { + var channel = context.Channel; + if (channel.Open && channel.Active && channel.IsWritable) + { + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("收到来自:【" + context.Channel.RemoteAddress.ToString() + "】心跳"); + await _channelService.PingReq(context.Channel); + await PingResp(context, PingRespPacket.Instance); + } + } + + public async Task PingResp(IChannelHandlerContext context, PingRespPacket packet) + { + await context.WriteAndFlushAsync(packet); + } + + public async Task PubAck(IChannelHandlerContext context, PubAckPacket packet) + { + int messageId = packet.PacketId; + var mqttChannel = _channelService.GetMqttChannel(await _channelService.GetDeviceId(context.Channel)); + var message = mqttChannel.GetMqttMessage(messageId); + if (message != null) + { + message.ConfirmStatus = ConfirmStatus.COMPLETE; + } + await context.WriteAndFlushAsync(packet); + } + + public async Task PubComp(IChannelHandlerContext context, PubCompPacket packet) + { + int messageId = packet.PacketId; + var mqttChannel = _channelService.GetMqttChannel(await _channelService.GetDeviceId(context.Channel)); + var message = mqttChannel.GetMqttMessage(messageId); + if (message != null) + { + message.ConfirmStatus = ConfirmStatus.COMPLETE; + } + await context.WriteAndFlushAsync(packet); + } + + public async Task Publish(IChannelHandlerContext context, PublishPacket packet) + { + await _channelService.Publish(context.Channel, packet); + } + + public async Task PubRec(IChannelHandlerContext context, PubRecPacket packet) + { + int messageId = packet.PacketId; + var mqttChannel = _channelService.GetMqttChannel(await _channelService.GetDeviceId(context.Channel)); + var message= mqttChannel.GetMqttMessage(messageId); + if (message != null) + { + message.ConfirmStatus = ConfirmStatus.PUBREC; + } + await _channelService.Pubrec(mqttChannel, messageId); + } + + public async Task PubRel(IChannelHandlerContext context, PubRelPacket packet) + { + int messageId = packet.PacketId; + var mqttChannel = _channelService.GetMqttChannel(await _channelService.GetDeviceId(context.Channel)); + var message = mqttChannel.GetMqttMessage(messageId); + if (message != null) + { + message.ConfirmStatus = ConfirmStatus.PUBREL; + } + await _channelService.Pubrel(context.Channel, messageId); + } + + public async Task SubAck(IChannelHandlerContext context, SubAckPacket packet) + { + await context.WriteAndFlushAsync(packet); + } + + public async Task Subscribe(IChannelHandlerContext context, SubscribePacket packet) + { + if (packet != null) + { + var deviceId= await _channelService.GetDeviceId(context.Channel); + var topics = packet.Requests.Select(p => p.TopicFilter).ToArray(); + var message = TransportMessage.CreateInvokeMessage(new RemoteInvokeMessage() { ServiceId = $"Subscribe", Parameters=new Dictionary { { "packet", packet } } }); + WirteDiagnosticBefore(message,context.Channel.RemoteAddress.ToString(), deviceId, packet.PacketType); + await _channelService.Suscribe(deviceId, topics); + await SubAck(context, SubAckPacket.InResponseTo(packet, QualityOfService.ExactlyOnce)); + WirteDiagnosticAfter(message); + } + } + + public async Task UnsubAck(IChannelHandlerContext context, UnsubAckPacket packet) + { + await context.WriteAndFlushAsync(packet); + } + + public async Task Unsubscribe(IChannelHandlerContext context, UnsubscribePacket packet) + { + string [] topics = packet.TopicFilters.ToArray(); + var deviceId = await _channelService.GetDeviceId(context.Channel); + var message = TransportMessage.CreateInvokeMessage(new RemoteInvokeMessage() { ServiceId = $"Unsubscribe", Parameters = new Dictionary { { "packet", packet } } }); + WirteDiagnosticBefore(message, context.Channel.RemoteAddress.ToString(), deviceId, packet.PacketType); + await _channelService.UnSubscribe(deviceId, topics); + await UnsubAck(context, UnsubAckPacket.InResponseTo(packet)); + WirteDiagnosticAfter(message); + } + + private void WirteDiagnosticBefore(TransportMessage message,string address, string traceId, PacketType packetType) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + var remoteInvokeMessage = message.GetContent(); + _diagnosticListener.WriteTransportBefore(TransportType.Mqtt, new TransportEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id, + MessageName = remoteInvokeMessage.ServiceId + }, packetType.ToString(), + traceId,address )); + } + } + + private void WirteDiagnosticAfter(TransportMessage message) + { + if (!AppConfig.ServerOptions.DisableDiagnostic) + { + _diagnosticListener.WriteTransportAfter(TransportType.Mqtt, new ReceiveEventData(new DiagnosticMessage + { + Content = message.Content, + ContentType = message.ContentType, + Id = message.Id + })); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Channel/MqttChannel.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Channel/MqttChannel.cs new file mode 100644 index 000000000..f943cec0e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Channel/MqttChannel.cs @@ -0,0 +1,86 @@ +using DotNetty.Common.Utilities; +using DotNetty.Transport.Channels; +using Surging.Core.CPlatform; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Channel +{ + public class MqttChannel + { + public IChannel Channel { get; set; } + public string ClientId { get; set; } + public bool IsWill { get; set; } + public SubscribeStatus SubscribeStatus { get; set; } + public List Topics { get; set; } + public SessionStatus SessionStatus { get; set; } + public int KeepAliveInSeconds { get; set; } + public DateTime PingReqTime { get; set; } = DateTime.Now; + + public bool CleanSession { get; set; } + public ConcurrentDictionary Messages { get; set; } + + public void AddMqttMessage(int messageId, SendMqttMessage msg) + { + Messages.AddOrUpdate(messageId, msg,(id,message)=>msg); + } + + public SendMqttMessage GetMqttMessage(int messageId) + { + SendMqttMessage mqttMessage = null; + Messages.TryGetValue(messageId, out mqttMessage); + return mqttMessage; + } + + + public void RemoveMqttMessage(int messageId) + { + SendMqttMessage mqttMessage = null; + Messages.Remove(messageId,out mqttMessage); + } + + public bool IsLogin() + { + bool result = false; + if (Channel != null) + { + AttributeKey _login = AttributeKey.ValueOf("login"); + result= Channel.Active && Channel.HasAttribute(_login); + } + return result; + } + + public async Task Close() + { + if (Channel != null) + await Channel.CloseAsync(); + } + + + public async Task IsOnine() + { + //如果保持连接的值非零,并且服务端在2倍的保持连接时间内没有收到客户端的报文,需要断开客户端的连接 + bool isOnline= (DateTime.Now - PingReqTime).TotalSeconds <= (this.KeepAliveInSeconds*2) && SessionStatus== SessionStatus.OPEN; + if(!isOnline) + { + await Close(); + } + return isOnline; + } + + public bool IsActive() + { + return Channel != null && Channel.Active; + } + + public void AddTopic(params string[] topics) + { + Topics.AddRange(topics); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/Behavior.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/Behavior.cs new file mode 100644 index 000000000..b2b4db088 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/Behavior.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public enum Behavior + { + Publish, + Suscribe, + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/ConfirmStatus.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/ConfirmStatus.cs new file mode 100644 index 000000000..9b10580e0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/ConfirmStatus.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public enum ConfirmStatus + { + PUB, + PUBREC, + PUBREL, + COMPLETE, + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/ConnReturnCode.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/ConnReturnCode.cs new file mode 100644 index 000000000..c19ba4255 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/ConnReturnCode.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public enum ConnReturnCode + { + Accepted = 0x00, + RefusedUnacceptableProtocolVersion = 0X01, + RefusedIdentifierRejected = 0x02, + RefusedServerUnavailable = 0x03, + RefusedBadUsernameOrPassword = 0x04, + RefusedNotAuthorized = 0x05 + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/MessageType.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/MessageType.cs new file mode 100644 index 000000000..aa6efa2b2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/MessageType.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public enum MessageType + { + CONNECT = 1, + CONNACK = 2, + PUBLISH = 3, + PUBACK = 4, + PUBREC = 5, + PUBREL = 6, + PUBCOMP = 7, + SUBSCRIBE = 8, + SUBACK = 9, + UNSUBSCRIBE = 10, + UNSUBACK = 11, + PINGREQ = 12, + PINGRESP = 13, + DISCONNECT = 14 + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/SessionStatus.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/SessionStatus.cs new file mode 100644 index 000000000..0f8c91c4f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/SessionStatus.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public enum SessionStatus + { + OPEN, + CLOSE + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/SubscribeStatus.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/SubscribeStatus.cs new file mode 100644 index 000000000..5e0486066 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Enums/SubscribeStatus.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public enum SubscribeStatus + { + Yes, + No + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/ConnectMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/ConnectMessage.cs new file mode 100644 index 000000000..86f7a5c23 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/ConnectMessage.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public class ConnectMessage:MqttMessage + { + public override MessageType MessageType => MessageType.CONNECT; + public string ProtocolName { get; set; } + + public int ProtocolLevel { get; set; } + + public bool CleanSession { get; set; } + + public bool HasWill { get; set; } + + public int WillQualityOfService { get; set; } + + public bool WillRetain { get; set; } + + public bool HasPassword { get; set; } + + public bool HasUsername { get; set; } + + public int KeepAliveInSeconds { get; set; } + + public string Username { get; set; } + + public string Password { get; set; } + + public string ClientId { get; set; } + + public string WillTopic { get; set; } + + public byte[] WillMessage { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/MqttMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/MqttMessage.cs new file mode 100644 index 000000000..e3191dbf0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/MqttMessage.cs @@ -0,0 +1,22 @@ +using DotNetty.Codecs.Mqtt.Packets; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Enums +{ + public abstract class MqttMessage + { + public abstract MessageType MessageType { get; } + + public virtual bool Duplicate { get; set; } + public virtual int Qos { get; set; } =(int) QualityOfService.AtMostOnce; + public virtual bool RetainRequested { get; set; } + + + public override string ToString() + { + return $"{this.GetType().Name}[Qos={this.Qos}, Duplicate={this.Duplicate}, Retain={this.RetainRequested}]"; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/MqttWillMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/MqttWillMessage.cs new file mode 100644 index 000000000..4968ef511 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/MqttWillMessage.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Messages +{ + public class MqttWillMessage + { + public string Topic{ get; set; } + + public string WillMessage { get; set; } + + + public bool WillRetain { get; set; } + + public int Qos { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/RetainMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/RetainMessage.cs new file mode 100644 index 000000000..b937eabd1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/RetainMessage.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Messages +{ + public class RetainMessage + { + public byte[] ByteBuf { get; set; } + + public int QoS { get; set; } + public new string ToString => Encoding.UTF8.GetString(ByteBuf); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/SendMqttMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/SendMqttMessage.cs new file mode 100644 index 000000000..8e82024a1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/SendMqttMessage.cs @@ -0,0 +1,27 @@ +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Messages +{ + public class SendMqttMessage + { + public int MessageId { get; set; } + + public IChannel Channel { get; set; } + + public ConfirmStatus ConfirmStatus { get; set; } + + public long Time { get; set; } + + public byte[] ByteBuf { get; set; } + + public bool Retain { get; set; } + + public int Qos { get; set; } + + public string Topic { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/SessionMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/SessionMessage.cs new file mode 100644 index 000000000..aa5bdd080 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Messages/SessionMessage.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Messages +{ + public class SessionMessage + { + public byte[] Message { get; set; } + + public int QoS { get; set; } + + public string Topic { get; set; } + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttBehaviorProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttBehaviorProvider.cs new file mode 100644 index 000000000..c95c13539 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttBehaviorProvider.cs @@ -0,0 +1,12 @@ +using Surging.Core.Protocol.Mqtt.Internal.Services; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public interface IMqttBehaviorProvider + { + MqttBehavior GetMqttBehavior(); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttBrokerEntryManger.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttBrokerEntryManger.cs new file mode 100644 index 000000000..e48fa5d5a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttBrokerEntryManger.cs @@ -0,0 +1,17 @@ +using Surging.Core.CPlatform.Address; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public interface IMqttBrokerEntryManger + { + ValueTask> GetMqttBrokerAddress(string topic); + + Task CancellationReg(string topic,AddressModel addressModel); + + Task Register(string topic, AddressModel addressModel); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttRemoteInvokeService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttRemoteInvokeService.cs new file mode 100644 index 000000000..519a85bd4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttRemoteInvokeService.cs @@ -0,0 +1,19 @@ +using Surging.Core.CPlatform.Runtime.Client; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public interface IMqttRemoteInvokeService + { + + Task InvokeAsync(RemoteInvokeContext context); + + Task InvokeAsync(RemoteInvokeContext context, CancellationToken cancellationToken); + + Task InvokeAsync(RemoteInvokeContext context, int requestTimeout); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttRomtePublishService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttRomtePublishService.cs new file mode 100644 index 000000000..ab7a4182b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/IMqttRomtePublishService.cs @@ -0,0 +1,19 @@ +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers.Implementation.Selectors.Implementation; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using Surging.Core.CPlatform.Support.Attributes; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + [ServiceBundle("Device")] + public interface IMqttRomtePublishService : IServiceKey + { + [Command(ShuntStrategy = AddressSelectorMode.HashAlgorithm)] + Task Publish(string deviceId, MqttWillMessage message); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/DefaultMqttBehaviorProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/DefaultMqttBehaviorProvider.cs new file mode 100644 index 000000000..33ab3dba6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/DefaultMqttBehaviorProvider.cs @@ -0,0 +1,38 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.Protocol.Mqtt.Internal.Services; +using System.Linq; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime.Implementation +{ + public class DefaultMqttBehaviorProvider : IMqttBehaviorProvider + { + #region Field + + private readonly IServiceEntryProvider _serviceEntryProvider; + private readonly CPlatformContainer _serviceProvider; + private MqttBehavior _mqttBehavior; + + #endregion Field + + #region Constructor + + public DefaultMqttBehaviorProvider(IServiceEntryProvider serviceEntryProvider, CPlatformContainer serviceProvider) + { + _serviceEntryProvider = serviceEntryProvider; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + public MqttBehavior GetMqttBehavior() + { + if (_mqttBehavior == null) + { + _mqttBehavior = _serviceEntryProvider.GetTypes() + .Select(type=> _serviceProvider.GetInstances(type) as MqttBehavior ).Where(p=>p!=null).FirstOrDefault(); + } + return _mqttBehavior; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/DefaultMqttBrokerEntryManager.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/DefaultMqttBrokerEntryManager.cs new file mode 100644 index 000000000..85d041d1a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/DefaultMqttBrokerEntryManager.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Mqtt; +using Surging.Core.CPlatform.Mqtt.Implementation; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks.Implementation; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime.Implementation +{ + public class DefaultMqttBrokerEntryManager : IMqttBrokerEntryManger + { + private readonly IMqttServiceRouteManager _mqttServiceRouteManager; + private readonly ILogger _logger; + private readonly ConcurrentDictionary> _brokerEntries = + new ConcurrentDictionary>(); + + public DefaultMqttBrokerEntryManager(IMqttServiceRouteManager mqttServiceRouteManager, + ILogger logger, IHealthCheckService healthCheckService) + { + _mqttServiceRouteManager = mqttServiceRouteManager; + _logger = logger; + _mqttServiceRouteManager.Changed += MqttRouteManager_Removed; + _mqttServiceRouteManager.Removed += MqttRouteManager_Removed; + healthCheckService.Removed += MqttRouteManager_Removed; + } + + public async Task CancellationReg(string topic, AddressModel addressModel) + { + await _mqttServiceRouteManager.RemoveByTopicAsync(topic, new AddressModel[] { addressModel }); + } + + public async ValueTask> GetMqttBrokerAddress(string topic) + { + _brokerEntries.TryGetValue(topic, out IEnumerable addresses); + if (addresses==null || !addresses.Any()) + { + var routes = await _mqttServiceRouteManager.GetRoutesAsync(); + var route= routes.Where(p => p.MqttDescriptor.Topic == topic).SingleOrDefault(); + if (route != null) + { + _brokerEntries.TryAdd(topic, route.MqttEndpoint); + addresses = route.MqttEndpoint; + } + } + return addresses; + } + + public async Task Register(string topic, AddressModel addressModel) + { + await _mqttServiceRouteManager.SetRoutesAsync(new MqttServiceRoute[] { new MqttServiceRoute { + MqttDescriptor=new MqttDescriptor{ + Topic=topic + }, + MqttEndpoint=new AddressModel[]{ + addressModel + } + } + }); + } + + private static string GetCacheKey(MqttDescriptor descriptor) + { + return descriptor.Topic; + } + + private void MqttRouteManager_Removed(object sender, MqttServiceRouteEventArgs e) + { + var key = GetCacheKey(e.Route.MqttDescriptor); + _brokerEntries.TryRemove(key, out IEnumerable value); + } + + private void MqttRouteManager_Removed(object sender, HealthCheckEventArgs e) + { + if(!e.Health) + _mqttServiceRouteManager.RemveAddressAsync(new AddressModel[] { e.Address }); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/MqttRemoteInvokeService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/MqttRemoteInvokeService.cs new file mode 100644 index 000000000..06e61a570 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/MqttRemoteInvokeService.cs @@ -0,0 +1,114 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform.Exceptions; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Client; +using Surging.Core.CPlatform.Runtime.Client.Address.Resolvers; +using Surging.Core.CPlatform.Runtime.Client.HealthChecks; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime.Implementation +{ + public class MqttRemoteInvokeService:IMqttRemoteInvokeService + { + private readonly ITransportClientFactory _transportClientFactory; + private readonly ILogger _logger; + private readonly IHealthCheckService _healthCheckService; + private readonly IMqttBrokerEntryManger _mqttBrokerEntryManger; + + public MqttRemoteInvokeService( ITransportClientFactory transportClientFactory, + ILogger logger, + IHealthCheckService healthCheckService, + IMqttBrokerEntryManger mqttBrokerEntryManger) + { + _transportClientFactory = transportClientFactory; + _logger = logger; + _healthCheckService = healthCheckService; + _mqttBrokerEntryManger = mqttBrokerEntryManger; + } + + #region Implementation of IRemoteInvokeService + + public async Task InvokeAsync(RemoteInvokeContext context) + { + await InvokeAsync(context, Task.Factory.CancellationToken); + } + + public async Task InvokeAsync(RemoteInvokeContext context, CancellationToken cancellationToken) + { + var mqttContext = context as MqttRemoteInvokeContext; + if (mqttContext != null) + { + var invokeMessage = context.InvokeMessage; + var host= NetUtils.GetHostAddress(); + var addresses = await _mqttBrokerEntryManger.GetMqttBrokerAddress(mqttContext.topic); + addresses = addresses.Except(new AddressModel[] { host }); + foreach (var address in addresses) + { + try + { + var endPoint = address.CreateEndPoint(); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"使用地址:'{endPoint}'进行调用。"); + var client =await _transportClientFactory.CreateClientAsync(endPoint); + await client.SendAsync(invokeMessage, cancellationToken).WithCancellation(cancellationToken); + } + catch (CommunicationException) + { + await _healthCheckService.MarkFailure(address); + } + catch (Exception exception) + { + _logger.LogError(exception, $"发起请求中发生了错误,服务Id:{invokeMessage.ServiceId}。"); + } + } + } + } + + public async Task InvokeAsync(RemoteInvokeContext context, int requestTimeout) + { + var mqttContext = context as MqttRemoteInvokeContext; + if (mqttContext != null) + { + var invokeMessage = context.InvokeMessage; + var host = NetUtils.GetHostAddress(); + var addresses = await _mqttBrokerEntryManger.GetMqttBrokerAddress(mqttContext.topic); + if (addresses != null) + { + addresses = addresses.Except(new AddressModel[] { host }); + foreach (var address in addresses) + { + try + { + var endPoint = address.CreateEndPoint(); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"使用地址:'{endPoint}'进行调用。"); + var client =await _transportClientFactory.CreateClientAsync(endPoint); + using (var cts = new CancellationTokenSource()) + { + await client.SendAsync(invokeMessage,cts.Token).WithCancellation(cts,requestTimeout); + } + } + catch (CommunicationException) + { + await _healthCheckService.MarkFailure(address); + } + catch (Exception exception) + { + _logger.LogError(exception, $"发起mqtt请求中发生了错误,服务Id:{invokeMessage.ServiceId}。"); + + } + } + } + } + } + + + #endregion Implementation of IRemoteInvokeService + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/MqttRomtePublishService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/MqttRomtePublishService.cs new file mode 100644 index 000000000..eb01b8401 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Implementation/MqttRomtePublishService.cs @@ -0,0 +1,19 @@ +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using Surging.Core.Protocol.Mqtt.Internal.Services; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime.Implementation +{ + public class MqttRomtePublishService : ServiceBase, IMqttRomtePublishService + { + public async Task Publish(string deviceId, MqttWillMessage message) + { + await ServiceLocator.GetService().Publish(deviceId, message); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/MqttRemoteInvokeContext.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/MqttRemoteInvokeContext.cs new file mode 100644 index 000000000..843652bc0 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/MqttRemoteInvokeContext.cs @@ -0,0 +1,13 @@ +using Surging.Core.CPlatform.Runtime.Client; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public class MqttRemoteInvokeContext: RemoteInvokeContext + { + public string topic { get; set; } + } +} + \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Runnable.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Runnable.cs new file mode 100644 index 000000000..51c731314 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/Runnable.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public abstract class Runnable + { + private volatile Thread _runnableThread; + private readonly Timer _timer; + public Runnable() + { + var timeSpan = TimeSpan.FromSeconds(3); + _timer = new Timer(s => + { + Run(); + }, null, timeSpan, timeSpan); + } + + public abstract void Run(); + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/SacnScheduled.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/SacnScheduled.cs new file mode 100644 index 000000000..3a3deeb18 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/SacnScheduled.cs @@ -0,0 +1,73 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public class SacnScheduled: ScanRunnable + { + + public SacnScheduled() + { + } + + private bool CheckTime(long time) + { + return DateTime.Now.Millisecond - time >= 10 * 1000; + } + + public override void Execute(SendMqttMessage poll) + { + if (CheckTime(poll.Time) && poll.Channel.Active) + { + poll.Time=DateTime.Now.Ticks / 10000; + switch (poll.ConfirmStatus) + { + case ConfirmStatus.PUB: + PubMessage(poll.Channel, poll); + break; + case ConfirmStatus.PUBREL: + PubRelAck(poll); + break; + case ConfirmStatus.PUBREC: + PubRecAck(poll); + break; + } + } + } + + private void PubMessage(IChannel channel, SendMqttMessage mqttMessage) + { + PublishPacket mqttPublishMessage = new PublishPacket((QualityOfService)mqttMessage.Qos, true, mqttMessage.Retain) + { + TopicName = mqttMessage.Topic, + PacketId = mqttMessage.MessageId, + Payload = Unpooled.WrappedBuffer(mqttMessage.ByteBuf) + }; + channel.WriteAndFlushAsync(mqttPublishMessage); + } + + protected void PubRelAck( SendMqttMessage mqttMessage) + { + PubRelPacket mqttPubAckMessage = new PubRelPacket() + { + PacketId = mqttMessage.MessageId, + }; + mqttMessage.Channel.WriteAndFlushAsync(mqttPubAckMessage); + } + + private void PubRecAck(SendMqttMessage mqttMessage) + { + PubRecPacket mqttPubAckMessage = new PubRecPacket() + { + PacketId = mqttMessage.MessageId, + }; + mqttMessage.Channel.WriteAndFlushAsync(mqttPubAckMessage); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/ScanRunnable.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/ScanRunnable.cs new file mode 100644 index 000000000..d9378c4bf --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Runtime/ScanRunnable.cs @@ -0,0 +1,41 @@ +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Surging.Core.Protocol.Mqtt.Internal.Runtime +{ + public abstract class ScanRunnable : Runnable + { + private ConcurrentQueue _queue = new ConcurrentQueue(); + public void Enqueue(SendMqttMessage t) + { + _queue.Enqueue(t); + } + + public void Enqueue(List ts) + { + ts.ForEach(message=> _queue.Enqueue(message)); + } + + public override void Run() + { + if (!_queue.IsEmpty) + { + List list = new List(); + for (; (_queue.TryDequeue(out SendMqttMessage poll));) + { + if (poll.ConfirmStatus != ConfirmStatus.COMPLETE) + { + list.Add(poll); + Execute(poll); + } + break; + } + } + } + + public abstract void Execute(SendMqttMessage poll); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/AbstractChannelService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/AbstractChannelService.cs new file mode 100644 index 000000000..91a0b210c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/AbstractChannelService.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; +using DotNetty.Common.Utilities; +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System.Collections; +using System.Linq; +using DotNetty.Codecs.Mqtt.Packets; +using System.Threading.Tasks; +using Surging.Core.Protocol.Mqtt.Internal.Runtime; +using System.Net; +using Surging.Core.CPlatform.Address; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Ids; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services +{ + public abstract class AbstractChannelService : IChannelService + { + private readonly AttributeKey _loginAttrKey = AttributeKey.ValueOf("login"); + private readonly AttributeKey _deviceIdAttrKey = AttributeKey.ValueOf("deviceId"); + private readonly IMessagePushService _messagePushService; + private readonly ConcurrentDictionary> _topics = new ConcurrentDictionary>(); + private readonly ConcurrentDictionary _mqttChannels = new ConcurrentDictionary(); + protected readonly ConcurrentDictionary> _retain = new ConcurrentDictionary>(); + private readonly IMqttBrokerEntryManger _mqttBrokerEntryManger; + private readonly IMqttRemoteInvokeService _mqttRemoteInvokeService; + private readonly string _publishServiceId; + + public AbstractChannelService(IMessagePushService messagePushService, + IMqttBrokerEntryManger mqttBrokerEntryManger, + IMqttRemoteInvokeService mqttRemoteInvokeService, + IServiceIdGenerator serviceIdGenerator + ) + { + _messagePushService = messagePushService; + _mqttBrokerEntryManger = mqttBrokerEntryManger; + _mqttRemoteInvokeService = mqttRemoteInvokeService; + _publishServiceId= serviceIdGenerator.GenerateServiceId(typeof(IMqttRomtePublishService).GetMethod("Publish")); + } + + public ConcurrentDictionary MqttChannels { get { + return _mqttChannels; + } + } + + public AttributeKey DeviceIdAttrKey + { + get + { + return _deviceIdAttrKey; + } + } + + public AttributeKey LoginAttrKey + { + get + { + return _loginAttrKey; + } + } + + public ConcurrentDictionary> Topics + { + get + { + return _topics; + } + } + + public ConcurrentDictionary> Retain + { + get + { + return _retain; + } + } + + public abstract Task Close(string deviceId, bool isDisconnect); + + public abstract Task Connect(string deviceId, MqttChannel build); + + public bool RemoveChannel(string topic, MqttChannel mqttChannel) + { + var result = false; + if (!string.IsNullOrEmpty(topic) && mqttChannel != null) + { + _topics.TryGetValue(topic, out IEnumerable mqttChannels); + var channels = mqttChannels == null ? new List() : mqttChannels.ToList(); + channels.Remove(mqttChannel); + _topics.AddOrUpdate(topic, channels, (key, value) => channels); + result = true; + } + return result; + } + + public async ValueTask GetDeviceId(IChannel channel) + { + string deviceId = null; + if (channel != null) + { + deviceId = channel.GetAttribute(DeviceIdAttrKey).Get(); + } + return await new ValueTask(deviceId); + } + + public bool AddChannel(string topic, MqttChannel mqttChannel) + { + var result = false; + if (!string.IsNullOrEmpty(topic) && mqttChannel != null) + { + _topics.TryGetValue(topic, out IEnumerable mqttChannels); + var channels = mqttChannels==null ? new List(): mqttChannels.ToList(); + channels.Add(mqttChannel); + _topics.AddOrUpdate(topic, channels, (key, value) => channels); + result = true; + } + return result; + } + + public MqttChannel GetMqttChannel(string deviceId) + { + MqttChannel channel = null; + if (!string.IsNullOrEmpty(deviceId)) + { + _mqttChannels.TryGetValue(deviceId, out channel); + } + return channel; + } + + protected async Task RegisterMqttBroker(string topic) + { + var addresses = await _mqttBrokerEntryManger.GetMqttBrokerAddress(topic); + var host = NetUtils.GetHostAddress(); + if (addresses==null || !addresses.Any(p => p.ToString() == host.ToString())) + await _mqttBrokerEntryManger.Register(topic, host); + } + + protected async Task BrokerCancellationReg(string topic) + { + if (Topics.ContainsKey(topic)) + { + if (Topics[topic].Count() == 0) + await _mqttBrokerEntryManger.CancellationReg(topic, NetUtils.GetHostAddress()); + } + else + { + await _mqttBrokerEntryManger.CancellationReg(topic, NetUtils.GetHostAddress()); + } + } + + public async Task RemotePublishMessage(string deviceId, MqttWillMessage willMessage) + { + await _mqttRemoteInvokeService.InvokeAsync(new MqttRemoteInvokeContext + { + topic = willMessage.Topic, + InvokeMessage = new RemoteInvokeMessage + { + ServiceId = _publishServiceId, + Parameters = new Dictionary() { + {"deviceId",deviceId}, + { "message",willMessage} + } + }, + + }, AppConfig.ServerOptions.ExecutionTimeoutInMilliseconds); + } + + public abstract Task Login(IChannel channel, string deviceId, ConnectMessage mqttConnectMessage); + + public abstract Task Publish(IChannel channel, PublishPacket mqttPublishMessage); + + public abstract Task Pubrec(MqttChannel channel, int messageId); + + public abstract ValueTask PingReq(IChannel channel); + + public abstract Task Pubrel(IChannel channel, int messageId); + + public abstract Task SendWillMsg(MqttWillMessage willMeaasge); + public abstract Task Suscribe(string deviceId, params string[] topics); + + public abstract Task UnSubscribe(string deviceId, params string[] topics); + + public abstract Task Publish(string deviceId, MqttWillMessage willMessage); + + public async ValueTask GetDeviceIsOnine(string deviceId) + { + bool result = false; + if (!string.IsNullOrEmpty(deviceId)) + { + MqttChannels.TryGetValue(deviceId, out MqttChannel mqttChannel); + result = mqttChannel==null?false: await mqttChannel.IsOnine(); + } + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IChannelService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IChannelService.cs new file mode 100644 index 000000000..921f96ca5 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IChannelService.cs @@ -0,0 +1,60 @@ +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services +{ + public interface IChannelService + { + /// + /// 获取mqtt通道 + /// + /// + /// + MqttChannel GetMqttChannel(string deviceId); + /// + /// 获取设备是否连接 + /// + /// + /// + /// + Task Connect(string deviceId, MqttChannel mqttChannel); + /// + /// 订阅 + /// + /// + /// 主题列表 + /// + Task Suscribe(String deviceId, params string[] topics); + Task Login(IChannel channel, string deviceId, ConnectMessage mqttConnectMessage); + /// + /// 发布 + /// + /// + /// + /// + Task Publish(IChannel channel, PublishPacket mqttPublishMessage); + ValueTask PingReq(IChannel channel); + Task Publish(string deviceId, MqttWillMessage willMessage); + Task RemotePublishMessage(string deviceId, MqttWillMessage willMessage); + Task Close(string deviceId, bool isDisconnect); + ValueTask GetDeviceIsOnine(string deviceId); + Task SendWillMsg(MqttWillMessage willMeaasge); + ValueTask GetDeviceId(IChannel channel); + /// + /// 取消订阅 + /// + /// + /// + /// + Task UnSubscribe(string deviceId, params string[] topics); + Task Pubrel(IChannel channel, int messageId); + Task Pubrec(MqttChannel channel, int messageId); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IClientSessionService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IClientSessionService.cs new file mode 100644 index 000000000..9c9ad7556 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IClientSessionService.cs @@ -0,0 +1,15 @@ +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services +{ + public interface IClientSessionService + { + void SaveMessage(string deviceId, SessionMessage sessionMessage); + + ConcurrentQueue GetMessages(string deviceId); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IMessagePushService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IMessagePushService.cs new file mode 100644 index 000000000..43e43287e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IMessagePushService.cs @@ -0,0 +1,28 @@ +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services +{ + public interface IMessagePushService + { + Task WriteWillMsg(MqttChannel mqttChannel, MqttWillMessage willMeaasge); + + Task SendQosConfirmMsg(QualityOfService qos, MqttChannel mqttChannel, string topic, byte[] bytes); + + Task SendPubBack(IChannel channel, int messageId); + + Task SendPubRec(MqttChannel mqttChannel, int messageId); + + Task SendPubRel(IChannel channel, int messageId); + + Task SendToPubComp(IChannel channel, int messageId); + + Task SendQos0Msg(IChannel channel, String topic, byte[] byteBuf); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IWillService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IWillService.cs new file mode 100644 index 000000000..fc99ed19c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/IWillService.cs @@ -0,0 +1,17 @@ +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services +{ + public interface IWillService + { + void Add(string deviceid, MqttWillMessage willMessage); + + Task SendWillMessage(string deviceId); + + void Remove(string deviceid); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/ClientSessionService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/ClientSessionService.cs new file mode 100644 index 000000000..768d5b48d --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/ClientSessionService.cs @@ -0,0 +1,28 @@ +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Concurrent; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services.Implementation +{ + public class ClientSessionService: IClientSessionService + { + private readonly ConcurrentDictionary> _clientsessionMessages = + new ConcurrentDictionary>(); + + public ConcurrentQueue GetMessages(string deviceId) + { + _clientsessionMessages.TryGetValue(deviceId, out ConcurrentQueue messages); + return messages; + } + + public void SaveMessage(string deviceId, SessionMessage sessionMessage) + { + _clientsessionMessages.TryGetValue(deviceId, out ConcurrentQueue sessionMessages); + _clientsessionMessages.AddOrUpdate(deviceId, sessionMessages, (id, message) => + { + message.Enqueue(sessionMessage); + return sessionMessages; + }); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/MessagePushService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/MessagePushService.cs new file mode 100644 index 000000000..5d6e9cccc --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/MessagePushService.cs @@ -0,0 +1,153 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using Surging.Core.Protocol.Mqtt.Internal.Runtime; +using Surging.Core.Protocol.Mqtt.Util; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services.Implementation +{ + public class MessagePushService:IMessagePushService + { + private readonly ScanRunnable _scanRunnable; + public MessagePushService(ScanRunnable scanRunnable) + { + _scanRunnable = scanRunnable; + } + public async Task WriteWillMsg(MqttChannel mqttChannel, MqttWillMessage willMeaasge) + { + switch (willMeaasge.Qos) + { + case 0: + await SendQos0Msg(mqttChannel.Channel, willMeaasge.Topic, Encoding.Default.GetBytes(willMeaasge.WillMessage)); + break; + case 1: // qos1 + await SendQosConfirmMsg(QualityOfService.AtLeastOnce, mqttChannel, willMeaasge.Topic, Encoding.Default.GetBytes(willMeaasge.WillMessage)); + break; + case 2: // qos2 + await SendQosConfirmMsg(QualityOfService.ExactlyOnce, mqttChannel, willMeaasge.Topic, Encoding.Default.GetBytes(willMeaasge.WillMessage)); + break; + } + + } + + public async Task SendQosConfirmMsg(QualityOfService qos, MqttChannel mqttChannel, string topic, byte[] bytes) + { + if (mqttChannel.IsLogin()) + { + int messageId = MessageIdGenerater.GenerateId(); + switch (qos) + { + case QualityOfService.AtLeastOnce: + mqttChannel.AddMqttMessage(messageId, await SendQos1Msg(mqttChannel.Channel, topic, false, bytes, messageId)); + break; + case QualityOfService.ExactlyOnce: + mqttChannel.AddMqttMessage(messageId,await SendQos2Msg(mqttChannel.Channel, topic, false, bytes, messageId)); + break; + } + } + + } + + private async Task SendQos1Msg(IChannel channel, String topic, bool isDup, byte[] byteBuf, int messageId) + { + var mqttPublishMessage = new PublishPacket(QualityOfService.AtMostOnce, true, true); + mqttPublishMessage.TopicName = topic; + mqttPublishMessage.PacketId = messageId; + mqttPublishMessage.Payload = Unpooled.WrappedBuffer(byteBuf); + await channel.WriteAndFlushAsync(mqttPublishMessage); + return Enqueue(channel, messageId, topic, byteBuf, (int)QualityOfService.AtLeastOnce, ConfirmStatus.PUB); + } + + private async Task SendQos2Msg(IChannel channel, String topic, bool isDup, byte[] byteBuf, int messageId) + { + var mqttPublishMessage = new PublishPacket(QualityOfService.AtMostOnce, true, true); + mqttPublishMessage.TopicName = topic; + mqttPublishMessage.PacketId = messageId; + mqttPublishMessage.Payload = Unpooled.WrappedBuffer(byteBuf); + await channel.WriteAndFlushAsync(mqttPublishMessage); + return Enqueue(channel, messageId, topic, byteBuf, (int)QualityOfService.ExactlyOnce, ConfirmStatus.PUB); + } + + private async Task SendQos0Msg(IChannel channel, String topic, byte[] byteBuf, int messageId) + { + if (channel != null) + { + var mqttPublishMessage = new PublishPacket(QualityOfService.AtMostOnce, true, true); + mqttPublishMessage.TopicName = topic; + mqttPublishMessage.Payload = Unpooled.WrappedBuffer(byteBuf); + await channel.WriteAndFlushAsync(mqttPublishMessage); + } + } + + public async Task SendPubBack(IChannel channel, int messageId) + { + var mqttPubAckMessage = new PubAckPacket() { + PacketId = messageId + }; + await channel.WriteAndFlushAsync(mqttPubAckMessage); + } + + public async Task SendPubRec(MqttChannel mqttChannel, int messageId) + { + var mqttPubAckMessage = new PubRecPacket() + { + PacketId = messageId + }; + var channel = mqttChannel.Channel; + await channel.WriteAndFlushAsync(mqttPubAckMessage); + var sendMqttMessage = Enqueue(channel, messageId, null, null, 1, ConfirmStatus.PUBREC); + mqttChannel.AddMqttMessage(messageId, sendMqttMessage); + } + + public async Task SendPubRel(IChannel channel, int messageId) + { + var mqttPubAckMessage = new PubRelPacket() + { + PacketId = messageId + }; + await channel.WriteAndFlushAsync(mqttPubAckMessage); + } + + public async Task SendToPubComp(IChannel channel, int messageId) + { + var mqttPubAckMessage = new PubCompPacket() + { + PacketId = messageId + }; + await channel.WriteAndFlushAsync(mqttPubAckMessage); + } + + + public async Task SendQos0Msg(IChannel channel, String topic, byte[] byteBuf) + { + if (channel != null) + { + await SendQos0Msg(channel, topic, byteBuf, 0); + } + } + + private SendMqttMessage Enqueue(IChannel channel, int messageId, String topic, byte[] datas, int mqttQoS, ConfirmStatus confirmStatus) + { + var message = new SendMqttMessage + { + ByteBuf = datas, + Channel = channel, + MessageId = messageId, + Qos = mqttQoS, + Time = DateTime.Now.Ticks / 10000, + ConfirmStatus = confirmStatus, + Topic = topic + }; + _scanRunnable.Enqueue(message); + return message; + } + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/MqttChannelService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/MqttChannelService.cs new file mode 100644 index 000000000..d05f6092f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/MqttChannelService.cs @@ -0,0 +1,433 @@ +using System; +using System.Collections.Generic; +using System.Text; +using DotNetty.Transport.Channels; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System.Linq; +using System.Collections.Concurrent; +using DotNetty.Codecs.Mqtt.Packets; +using Microsoft.Extensions.Logging; +using DotNetty.Buffers; +using System.Threading.Tasks; +using Surging.Core.Protocol.Mqtt.Internal.Runtime; +using Surging.Core.CPlatform.Ids; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services.Implementation +{ + public class MqttChannelService : AbstractChannelService + { + private readonly IMessagePushService _messagePushService; + private readonly IClientSessionService _clientSessionService; + private readonly ILogger _logger; + private readonly IWillService _willService; + public MqttChannelService(IMessagePushService messagePushService, IClientSessionService clientSessionService, + ILogger logger, IWillService willService, + IMqttBrokerEntryManger mqttBrokerEntryManger, + IMqttRemoteInvokeService mqttRemoteInvokeService, + IServiceIdGenerator serviceIdGenerator) : + base(messagePushService, + mqttBrokerEntryManger, + mqttRemoteInvokeService, + serviceIdGenerator) + { + _messagePushService = messagePushService; + _clientSessionService = clientSessionService; + _logger = logger; + _willService = willService; + } + + public override async Task Close(string deviceId, bool isDisconnect) + { + if (!string.IsNullOrEmpty(deviceId)) + { + MqttChannels.TryGetValue(deviceId, out MqttChannel mqttChannel); + if (mqttChannel != null) + { + mqttChannel.SessionStatus = SessionStatus.CLOSE; + await mqttChannel.Close(); + mqttChannel.Channel = null; + } + if (!mqttChannel.CleanSession) + { + var messages = mqttChannel.Messages; + if (messages != null) + { + foreach (var sendMqttMessage in messages.Values) + { + if (sendMqttMessage.ConfirmStatus == ConfirmStatus.PUB) + { + _clientSessionService.SaveMessage(mqttChannel.ClientId, new SessionMessage + { + Message = sendMqttMessage.ByteBuf, + QoS = sendMqttMessage.Qos, + Topic = sendMqttMessage.Topic + }); + } + } + } + } + else + { + MqttChannels.TryRemove(deviceId, out MqttChannel channel); + if (mqttChannel.SubscribeStatus == SubscribeStatus.Yes) + { + RemoveSubTopic(mqttChannel); + } + mqttChannel.Topics.ForEach(async topic => { await BrokerCancellationReg(topic); }); + } + if (mqttChannel.IsWill) + { + if (!isDisconnect) + { + await _willService.SendWillMessage(deviceId); + } + } + + } + } + + public override async Task Connect(string deviceId, MqttChannel channel) + { + var mqttChannel = GetMqttChannel(deviceId); + if (mqttChannel != null) + { + if (await mqttChannel.IsOnine()) return false; + else + { + if (mqttChannel.SubscribeStatus == SubscribeStatus.Yes) + { + var topics = RemoveSubTopic(mqttChannel); + foreach (var topic in topics) + { + Topics.TryGetValue(topic, out IEnumerable comparisonValue); + var newValue = comparisonValue.Concat(new[] { channel }); + Topics.AddOrUpdate(topic, newValue, (key, value) => newValue); + } + } + + } + } + MqttChannels.AddOrUpdate(deviceId, channel, (k, v) => channel); + return true; + } + + public override async Task Login(IChannel channel, string deviceId, ConnectMessage mqttConnectMessage) + { + channel.GetAttribute(LoginAttrKey).Set("login"); + channel.GetAttribute(DeviceIdAttrKey).Set(deviceId); + await Init(channel, mqttConnectMessage); + } + + public override async Task Publish(IChannel channel, PublishPacket mqttPublishMessage) + { + MqttChannel mqttChannel = GetMqttChannel(await this.GetDeviceId(channel)); + var buffer = mqttPublishMessage.Payload; + byte[] bytes = new byte[buffer.ReadableBytes]; + buffer.ReadBytes(bytes); + int messageId = mqttPublishMessage.PacketId; + if (channel.HasAttribute(LoginAttrKey) && mqttChannel != null) + { + bool isRetain = mqttPublishMessage.RetainRequested; + switch (mqttPublishMessage.QualityOfService) + { + case QualityOfService.AtLeastOnce: + await _messagePushService.SendPubBack(channel, messageId); + break; + case QualityOfService.ExactlyOnce: + await Pubrec(mqttChannel, messageId); + break; + } + if (isRetain) + { + SaveRetain(mqttPublishMessage.TopicName, + new RetainMessage + { + ByteBuf = bytes, + QoS = (int)mqttPublishMessage.QualityOfService + }, mqttPublishMessage.QualityOfService == QualityOfService.AtMostOnce ? true : false); + } + await PushMessage(mqttPublishMessage.TopicName, (int)mqttPublishMessage.QualityOfService, bytes, isRetain); + await RemotePublishMessage("", new MqttWillMessage + { + Qos = (int)mqttPublishMessage.QualityOfService, + Topic = mqttPublishMessage.TopicName, + WillMessage = Encoding.Default.GetString(bytes), + WillRetain = mqttPublishMessage.RetainRequested + }); + } + } + + public override async Task Publish(string deviceId, MqttWillMessage willMessage) + { + if (!string.IsNullOrEmpty(deviceId)) + { + var mqttChannel = GetMqttChannel(deviceId); + if (mqttChannel != null && await mqttChannel.IsOnine()) + { + await _messagePushService.WriteWillMsg(mqttChannel, willMessage); + } + } + else { await SendWillMsg(willMessage); } + if (willMessage.WillRetain) + SaveRetain(willMessage.Topic, new RetainMessage + { + ByteBuf = Encoding.UTF8.GetBytes(willMessage.WillMessage), + QoS = willMessage.Qos + }, willMessage.Qos == 0 ? true : false); + } + + private async Task PushMessage(string topic, int qos, byte[] bytes, bool isRetain) + { + Topics.TryGetValue(topic, out IEnumerable mqttChannels); + if (mqttChannels != null && mqttChannels.Any()) + { + foreach (var mqttChannel in mqttChannels) + { + if (await mqttChannel.IsOnine()) + { + if (mqttChannel.IsActive()) + { + await SendMessage(mqttChannel, qos, + topic, bytes); + } + else + { + if (!mqttChannel.CleanSession && !isRetain) + { + _clientSessionService.SaveMessage(mqttChannel.ClientId, + new SessionMessage + { + Message = bytes, + QoS = qos, + Topic = topic + }); + break; + } + } + } + else + { + _clientSessionService.SaveMessage(mqttChannel.ClientId, + new SessionMessage + { + Message = bytes, + QoS = qos, + Topic = topic + }); + } + } + } + } + + public override async Task Pubrec(MqttChannel channel, int messageId) + { + await _messagePushService.SendPubRec(channel, messageId); + } + + public override async Task Pubrel(IChannel channel, int messageId) + { + if (MqttChannels.TryGetValue(await this.GetDeviceId(channel), out MqttChannel mqttChannel)) + { + if (mqttChannel.IsLogin()) + { + mqttChannel.RemoveMqttMessage(messageId); + await _messagePushService.SendToPubComp(channel, messageId); + } + } + } + + public override async ValueTask PingReq(IChannel channel) + { + if (MqttChannels.TryGetValue(await this.GetDeviceId(channel), out MqttChannel mqttChannel)) + { + if (mqttChannel.IsLogin()) + { + mqttChannel.PingReqTime = DateTime.Now; + } + } + } + + public override async Task SendWillMsg(MqttWillMessage willMeaasge) + { + Topics.TryGetValue(willMeaasge.Topic, out IEnumerable mqttChannels); + if (mqttChannels != null && mqttChannels.Any()) + { + foreach (var mqttChannel in mqttChannels) + { + if (!await mqttChannel.IsOnine()) + { + _clientSessionService.SaveMessage(mqttChannel.ClientId, new SessionMessage + { + Message = Encoding.UTF8.GetBytes(willMeaasge.WillMessage), + QoS = willMeaasge.Qos, + Topic = willMeaasge.Topic + }); + } + else + { + await _messagePushService.WriteWillMsg(mqttChannel, willMeaasge); + } + } + } + } + + public override async Task Suscribe(string deviceId, params string[] topics) + { + if (!string.IsNullOrEmpty(deviceId)) + { + MqttChannels.TryGetValue(deviceId, out MqttChannel mqttChannel); + mqttChannel.SubscribeStatus = SubscribeStatus.Yes; + mqttChannel.AddTopic(topics); + if (mqttChannel.IsLogin()) + { + foreach (var topic in topics) + { + this.AddChannel(topic, mqttChannel); + await RegisterMqttBroker(topic); + await this.SendRetain(topic, mqttChannel); + } + } + } + } + + public override async Task UnSubscribe(string deviceId, params string[] topics) + { + if (MqttChannels.TryGetValue(deviceId, out MqttChannel mqttChannel)) + { + foreach (var topic in topics) + { + RemoveChannel(topic, mqttChannel); + await BrokerCancellationReg(topic); + } + } + } + + public async Task SendRetain(string topic, MqttChannel mqttChannel) + { + Retain.TryGetValue(topic, out ConcurrentQueue retainMessages); + if (retainMessages != null && !retainMessages.IsEmpty) + { + var messages = retainMessages.GetEnumerator(); + while (messages.MoveNext()) + { + var retainMessage = messages.Current; + await SendMessage(mqttChannel, retainMessage.QoS, topic, retainMessage.ByteBuf); + }; + } + } + + private void SaveRetain(String topic, RetainMessage retainMessage, bool isClean) + { + Retain.TryGetValue(topic, out ConcurrentQueue retainMessages); + if (retainMessages == null) retainMessages=new ConcurrentQueue(); + if (!retainMessages.IsEmpty && isClean) + { + retainMessages.Clear(); + } + retainMessages.Enqueue(retainMessage); + Retain.AddOrUpdate(topic, retainMessages,(key,value)=> retainMessages); + } + + public IEnumerable RemoveSubTopic(MqttChannel mqttChannel) + { + IEnumerable topics = mqttChannel.Topics; + foreach (var topic in topics) + { + Topics.TryGetValue(topic, out IEnumerable comparisonValue); + var newValue = comparisonValue.Where(p => p != mqttChannel); + Topics.TryUpdate(topic, newValue, comparisonValue); + } + return topics; + } + + private async Task SendMessage(MqttChannel mqttChannel,int qos, string topic,byte [] byteBuf) + { + switch (qos) + { + case 0: + await _messagePushService.SendQos0Msg(mqttChannel.Channel, topic, byteBuf); + break; + case 1: + await _messagePushService.SendQosConfirmMsg(QualityOfService.AtLeastOnce, mqttChannel, topic, byteBuf); + break; + case 2: + await _messagePushService.SendQosConfirmMsg(QualityOfService.ExactlyOnce, mqttChannel, topic, byteBuf); + break; + } + } + + private async Task Init(IChannel channel, ConnectMessage mqttConnectMessage) + { + String deviceId = await GetDeviceId(channel); + MqttChannel mqttChannel = new MqttChannel() + { + Channel = channel, + KeepAliveInSeconds = mqttConnectMessage.KeepAliveInSeconds, + CleanSession = mqttConnectMessage.CleanSession, + ClientId = mqttConnectMessage.ClientId, + SessionStatus = SessionStatus.OPEN, + IsWill = mqttConnectMessage.HasWill, + SubscribeStatus = SubscribeStatus.No, + Messages = new ConcurrentDictionary(), + Topics = new List() + }; + if (await Connect(deviceId, mqttChannel)) + { + if (mqttConnectMessage.HasWill) + { + if (mqttConnectMessage.WillMessage == null || string.IsNullOrEmpty(mqttConnectMessage.WillTopic)) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"WillMessage 和 WillTopic不能为空"); + return; + } + var willMessage = new MqttWillMessage + { + Qos = mqttConnectMessage.Qos, + WillRetain = mqttConnectMessage.WillRetain, + Topic = mqttConnectMessage.WillTopic, + WillMessage = Encoding.UTF8.GetString(mqttConnectMessage.WillMessage) + + }; + _willService.Add(mqttConnectMessage.ClientId, willMessage); + } + else + { + _willService.Remove(mqttConnectMessage.ClientId); + if (!mqttConnectMessage.WillRetain && mqttConnectMessage.WillQualityOfService != 0) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"WillRetain 设置为false,WillQos必须设置为AtMostOnce"); + return; + } + } + await channel.WriteAndFlushAsync(new ConnAckPacket + { + ReturnCode = ConnectReturnCode.Accepted, + SessionPresent = !mqttConnectMessage.CleanSession + }); + var sessionMessages = _clientSessionService.GetMessages(mqttConnectMessage.ClientId); + if (sessionMessages != null && !sessionMessages.IsEmpty) + { + for (; sessionMessages.TryDequeue(out SessionMessage sessionMessage) && sessionMessage != null;) + { + switch (sessionMessage.QoS) + { + case 0: + await _messagePushService.SendQos0Msg(channel, sessionMessage.Topic, sessionMessage.Message); + break; + case 1: + await _messagePushService.SendQosConfirmMsg(QualityOfService.AtLeastOnce, GetMqttChannel(deviceId), sessionMessage.Topic, sessionMessage.Message); + break; + case 2: + await _messagePushService.SendQosConfirmMsg(QualityOfService.ExactlyOnce, GetMqttChannel(deviceId), sessionMessage.Topic, sessionMessage.Message); + break; + } + } + } + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/WillService.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/WillService.cs new file mode 100644 index 000000000..7764ae8e3 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/Implementation/WillService.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services.Implementation +{ + public class WillService: IWillService + { + private ConcurrentDictionary willMeaasges = new ConcurrentDictionary(); + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + + public WillService(ILogger logger, CPlatformContainer serviceProvider) + { + _logger = logger; + _serviceProvider = serviceProvider; + } + + public void Add(string deviceid, MqttWillMessage willMessage) + { + willMeaasges.AddOrUpdate(deviceid, willMessage,(id,message)=>willMessage); + } + + public async Task SendWillMessage(string deviceId) + { + if (!string.IsNullOrEmpty(deviceId)) + { + willMeaasges.TryGetValue(deviceId, out MqttWillMessage willMessage); + if (willMeaasges != null) + { + await _serviceProvider.GetInstances().SendWillMsg(willMessage); + if (!willMessage.WillRetain) + { + Remove(deviceId); + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation($"deviceId:{deviceId} 的遗嘱消息[" + willMessage.WillMessage + "] 已经被删除"); + + } + } + } + } + + public void Remove(string deviceid) { + willMeaasges.TryRemove(deviceid,out MqttWillMessage message); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/MqttBehavior.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/MqttBehavior.cs new file mode 100644 index 000000000..0d62a3055 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Internal/Services/MqttBehavior.cs @@ -0,0 +1,74 @@ +using Autofac; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using Surging.Core.Protocol.Mqtt.Internal.Messages; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt.Internal.Services +{ + public abstract class MqttBehavior: ServiceBase + { + public async Task Publish(string deviceId, MqttWillMessage willMessage) + { + await GetService().Publish(deviceId, willMessage); + } + + public async Task RemotePublish(string deviceId, MqttWillMessage willMessage) + { + await GetService().RemotePublishMessage(deviceId, willMessage); + } + + public override T GetService(string key) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return base.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public override T GetService() + { + if (ServiceLocator.Current.IsRegistered()) + return base.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public override object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return base.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public override object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return base.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + public async Task GetDeviceIsOnine(string deviceId) + { + return await this.GetService().GetDeviceIsOnine(deviceId); + } + + public abstract Task Authorized(string username, string password); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttHandlerServiceBase.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttHandlerServiceBase.cs new file mode 100644 index 000000000..34dacefb2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttHandlerServiceBase.cs @@ -0,0 +1,48 @@ +using DotNetty.Codecs.Mqtt.Packets; +using DotNetty.Transport.Channels; +using Surging.Core.CPlatform.Messages; +using Surging.Core.Protocol.Mqtt.Internal.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt +{ + public abstract class MqttHandlerServiceBase + { + protected readonly Action _handler; + public MqttHandlerServiceBase( Action handler) + { + _handler = handler; + } + + public abstract void Login(IChannelHandlerContext context, ConnectPacket packet); + + public abstract void ConnAck(IChannelHandlerContext context, ConnAckPacket packet); + + public abstract void Disconnect(IChannelHandlerContext context, DisconnectPacket packet); + + public abstract void PingReq(IChannelHandlerContext context, PingReqPacket packet); + + public abstract void PingResp(IChannelHandlerContext context, PingRespPacket packet); + + public abstract void PubAck(IChannelHandlerContext context, PubAckPacket packet); + + public abstract void PubComp(IChannelHandlerContext context, PubCompPacket packet); + + public abstract void PubRec(IChannelHandlerContext context, PubRecPacket packet); + + public abstract void PubRel(IChannelHandlerContext context, PubRelPacket packet); + + public abstract void Publish(IChannelHandlerContext context, PublishPacket packet); + + public abstract void SubAck(IChannelHandlerContext context, SubAckPacket packet); + + public abstract void Subscribe(IChannelHandlerContext context, SubscribePacket packet); + + public abstract void UnsubAck(IChannelHandlerContext context, UnsubAckPacket packet); + + public abstract void Unsubscribe(IChannelHandlerContext context, UnsubscribePacket packet); + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttProtocolModule.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttProtocolModule.cs new file mode 100644 index 000000000..bd6e8bf44 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttProtocolModule.cs @@ -0,0 +1,122 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Ids; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Mqtt; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.Protocol.Mqtt.Diagnostics; +using Surging.Core.Protocol.Mqtt.Implementation; +using Surging.Core.Protocol.Mqtt.Internal.Channel; +using Surging.Core.Protocol.Mqtt.Internal.Runtime; +using Surging.Core.Protocol.Mqtt.Internal.Runtime.Implementation; +using Surging.Core.Protocol.Mqtt.Internal.Services; +using Surging.Core.Protocol.Mqtt.Internal.Services.Implementation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Mqtt +{ + public class MqttProtocolModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + base.Initialize(context); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType(typeof(DefaultMqttServiceFactory)).As(typeof(IMqttServiceFactory)).SingleInstance(); + builder.RegisterType(typeof(DefaultMqttBrokerEntryManager)).As(typeof(IMqttBrokerEntryManger)).SingleInstance(); + builder.RegisterType(typeof(MqttRemoteInvokeService)).As(typeof(IMqttRemoteInvokeService)).SingleInstance(); + builder.Register(provider => + { + return new WillService( + provider.Resolve>(), + provider.Resolve() + ); + }).As().SingleInstance(); + builder.Register(provider => + { + return new MessagePushService(new SacnScheduled()); + }).As().SingleInstance(); + builder.RegisterType(typeof(ClientSessionService)).As(typeof(IClientSessionService)).SingleInstance(); + builder.Register(provider => + { + return new MqttChannelService( + provider.Resolve(), + provider.Resolve(), + provider.Resolve>(), + provider.Resolve(), + provider.Resolve(), + provider.Resolve(), + provider.Resolve() + ); + }).As(typeof(IChannelService)).SingleInstance(); + builder.RegisterType(typeof(DefaultMqttBehaviorProvider)).As(typeof(IMqttBehaviorProvider)).SingleInstance(); + + if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.Mqtt) + { + RegisterDefaultProtocol(builder); + } + else if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterMqttProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DotNettyMqttServerMessageListener(provider.Resolve>(), + provider.Resolve(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + + var messageListener = provider.Resolve(); + return new DefaultServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, null); + + }).As(); + } + + private static void RegisterMqttProtocol(ContainerBuilderWrapper builder) + { + + builder.Register(provider => + { + return new DotNettyMqttServerMessageListener(provider.Resolve>(), + provider.Resolve(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new MqttServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }); + + }).As(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttServiceHost.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttServiceHost.cs new file mode 100644 index 000000000..b8d2de071 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/MqttServiceHost.cs @@ -0,0 +1,56 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Mqtt +{ + public class MqttServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public MqttServiceHost(Func> messageListenerFactory) : base(null) + { + _messageListenerFactory = messageListenerFactory; + } + + #region Overrides of ServiceHostAbstract + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(endPoint); + + } + + public override async Task StartAsync(string ip, int port) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.MQTTPort)); + } + + #endregion Overrides of ServiceHostAbstract + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Surging.Core.Protocol.Mqtt.csproj b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Surging.Core.Protocol.Mqtt.csproj new file mode 100644 index 000000000..3d3d3c891 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Surging.Core.Protocol.Mqtt.csproj @@ -0,0 +1,35 @@ + + + + net6.0 + fanly + surging Micro Service Framework + surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec + Copyright © fanly All Rights Reserved. + https://github.com/dotnetcore/surging/blob/master/LICENSE + https://github.com/dotnetcore/surging + MicroService surging + 1.multiple register center cluster +2. fix bug + 1.1.0.0 + 1.1.0 + + + + + + + + + + + + + + + + C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.logging.abstractions\2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + + diff --git a/src/Surging.Core/Surging.Core.Protocol.Mqtt/Util/MessageIdGenerater.cs b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Util/MessageIdGenerater.cs new file mode 100644 index 000000000..5e29f6de4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Mqtt/Util/MessageIdGenerater.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Surging.Core.Protocol.Mqtt.Util +{ + public class MessageIdGenerater + { + + private static int _index; + private static int _lock; + public static int GenerateId() + { + for (; ; ) + { + if (Interlocked.Exchange(ref _lock, 1) != 0) + { + default(SpinWait).SpinOnce(); + continue; + } + if (int.MaxValue > _index) + _index++; + else + _index = 0; + + Interlocked.Exchange(ref _lock, 0); + return _index; + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Adapter/ConnectionChannelHandlerAdapter.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Adapter/ConnectionChannelHandlerAdapter.cs new file mode 100644 index 000000000..bd49d1058 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Adapter/ConnectionChannelHandlerAdapter.cs @@ -0,0 +1,63 @@ +using DotNetty.Buffers; +using DotNetty.Handlers.Timeout; +using DotNetty.Transport.Channels; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Network; +using Surging.Core.Protocol.Tcp.Runtime; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Adapter +{ + public class ConnectionChannelHandlerAdapter : ChannelHandlerAdapter + { + private readonly ILogger _logger; + private readonly IDeviceProvider _deviceProvider; + private readonly ITcpServiceEntryProvider _tcpServiceEntryProvider; + private readonly TcpServerProperties _tcpServerProperties; + public ConnectionChannelHandlerAdapter(ILogger logger, IDeviceProvider deviceProvider, ITcpServiceEntryProvider tcpServiceEntryProvider, TcpServerProperties tcpServerProperties) + { + _logger = logger; + _deviceProvider = deviceProvider; + _tcpServiceEntryProvider = tcpServiceEntryProvider; + _tcpServerProperties= tcpServerProperties; + + } + + + public override void ChannelActive(IChannelHandlerContext ctx) + { + _deviceProvider.Register(ctx); + var tcpEntry=_tcpServiceEntryProvider.GetEntry(); + tcpEntry.Behavior.DeviceStatusProcess(DeviceStatus.Connected, ctx.Channel.Id.AsLongText(), _tcpServerProperties); + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("channel active:" + ctx.Channel.RemoteAddress); + + } + + public override void ChannelInactive(IChannelHandlerContext ctx) + { + _deviceProvider.Unregister(ctx); + var tcpEntry = _tcpServiceEntryProvider.GetEntry(); + tcpEntry.Behavior.DeviceStatusProcess(DeviceStatus.Closed, ctx.Channel.Id.AsLongText(), _tcpServerProperties); + if (_logger.IsEnabled(LogLevel.Information)) + _logger.LogInformation("channel inactive:" + ctx.Channel.RemoteAddress); + + } + + + public override void ExceptionCaught(IChannelHandlerContext ctx, Exception exception) + { + _deviceProvider.Unregister(ctx); + var tcpEntry = _tcpServiceEntryProvider.GetEntry(); + tcpEntry.Behavior.DeviceStatusProcess(DeviceStatus.Abnormal, ctx.Channel.Id.AsLongText(), _tcpServerProperties); + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError("channel exceptionCaught:" + ctx.Channel.RemoteAddress, exception); + + } + } +} + \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Codecs/FixedLengthFrameDecoder.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Codecs/FixedLengthFrameDecoder.cs new file mode 100644 index 000000000..4a086bb47 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Codecs/FixedLengthFrameDecoder.cs @@ -0,0 +1,41 @@ +using DotNetty.Buffers; +using DotNetty.Codecs; +using DotNetty.Transport.Channels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Codecs +{ + public class FixedLengthFrameDecoder : ByteToMessageDecoder + { + private readonly int frameLength; + public FixedLengthFrameDecoder(int frameLength) + { + if (frameLength <= 0) + throw new ArgumentOutOfRangeException(nameof(frameLength)); + this.frameLength = frameLength; + } + protected override void Decode(IChannelHandlerContext ctx, IByteBuffer input, List output) + { + object decoded = this.Decode(ctx, input); + if (decoded != null) + output.Add(decoded); + } + + protected virtual object Decode(IChannelHandlerContext ctx, IByteBuffer buffer) + { + if (buffer.ReadableBytes < frameLength) + { + return null; + } + else + { + return buffer.ReadRetainedSlice(frameLength); + } + } + } +} + diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/DotNettyTcpMessageSender.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/DotNettyTcpMessageSender.cs new file mode 100644 index 000000000..3e7af34b4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/DotNettyTcpMessageSender.cs @@ -0,0 +1,128 @@ +using DotNetty.Buffers; +using DotNetty.Transport.Channels; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport; +using Surging.Core.Protocol.Tcp.Runtime; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp +{ + public abstract class DotNettyTcpMessageSender + { + + protected DotNettyTcpMessageSender() + { + } + + protected IByteBuffer GetByteBuffer(TransportMessage message) + { + var data = message.GetContent(); + return Unpooled.WrappedBuffer(data); + } + } + + #region Implementation of IMessageSender + + /// + /// 基于DotNetty服务端的消息发送者。 + /// + public class DotNettyTcpServerMessageSender : DotNettyTcpMessageSender, IMessageSender + { + private readonly IChannelHandlerContext _context; + + public DotNettyTcpServerMessageSender(IChannelHandlerContext context) : base() + { + _context = context; + } + + /// + /// 发送消息。 + /// + /// 消息内容。 + /// 一个任务。 + public async Task SendAsync(TransportMessage message) + { + var buffer = GetByteBuffer(message); + await _context.WriteAsync(buffer); + } + + /// + /// 发送消息并清空缓冲区。 + /// + /// 消息内容。 + /// 一个任务。 + public async Task SendAndFlushAsync(TransportMessage message) + { + var buffer = GetByteBuffer(message); + if (_context.Channel.RemoteAddress != null) + await _context.WriteAndFlushAsync(buffer); + } + + + } + #endregion Implementation of IMessageSender + + public class TcpServerMessageSender : ITcpMessageSender + { + private readonly IChannelHandlerContext _context; + + public TcpServerMessageSender(IChannelHandlerContext context) : base() + { + _context = context; + } + + /// + /// 发送消息。 + /// + /// 消息内容。 + /// 一个任务。 + public async Task SendAsync(object message, Encoding encoding) + { + if (message != null) + { + var buffer = Unpooled.WrappedBuffer(encoding.GetBytes(message.ToString())); + await SendAsync(buffer); + } + } + + /// + /// 发送消息并清空缓冲区。 + /// + /// 消息内容。 + /// 一个任务。 + public async Task SendAndFlushAsync(object message, Encoding encoding) + { + if (message != null) + { + var buffer = Unpooled.WrappedBuffer(encoding.GetBytes(message.ToString())); + await SendAndFlushAsync(buffer); + } + } + + public async Task SendAsync(object message) + { + await SendAsync(message, Encoding.UTF8); + } + + public async Task SendAndFlushAsync(object message) + { + await SendAndFlushAsync(message, Encoding.UTF8); + } + + public async Task SendAndFlushAsync(IByteBuffer buffer) + { + if (_context.Channel.RemoteAddress != null) + await _context.WriteAndFlushAsync(buffer); + } + + public async Task SendAsync(IByteBuffer buffer) + { + if (_context.Channel.RemoteAddress != null) + await _context.WriteAsync(buffer); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/DotNettyTcpServerMessageListener.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/DotNettyTcpServerMessageListener.cs new file mode 100644 index 000000000..1095dfddd --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/DotNettyTcpServerMessageListener.cs @@ -0,0 +1,245 @@ +using DotNetty.Buffers; +using DotNetty.Codecs; +using DotNetty.Handlers.Timeout; +using DotNetty.Transport.Bootstrapping; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Sockets; +using Microsoft.Extensions.Logging; +using RulesEngine.ExpressionBuilders; +using RulesEngine.Models; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Network; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.Protocol.Tcp.Adapter; +using Surging.Core.Protocol.Tcp.Codecs; +using Surging.Core.Protocol.Tcp.RuleParser.Implementation; +using Surging.Core.Protocol.Tcp.Runtime; +using Surging.Core.Protocol.Tcp.Util; +using System.Net; +using System.Text; +using System.Linq.Expressions; +using DotNetty.Common.Utilities; + +namespace Surging.Core.Protocol.Tcp +{ + public class DotNettyTcpServerMessageListener : IMessageListener, INetwork, IDisposable + { + + #region Field + public event ReceivedDelegate Received; + private readonly TcpServerProperties _tcpServerProperties; + private readonly ILogger _logger; + private IChannel _channel; + private readonly TcpRuleWorkflow _ruleWorkflow; + private readonly RulesEngine.RulesEngine _engine; + public string Id { get; set; } + #endregion Field + + #region Constructor + public DotNettyTcpServerMessageListener(ILogger logger, string id, TcpServerProperties properties) + { + _logger = logger; + Id = id; + _tcpServerProperties= properties; + _ruleWorkflow = GetTcpRuleWorkflow(); + _engine = GetRuleEngine(); + } + #endregion + + public async Task OnReceived(IMessageSender sender, TransportMessage message) + { + if (Received == null) + return; + await Received(sender, message); + } + + public void Dispose() + { + Task.Run(async () => + { + await _channel.EventLoop.ShutdownGracefullyAsync(); + await _channel.CloseAsync(); + }).Wait(); + } + + + + public bool IsAlive() + { + return _channel.Active; + } + + public bool IsAutoReload() + { + return false; + } + + + + public void Shutdown() + { + Task.Run(async () => + { + await _channel.EventLoop.ShutdownGracefullyAsync(); + await _channel.CloseAsync(); + }).Wait(); + } + + NetworkType INetwork.GetType() + { + return NetworkType.TcpServer; + } + + public async Task StartAsync(EndPoint endPoint) + { + var ipEndPoint = (IPEndPoint)endPoint; + _tcpServerProperties.Host = ipEndPoint.Address.ToString(); + _tcpServerProperties.Port= ipEndPoint.Port; + await StartAsync(); + } + + public async Task StartAsync() + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备启动服务主机,监听地址:{_tcpServerProperties.Host}:{_tcpServerProperties.Port}。"); + + IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1); + IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2 + var tcpServiceEntryProvider = ServiceLocator.GetService(); + var workerGroup1 = new SingleThreadEventLoop(); + + var bootstrap = new ServerBootstrap(); + bootstrap + .Channel() + .ChildOption(ChannelOption.SoKeepalive, true) + .Option(ChannelOption.SoBacklog, AppConfig.ServerOptions.SoBacklog) + .ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default) + .Group(bossGroup, workerGroup) + .ChildHandler(new ActionChannelInitializer( channel => + { + var pipeline = channel.Pipeline; + + pipeline.AddLast(new ConnectionChannelHandlerAdapter(_logger, ServiceLocator.GetService(), tcpServiceEntryProvider, _tcpServerProperties)); + pipeline.AddLast(workerGroup1, "ServerHandler", new ServerHandler(_tcpServerProperties,_engine,_ruleWorkflow, _logger) + ); + switch (_tcpServerProperties.ParserType) + { + case PayloadParserType.Direct: + { + pipeline.AddLast(new LengthFieldPrepender(4)); + pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4)); + } + break; + case PayloadParserType.FixedLength: + { + if (_tcpServerProperties.ParserConfiguration != null && _tcpServerProperties.ParserConfiguration.ContainsKey("size")) + { + var configValue = _tcpServerProperties.ParserConfiguration["size"]; + pipeline.AddLast(new FixedLengthFrameDecoder(int.Parse(configValue.ToString() ?? "0"))); + } + } + break; + case PayloadParserType.Delimited: + { + if (_tcpServerProperties.ParserConfiguration != null && _tcpServerProperties.ParserConfiguration.ContainsKey("delimited")) + { + var configValue = _tcpServerProperties.ParserConfiguration["delimited"]; + var delimiter = Unpooled.CopiedBuffer(Encoding.Default.GetBytes(configValue.ToString() ?? "")); + pipeline.AddLast(new DelimiterBasedFrameDecoder(int.MaxValue, true, delimiter)); + } + } + break; + } + + })) + .Option(ChannelOption.SoBroadcast, true); + try + { + _channel = await bootstrap.BindAsync(_tcpServerProperties.CreateSocketAddress()); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"Tcp服务主机启动成功,监听地址:{_tcpServerProperties.Host}:{_tcpServerProperties.Port}。"); + } + catch (Exception ex) + { + _logger.LogError($"Tcp服务主机启动失败,监听地址:{_tcpServerProperties.Host}:{_tcpServerProperties.Port}。 "); + } + } + + private RulesEngine.RulesEngine GetRuleEngine() + { + var reSettingsWithCustomTypes = new ReSettings { CustomTypes = new Type[] { typeof(RulePipePayloadParser) } }; + var result = new RulesEngine.RulesEngine(new Workflow[] { _ruleWorkflow.GetWorkflow() }, null, reSettingsWithCustomTypes); + return result; + } + + private TcpRuleWorkflow GetTcpRuleWorkflow() + { + var result = new TcpRuleWorkflow("1==1"); + if (_tcpServerProperties.ParserConfiguration!=null && _tcpServerProperties.ParserConfiguration.ContainsKey("script")) + { + var configValue = _tcpServerProperties.ParserConfiguration["script"]; + result = new TcpRuleWorkflow(configValue.ToString() ?? ""); + } + return result; + } + + private class ServerHandler : ChannelHandlerAdapter + { + + private readonly TcpServerProperties _tcpServerProperties; + private readonly ILogger _logger; + private readonly RulesEngine.RulesEngine _engine; + private readonly TcpRuleWorkflow _ruleWorkflow; + + + public ServerHandler(TcpServerProperties tcpServerProperties, RulesEngine.RulesEngine engine, TcpRuleWorkflow ruleWorkflow,ILogger logger) + { + _tcpServerProperties = tcpServerProperties; + _engine = engine; + _ruleWorkflow = ruleWorkflow; + _logger = logger; + } + + public override async void ChannelRead(IChannelHandlerContext ctx, object message) + { + var buffer = (IByteBuffer)message; + var parser = await GetParser(); + var tcpServiceEntryProvider = ServiceLocator.GetService(); + var entry = tcpServiceEntryProvider.GetEntry(); + if (entry != null) { entry.Behavior.Parser = parser; + entry.Behavior.Sender = new TcpServerMessageSender(ctx); + entry.Behavior.Load(ctx.Channel.Id.AsLongText() ,_tcpServerProperties); } + if (_tcpServerProperties.ParserType == PayloadParserType.Script) + { + if (_tcpServerProperties.ParserConfiguration != null && _tcpServerProperties.ParserConfiguration.ContainsKey("script")) + { + parser.Build(buffer); + } + } + else + { + parser.Direct(buffer => buffer).Fixed(buffer.ReadableBytes).Handle(buffer); + } + ReferenceCountUtil.Release(buffer); + + } + + public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) + { + context.CloseAsync(); + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, $"与服务器:{context.Channel.RemoteAddress}通信时发送了错误。"); + } + + + private async Task GetParser() + { + var payloadParser = new RulePipePayloadParser(); + var ruleResult = await _engine.ExecuteActionWorkflowAsync(_ruleWorkflow.WorkflowName, _ruleWorkflow.RuleName, new RuleParameter[] { new RuleParameter("parser", payloadParser) }); + return payloadParser; + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Extensions/TransportMessageExtensions.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Extensions/TransportMessageExtensions.cs new file mode 100644 index 000000000..5d99cc36a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Extensions/TransportMessageExtensions.cs @@ -0,0 +1,20 @@ +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Extensions +{ + public static class TransportMessageExtensions + { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsTcpDispatchMessage(this TransportMessage message) + { + return message.ContentType == typeof(byte[]).FullName; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Messages/Codec/EncodedMessage.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Messages/Codec/EncodedMessage.cs new file mode 100644 index 000000000..054ef4251 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Messages/Codec/EncodedMessage.cs @@ -0,0 +1,14 @@ +using DotNetty.Buffers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Messages.Codec +{ + public class EncodedMessage + { + public IByteBuffer Payload { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/RuleParser/IRulePayloadParser.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/RuleParser/IRulePayloadParser.cs new file mode 100644 index 000000000..ac62647d8 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/RuleParser/IRulePayloadParser.cs @@ -0,0 +1,24 @@ +using DotNetty.Buffers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.RuleParser +{ + public interface IRulePayloadParser + { + + void Handle(IByteBuffer buffer); + + void Reset(); + + void Build(IByteBuffer buffer); + + void Close(); + + ISubject HandlePayload(); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/RuleParser/Implementation/RulePipePayloadParser.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/RuleParser/Implementation/RulePipePayloadParser.cs new file mode 100644 index 000000000..c67ef977b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/RuleParser/Implementation/RulePipePayloadParser.cs @@ -0,0 +1,180 @@ +using DotNetty.Buffers; +using Jint; +using Surging.Core.Protocol.Tcp.Util; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.RuleParser.Implementation +{ + public class RulePipePayloadParser : IRulePayloadParser + { + private readonly List _result = new List(); + private ISubject _bufferSubject = new ReplaySubject(); + private readonly List> _pipe = new List>(); + private readonly List _fixedRecordLength = new List(); + private readonly AtomicInteger _currentPipe = new AtomicInteger(); + private readonly AtomicInteger _currentFixedRecordLength = new AtomicInteger(); + private Func _directMapper; + public RulePipePayloadParser Result(IByteBuffer buffer) + { + _result.Add(buffer); + return this; + } + + public RulePipePayloadParser Result(string buffer) + { + return Result(Unpooled.CopiedBuffer(buffer, Encoding.UTF8)); + } + + public RulePipePayloadParser Result(string buffer,string encodeName) + { + return Result(Unpooled.CopiedBuffer(buffer, Encoding.GetEncoding(encodeName))); + } + + public RulePipePayloadParser Result(byte[] buffer) + { + return Result(Unpooled.CopiedBuffer(buffer)); + } + + public RulePipePayloadParser Fixed(int length) + { + + _fixedRecordLength.Add(length); + return this; + } + + public void Handle(IByteBuffer buffer) + { + if (_directMapper == null) + { + return; + } + var buf = _directMapper.Invoke(buffer); + if (null != buf) + { + _bufferSubject.OnNext(buf); + } + } + + public Action GetNextHandler() + { + int i = _currentPipe.Increment()-1; + if (i < _pipe.Count) + { + return _pipe[i]; + } + _currentPipe.Value = 0; + return _pipe[0]; + } + + public int GetNextFixedRecordLength() + { + int i = _currentFixedRecordLength.Increment()-1; + if (i < _fixedRecordLength.Count) + { + return _fixedRecordLength[i]; + } + _currentFixedRecordLength.Value = 0; + return _fixedRecordLength[0]; + } + + public void Build(IByteBuffer buffer) + { + if (_pipe.Any()) + { + foreach (var pipe in _pipe) + { + try + { + pipe.Invoke(buffer); + } + catch (Exception ex) + { + throw ex; + } + } + } + } + + + public RulePipePayloadParser Complete() + { + _currentPipe.Value = 0; + _currentFixedRecordLength.Value = 0; + if (_result.Any()) + { + var buffer = Unpooled.Buffer(); + + foreach (var buf in _result) + { + + buf.ReadBytes(buffer, buf.ReadableBytes); + + + } + _result.Clear(); + _bufferSubject.OnNext(buffer); + } + _bufferSubject.OnCompleted(); + return this; + + } + + public RulePipePayloadParser Handler(Action handler) + { + _pipe.Add(handler); + return this; + } + + public RulePipePayloadParser Handler(string script) + { + var propertyName = "script"; + script = $"var {propertyName} ={script}"; + var engine = new Engine() + .SetValue("parser", this).SetValue("BytesUtils", new BytesUtils()).Execute(script); + _pipe.Add(buffer => + { + try + { + engine.Invoke(propertyName, buffer); + } + catch(Exception ex) + { + throw ex; + } + }); + return this; + } + + public ISubject HandlePayload() + { + return _bufferSubject; + } + + public void Reset() + { + _result.Clear(); + Complete(); + } + + public void Close() + { + _bufferSubject.OnCompleted(); + _currentFixedRecordLength.Value=0; + _currentPipe.Value = 0; + _result.Clear(); + _bufferSubject = new ReplaySubject(); + } + + public RulePipePayloadParser Direct(Func mapper) + { + _directMapper = mapper; + return this; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/DeviceStatus.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/DeviceStatus.cs new file mode 100644 index 000000000..9814b4e79 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/DeviceStatus.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public enum DeviceStatus + { + Connected, + Closed, + Abnormal + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/IDeviceProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/IDeviceProvider.cs new file mode 100644 index 000000000..0c6602ab8 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/IDeviceProvider.cs @@ -0,0 +1,23 @@ +using DotNetty.Transport.Channels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public interface IDeviceProvider + { + bool Register(IChannelHandlerContext channelHandler); + + bool Unregister(IChannelHandlerContext channelHandlerContext); + + bool Unregister(string clientId); + + bool IsConnected(string clientId); + + Task SendClientMessage(string clientId,object message); + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/ITcpMessageSender.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/ITcpMessageSender.cs new file mode 100644 index 000000000..1d15271df --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/ITcpMessageSender.cs @@ -0,0 +1,23 @@ +using DotNetty.Buffers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public interface ITcpMessageSender + { + Task SendAsync(object message); + Task SendAndFlushAsync(object message); + + Task SendAsync(object message, Encoding encoding); + + Task SendAndFlushAsync(object message, Encoding encoding); + + Task SendAndFlushAsync(IByteBuffer buffer); + + Task SendAsync(IByteBuffer buffer); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/ITcpServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/ITcpServiceEntryProvider.cs new file mode 100644 index 000000000..57d9b226c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/ITcpServiceEntryProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public interface ITcpServiceEntryProvider + { + TcpServiceEntry GetEntry(); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/DefaultDeviceProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/DefaultDeviceProvider.cs new file mode 100644 index 000000000..9e5676749 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/DefaultDeviceProvider.cs @@ -0,0 +1,52 @@ +using DotNetty.Transport.Channels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Collections.Concurrent; + +namespace Surging.Core.Protocol.Tcp.Runtime.Implementation +{ + public class DefaultDeviceProvider : IDeviceProvider + { + private readonly ConcurrentDictionary deviceItems = new ConcurrentDictionary(); + public bool IsConnected(string clientId) + { + var result = false; + var device = deviceItems.GetValueOrDefault(clientId); + if (device != null) + { + result = device.Channel.Active; + } + return result; + } + + public bool Register(IChannelHandlerContext channelHandler) + { + return deviceItems.TryAdd(channelHandler.Channel.Id.AsLongText(), channelHandler); + } + + + + public async Task SendClientMessage(string clientId, object message) + { + var device = deviceItems.GetValueOrDefault(clientId); + if (device != null) + { + await device.WriteAndFlushAsync(message); + } + + } + + public bool Unregister(IChannelHandlerContext channelHandler) + { + return deviceItems.Remove(channelHandler.Channel.Id.AsLongText(), out IChannelHandlerContext handlerContext); + } + + public bool Unregister(string clientId) + { + return deviceItems.Remove(clientId, out IChannelHandlerContext handlerContext); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/DefaultTcpServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/DefaultTcpServiceEntryProvider.cs new file mode 100644 index 000000000..a67f3bbdc --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/DefaultTcpServiceEntryProvider.cs @@ -0,0 +1,91 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime.Implementation +{ + public class DefaultTcpServiceEntryProvider : ITcpServiceEntryProvider + { + #region Field + + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private Type? _tcpServiceEntryType=null; + + #endregion Field + + #region Constructor + + public DefaultTcpServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of ITcpServiceEntryProvider + + /// + /// 获取服务条目集合。 + /// + /// 服务条目集合。 + public TcpServiceEntry GetEntry() + { + var services = _types.ToArray(); + TcpServiceEntry result = new TcpServiceEntry(); + if(_tcpServiceEntryType !=null) + result = CreateServiceEntry(_tcpServiceEntryType); + else + { + foreach (var service in services) + { + var entry = CreateServiceEntry(service); + if (entry != null) + { + _tcpServiceEntryType = service; + result = entry; + break; + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下Tcp服务:{result.Type.FullName}。"); + } + } + return result; + } + + public TcpServiceEntry CreateServiceEntry(Type service) + { + TcpServiceEntry result = null; + var routeTemplate = service.GetCustomAttribute(); + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as TcpBehavior; + var path = RoutePatternParser.Parse(routeTemplate.RouteTemplate, service.Name); + if (path.Length > 0 && path[0] != '/') + path = $"/{path}"; + if (behavior != null) + result = new TcpServiceEntry + { + Behavior = behavior, + Type = behavior.GetType(), + Path = path, + }; + return result; + } + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/TcpNetworkProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/TcpNetworkProvider.cs new file mode 100644 index 000000000..084a051e9 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/Implementation/TcpNetworkProvider.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Network; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime.Implementation +{ + public class TcpNetworkProvider : INetworkProvider + { + private readonly ILogger _logger; + public TcpNetworkProvider(ILogger logger) + { + _logger = logger; + } + public INetwork CreateNetwork(TcpServerProperties properties) + { + var tcpServer = new DotNettyTcpServerMessageListener(_logger, properties.Id, properties); + return tcpServer; + } + + public IDictionary GetConfigMetadata() + { + return new Dictionary(); + } + + public async void Reload(INetwork network, TcpServerProperties properties) + { + var tcpServer = network as DotNettyTcpServerMessageListener; + if (tcpServer != null) + { + tcpServer.Shutdown(); + await tcpServer.StartAsync(); + } + } + + public NetworkType GetNetworkType() + { + return NetworkType.TcpServer; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/PayloadParserType.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/PayloadParserType.cs new file mode 100644 index 000000000..a74cdb54e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/PayloadParserType.cs @@ -0,0 +1,10 @@ +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public enum PayloadParserType + { + Direct,//不处理 + FixedLength,//"固定长度" + Delimited,//分隔符 + Script//自定义脚本 + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/PayloadType.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/PayloadType.cs new file mode 100644 index 000000000..0f390074c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/PayloadType.cs @@ -0,0 +1,9 @@ +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public enum PayloadType + { + Json, + String, + Xml + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpBehavior.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpBehavior.cs new file mode 100644 index 000000000..dc604b9ff --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpBehavior.cs @@ -0,0 +1,124 @@ +using Autofac; +using DotNetty.Buffers; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.Protocol.Tcp.RuleParser.Implementation; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public abstract class TcpBehavior : IServiceBehavior + { + private ServerReceivedDelegate _received; + public event ServerReceivedDelegate Received + { + add + { + + _received += value; + } + remove + { + _received -= value; + } + } + + public abstract void Load(string clientId,TcpServerProperties tcpServerProperties); + + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + + public abstract void DeviceStatusProcess(DeviceStatus status, string clientId, TcpServerProperties tcpServerProperties); + + public async Task SendClientMessage(string clientId, object message) + { + var deviceProvider = ServiceLocator.GetService(); + await deviceProvider.SendClientMessage(clientId, message); + } + public ITcpMessageSender Sender { get; set; } + public RulePipePayloadParser Parser { get; set; } + + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (_received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await _received(message); + } + public T CreateProxy(string key) where T : class + { + return ServiceLocator.GetService().CreateProxy(key); + } + + public object CreateProxy(Type type) + { + return ServiceLocator.GetService().CreateProxy(type); + } + + public object CreateProxy(string key, Type type) + { + return ServiceLocator.GetService().CreateProxy(key, type); + } + + public T CreateProxy() where T : class + { + return ServiceLocator.GetService().CreateProxy(); + } + + public T GetService(string key) where T : class + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return ServiceLocator.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public T GetService() where T : class + { + if (ServiceLocator.Current.IsRegistered()) + return ServiceLocator.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return ServiceLocator.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return ServiceLocator.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpServerProperties.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpServerProperties.cs new file mode 100644 index 000000000..5b68ce1ac --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpServerProperties.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Net; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public class TcpServerProperties + { + public string _id; + public string Id + { + get { return _id; } + set { _id = value; } + } + + + private PayloadType _payloadType; + public PayloadType PayloadType + { + get { return _payloadType; } + set { _payloadType = value; } + } + + private IDictionary _parserConfiguration; + public IDictionary ParserConfiguration + { + get { return _parserConfiguration; } + set { _parserConfiguration = value; } + } + + private PayloadParserType _parserType; + public PayloadParserType ParserType + { + get { return _parserType; } + set { _parserType = value; } + } + + private string _host; + public string Host + { + get { return _host; } + set { _host = value; } + } + + private int _port; + public int Port + { + get { return _port; } + set { _port = value; } + } + + private bool _ssl; + public bool SSL + { + get { return _ssl; } + set { _ssl = value; } + } + + //服务实例数量(线程数) + private int _instance = Environment.ProcessorCount; + public int Instance + { + get { return _instance; } + set { _instance = value; } + } + + private string _certId; + public string CertId + { + get { return _certId; } + set { _certId = value; } + } + + public IPEndPoint CreateSocketAddress() + { + if (string.IsNullOrEmpty(_host)) + { + _host = "localhost"; + } + return new IPEndPoint(IPAddress.Parse(_host),_port); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpServiceEntry.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpServiceEntry.cs new file mode 100644 index 000000000..8dd4ce732 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Runtime/TcpServiceEntry.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Runtime +{ + public class TcpServiceEntry + { + public string Path { get; set; } + + public Type Type { get; set; } + + public TcpBehavior Behavior { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Surging.Core.Protocol.Tcp.csproj b/src/Surging.Core/Surging.Core.Protocol.Tcp/Surging.Core.Protocol.Tcp.csproj new file mode 100644 index 000000000..2d2b91d5e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Surging.Core.Protocol.Tcp.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpProtocolModule.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpProtocolModule.cs new file mode 100644 index 000000000..83b64ddc5 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpProtocolModule.cs @@ -0,0 +1,122 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Network; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.Protocol.Tcp.Runtime; +using Surging.Core.Protocol.Tcp.Runtime.Implementation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp +{ + public class TcpProtocolModule : EnginePartModule + { + public override void Initialize(AppModuleContext serviceProvider) + { + base.Initialize(serviceProvider); + var config = new Dictionary(); + config.Add("script", @"parser.Fixed(4).Handler( + function(buffer){ + var buf = BytesUtils.Slice(buffer,1,4); + parser.Fixed(buffer.ReadableBytes).Result(buf); + }).Handler( + function(buffer){parser.Fixed(8).Result(buffer);} + ).Handler( + function(buffer){parser.Result('处理完成','gb2312').Complete();} + )"); + var network= serviceProvider.ServiceProvoider.GetInstances>().CreateNetwork(new TcpServerProperties + { + ParserType = PayloadParserType.Script, + PayloadType = PayloadType.String, + Host = "127.0.0.1", + Port = 322, + ParserConfiguration = config + }); + network.StartAsync(); + + + var network1 = serviceProvider.ServiceProvoider.GetInstances>().CreateNetwork(new TcpServerProperties + { + ParserType = PayloadParserType.Direct, + PayloadType = PayloadType.String, + Host = "127.0.0.1", + Port = 321 + }); + network1.StartAsync(); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.Register(provider => + { + return new DefaultTcpServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(ITcpServiceEntryProvider)).SingleInstance(); + builder.RegisterType(typeof(DefaultDeviceProvider)).As(typeof(IDeviceProvider)).SingleInstance(); + builder.RegisterType(typeof(DefaultTcpServiceEntryProvider)).As(typeof(ITcpServiceEntryProvider)).SingleInstance(); + builder.RegisterType(typeof(TcpNetworkProvider)).As>().SingleInstance(); + if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.Tcp) + { + RegisterDefaultProtocol(builder); + } + else if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterTcpProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DotNettyTcpServerMessageListener(provider.Resolve>(), + "default",new TcpServerProperties() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new TcpServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }); + + }).As(); + } + + private static void RegisterTcpProtocol(ContainerBuilderWrapper builder) + { + + builder.Register(provider => + { + return new DotNettyTcpServerMessageListener(provider.Resolve>(), + "default",new TcpServerProperties() + ); + }).SingleInstance(); + builder.Register(provider => + { + var messageListener = provider.Resolve(); + return new TcpServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }); + + }).As(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpServiceExecutor.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpServiceExecutor.cs new file mode 100644 index 000000000..94f314b3a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpServiceExecutor.cs @@ -0,0 +1,111 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Transport; +using Surging.Core.Protocol.Tcp.Extensions; +using Surging.Core.Protocol.Tcp.Runtime; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp +{ + public class TcpServiceExecutor : IServiceExecutor + { + #region Field + + private readonly ITcpServiceEntryProvider _udpServiceEntryProvider; + private readonly ILogger _logger; + + #endregion Field + + #region Constructor + + public TcpServiceExecutor(ITcpServiceEntryProvider dnsServiceEntryProvider, + ILogger logger) + { + _udpServiceEntryProvider = dnsServiceEntryProvider; + _logger = logger; + } + + #endregion Constructor + + #region Implementation of IServiceExecutor + + /// + /// 执行。 + /// + /// 消息发送者。 + /// 调用消息。 + public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) + { + if (_logger.IsEnabled(LogLevel.Trace)) + _logger.LogTrace("服务提供者接收到消息。"); + + + byte[] udpMessage = null; + try + { + if (message.IsTcpDispatchMessage()) + udpMessage = message.GetContent(); + } + catch (Exception exception) + { + _logger.LogError(exception, "将接收到的消息反序列化成 TransportMessage 时发送了错误。"); + return; + } + var entry = _udpServiceEntryProvider.GetEntry(); + if (entry == null) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"未实现UdpBehavior实例。"); + return; + } + if (udpMessage != null) + await LocalExecuteAsync(entry, udpMessage); + + await SendRemoteInvokeResult(sender, udpMessage); + } + + #endregion Implementation of IServiceExecutor + + #region Private Method + + + private async Task LocalExecuteAsync(TcpServiceEntry entry, byte[] bytes) + { + HttpResultMessage resultMessage = new HttpResultMessage(); + try + { + // await entry.Behavior.Dispatch(bytes); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "执行本地逻辑时候发生了错误。"); + } + } + + private async Task SendRemoteInvokeResult(IMessageSender sender, byte[] resultMessage) + { + try + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("准备发送响应消息。"); + + await sender.SendAndFlushAsync(new TransportMessage(resultMessage)); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("响应消息发送成功。"); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "发送响应消息时候发生了异常。"); + } + } + + #endregion Private Method + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpServiceHost.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpServiceHost.cs new file mode 100644 index 000000000..db7c217ea --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/TcpServiceHost.cs @@ -0,0 +1,68 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp +{ + public class TcpServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public TcpServiceHost(Func> messageListenerFactory) : base(null) + { + _messageListenerFactory = messageListenerFactory; + } + + #region Overrides of ServiceHostAbstract + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(endPoint); + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + public override async Task StartAsync(string ip, int port) + { + if (_serverMessageListener != null) + return; + if (AppConfig.ServerOptions.Ports.TcpPort >0) + { + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.TcpPort)); + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + } + + #endregion Overrides of ServiceHostAbstract + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/AtomicInteger.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/AtomicInteger.cs new file mode 100644 index 000000000..0cf31d8da --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/AtomicInteger.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Util +{ + public class AtomicInteger + { + private int _value; + + public int Value + { + get => _value; + set => Interlocked.Exchange(ref _value, value); + } + + public AtomicInteger() + : this(0) + { + } + + public AtomicInteger(int defaultValue) + { + _value = defaultValue; + } + + public int Increment() + { + Interlocked.Increment(ref _value); + return _value; + } + + public int Decrement() + { + Interlocked.Decrement(ref _value); + return _value; + } + + public int Add(int value) + { + AddInternal(value); + return _value; + } + + private void AddInternal(int value) + { + Interlocked.Add(ref _value, value); + } + + public override bool Equals(object obj) + { + switch (obj) + { + case AtomicInteger atomicInteger: + return atomicInteger._value == _value; + case int value: + return value == _value; + default: + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public static AtomicInteger operator +(AtomicInteger atomicInteger, int value) + { + atomicInteger.AddInternal(value); + return atomicInteger; + } + + public static AtomicInteger operator +(int value, AtomicInteger atomicInteger) + { + atomicInteger.AddInternal(value); + return atomicInteger; + } + + public static AtomicInteger operator -(AtomicInteger atomicInteger, int value) + { + atomicInteger.AddInternal(-value); + return atomicInteger; + } + + public static AtomicInteger operator -(int value, AtomicInteger atomicInteger) + { + atomicInteger.AddInternal(-value); + return atomicInteger; + } + + public static implicit operator AtomicInteger(int value) + { + return new AtomicInteger(value); + } + + public static implicit operator int(AtomicInteger atomicInteger) + { + return atomicInteger._value; + } + + public static bool operator ==(AtomicInteger atomicInteger, int value) + { + return atomicInteger._value == value; + } + + public static bool operator !=(AtomicInteger atomicInteger, int value) + { + return !(atomicInteger == value); + } + + public static bool operator ==(int value, AtomicInteger atomicInteger) + { + return atomicInteger._value == value; + } + + public static bool operator !=(int value, AtomicInteger atomicInteger) + { + return !(value == atomicInteger); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/BytesUtils.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/BytesUtils.cs new file mode 100644 index 000000000..f052d1fa1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/BytesUtils.cs @@ -0,0 +1,20 @@ +using DotNetty.Buffers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Util +{ + public class BytesUtils + { + public IByteBuffer Slice(IByteBuffer byteBuffer,int index,int length) + { + var result= byteBuffer.RetainedSlice(index, length).SetReaderIndex(0); + byteBuffer.SetReaderIndex(length+index); + result.SetReaderIndex(0); + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/TcpRuleWorkflow.cs b/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/TcpRuleWorkflow.cs new file mode 100644 index 000000000..e3906d05c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Tcp/Util/TcpRuleWorkflow.cs @@ -0,0 +1,67 @@ +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Tcp.Util +{ + public class TcpRuleWorkflow + { + + public TcpRuleWorkflow() : this("TcpRuleWorkflow", "TcpRule", "1 == 1", "OutputExpression", new Dictionary()) + { + + } + + public TcpRuleWorkflow(string actionExpression) : this() + { + var str = Regex.Replace(actionExpression, @"(\.Handler\()[.\r|\n|\t|\s]*?(?=(function))", ".Handler(\"", RegexOptions.IgnoreCase); + str = Regex.Replace(str, @"(})[.\r|\n|\t|\s]*?(?=(\)))", "}\"", RegexOptions.IgnoreCase); + Context.Add("expression", str ?? "1 == 1"); + } + + public TcpRuleWorkflow(string workflowName,string ruleName,string expression,string ruleActionName, Dictionary context) + { + WorkflowName = workflowName; + RuleName = ruleName; + Expression = expression; + RuleActionName = ruleActionName; + Context = context; + } + public string WorkflowName { get; set; } + + public string RuleName { get; set; } + + + public string Expression { get; set; } + + public string RuleActionName { get; set; } + + public new Dictionary Context { get; set; } + + public Workflow GetWorkflow() + { + var result = new Workflow + { + WorkflowName = WorkflowName, + + Rules = new List{ + new Rule{ + RuleName =RuleName, + Expression = Expression, + Actions = new RuleActions{ + OnSuccess = new ActionInfo{ + Name = RuleActionName, + Context =Context + } + } + } + } + }; + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/DotNettyUdpMessageSender.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/DotNettyUdpMessageSender.cs new file mode 100644 index 000000000..9be8b29eb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/DotNettyUdpMessageSender.cs @@ -0,0 +1,65 @@ +using DotNetty.Buffers; +using DotNetty.Transport.Channels; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Codec; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Udp +{ + public abstract class DotNettyUdpMessageSender + { + private readonly ITransportMessageEncoder _transportMessageEncoder; + + protected DotNettyUdpMessageSender(ITransportMessageEncoder transportMessageEncoder) + { + _transportMessageEncoder = transportMessageEncoder; + } + + protected IByteBuffer GetByteBuffer(TransportMessage message) + { + var data = message.GetContent(); + return Unpooled.WrappedBuffer(data); + } + } + + /// + /// 基于DotNetty服务端的消息发送者。 + /// + public class DotNettyUdpServerMessageSender : DotNettyUdpMessageSender, IMessageSender + { + private readonly IChannelHandlerContext _context; + + public DotNettyUdpServerMessageSender(ITransportMessageEncoder transportMessageEncoder, IChannelHandlerContext context) : base(transportMessageEncoder) + { + _context = context; + } + + #region Implementation of IMessageSender + + /// + /// 发送消息。 + /// + /// 消息内容。 + /// 一个任务。 + public async Task SendAsync(TransportMessage message) + { + var buffer = GetByteBuffer(message); + await _context.WriteAsync(buffer); + } + + /// + /// 发送消息并清空缓冲区。 + /// + /// 消息内容。 + /// 一个任务。 + public async Task SendAndFlushAsync(TransportMessage message) + { + var buffer = GetByteBuffer(message); + if( _context.Channel.RemoteAddress !=null) + await _context.WriteAndFlushAsync(buffer); + } + + #endregion Implementation of IMessageSender + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/DotNettyUdpServerMessageListener.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/DotNettyUdpServerMessageListener.cs new file mode 100644 index 000000000..136b3485e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/DotNettyUdpServerMessageListener.cs @@ -0,0 +1,133 @@ +using DotNetty.Buffers; +using DotNetty.Transport.Bootstrapping; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Channels.Sockets; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Transport; +using Surging.Core.CPlatform.Transport.Codec; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Udp +{ + public class DotNettyUdpServerMessageListener : IMessageListener, IDisposable + { + #region Field + + private readonly ILogger _logger; + private readonly ITransportMessageDecoder _transportMessageDecoder; + private readonly ITransportMessageEncoder _transportMessageEncoder; + private IChannel _channel; + private readonly ISerializer _serializer; + + public event ReceivedDelegate Received; + + #endregion Field + + #region Constructor + public DotNettyUdpServerMessageListener(ILogger logger + , ITransportMessageCodecFactory codecFactory) + { + _logger = logger; + _transportMessageEncoder = codecFactory.GetEncoder(); + _transportMessageDecoder = codecFactory.GetDecoder(); + } + + public async Task StartAsync(EndPoint endPoint) + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); + + var group = new MultithreadEventLoopGroup(); + var bootstrap = new Bootstrap(); + bootstrap + .Group(group) + .Channel() + .Option(ChannelOption.SoBacklog, 1024) + .Option(ChannelOption.SoSndbuf, 1024 * 4096*10) + .Option(ChannelOption.SoRcvbuf, 1024 * 4096*10) + .Handler(new ServerHandler(async (contenxt, message) => + { + var sender = new DotNettyUdpServerMessageSender(_transportMessageEncoder, contenxt); + await OnReceived(sender, message); + }, _logger, _serializer) + ).Option(ChannelOption.SoBroadcast, true); + try + { + + _channel = await bootstrap.BindAsync(endPoint); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"Udp服务主机启动成功,监听地址:{endPoint}。"); + } + catch(Exception ex) + { + _logger.LogError($"Udp服务主机启动失败,监听地址:{endPoint}。 "); + } + + } + + public async Task OnReceived(IMessageSender sender, TransportMessage message) + { + if (Received == null) + return; + await Received(sender, message); + } + + + public void CloseAsync() + { + Task.Run(async () => + { + await _channel.EventLoop.ShutdownGracefullyAsync(); + await _channel.CloseAsync(); + }).Wait(); + } + + public void Dispose() + { + Task.Run(async () => + { + await _channel.DisconnectAsync(); + }).Wait(); + } + + #endregion + + private class ServerHandler : SimpleChannelInboundHandler + { + + private readonly Action _readAction; + private readonly ILogger _logger; + private readonly ISerializer _serializer; + + + + public ServerHandler(Action readAction, ILogger logger, ISerializer serializer) + { + _readAction = readAction; + _logger = logger; + _serializer = serializer; + } + + protected override void ChannelRead0(IChannelHandlerContext ctx, DatagramPacket msg) + { + var buff = msg.Content; + byte[] messageBytes = new byte[buff.ReadableBytes]; + buff.ReadBytes(messageBytes); + _readAction(ctx, new TransportMessage(messageBytes)); + } + + public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) + { + context.CloseAsync(); + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, $"与服务器:{context.Channel.RemoteAddress}通信时发送了错误。"); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/Extensions/TransportMessageExtensions.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/Extensions/TransportMessageExtensions.cs new file mode 100644 index 000000000..2e816e3a7 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/Extensions/TransportMessageExtensions.cs @@ -0,0 +1,18 @@ +using Surging.Core.CPlatform.Messages; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Surging.Core.Protocol.Udp.Extensions +{ + public static class TransportMessageExtensions + { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsUdpDispatchMessage(this TransportMessage message) + { + return message.ContentType == typeof(byte[]).FullName; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/IUdpServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/IUdpServiceEntryProvider.cs new file mode 100644 index 000000000..f9ff95f2f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/IUdpServiceEntryProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Udp.Runtime +{ + public interface IUdpServiceEntryProvider + { + UdpServiceEntry GetEntry(); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/Implementation/DefaultUdpServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/Implementation/DefaultUdpServiceEntryProvider.cs new file mode 100644 index 000000000..2aad2e209 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/Implementation/DefaultUdpServiceEntryProvider.cs @@ -0,0 +1,87 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.Protocol.Udp.Runtime.Implementation +{ + public class DefaultUdpServiceEntryProvider : IUdpServiceEntryProvider + { + #region Field + + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private UdpServiceEntry _udpServiceEntry; + + #endregion Field + + #region Constructor + + public DefaultUdpServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of IUdpServiceEntryProvider + + /// + /// 获取服务条目集合。 + /// + /// 服务条目集合。 + public UdpServiceEntry GetEntry() + { + var services = _types.ToArray(); + if (_udpServiceEntry == null) + { + _udpServiceEntry = new UdpServiceEntry(); + foreach (var service in services) + { + var entry = CreateServiceEntry(service); + if (entry != null) + { + _udpServiceEntry = entry; + break; + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下Udp服务:{_udpServiceEntry.Type.FullName}。"); + } + } + return _udpServiceEntry; + } + + public UdpServiceEntry CreateServiceEntry(Type service) + { + UdpServiceEntry result = null; + var routeTemplate = service.GetCustomAttribute(); + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as UdpBehavior; + var path = RoutePatternParser.Parse(routeTemplate.RouteTemplate, service.Name); + if (path.Length > 0 && path[0] != '/') + path = $"/{path}"; + if (behavior != null) + result = new UdpServiceEntry + { + Behavior = behavior, + Type = behavior.GetType(), + Path = path, + }; + return result; + } + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/UdpBehavior.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/UdpBehavior.cs new file mode 100644 index 000000000..e5f1d2971 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/UdpBehavior.cs @@ -0,0 +1,109 @@ +using Autofac; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Udp.Runtime +{ + public abstract class UdpBehavior : IServiceBehavior + { + private ServerReceivedDelegate received; + public event ServerReceivedDelegate Received + { + add + { + if (received == null) + { + received += value; + } + } + remove + { + received -= value; + } + } + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await received(message); + } + public T CreateProxy(string key) where T : class + { + return ServiceLocator.GetService().CreateProxy(key); + } + + public object CreateProxy(Type type) + { + return ServiceLocator.GetService().CreateProxy(type); + } + + public object CreateProxy(string key, Type type) + { + return ServiceLocator.GetService().CreateProxy(key, type); + } + + public T CreateProxy() where T : class + { + return ServiceLocator.GetService().CreateProxy(); + } + + public T GetService(string key) where T : class + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return ServiceLocator.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public T GetService() where T : class + { + if (ServiceLocator.Current.IsRegistered()) + return ServiceLocator.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return ServiceLocator.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return ServiceLocator.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + public abstract Task Dispatch(IEnumerable bytes); + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/UdpServiceEntry.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/UdpServiceEntry.cs new file mode 100644 index 000000000..c1941b50e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/Runtime/UdpServiceEntry.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Udp.Runtime +{ + public class UdpServiceEntry + { + public string Path { get; set; } + + public Type Type { get; set; } + + public UdpBehavior Behavior { get; set; } + } + +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/Surging.Core.Protocol.Udp.csproj b/src/Surging.Core/Surging.Core.Protocol.Udp/Surging.Core.Protocol.Udp.csproj new file mode 100644 index 000000000..8047e09ce --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/Surging.Core.Protocol.Udp.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/UdpProtocolModule.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/UdpProtocolModule.cs new file mode 100644 index 000000000..c42cc63fc --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/UdpProtocolModule.cs @@ -0,0 +1,92 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.Protocol.Udp.Runtime; +using Surging.Core.Protocol.Udp.Runtime.Implementation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.Udp +{ + public class UdpProtocolModule : EnginePartModule + { + public override void Initialize(AppModuleContext serviceProvider) + { + base.Initialize(serviceProvider); + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.Register(provider => + { + return new DefaultUdpServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(IUdpServiceEntryProvider)).SingleInstance(); + builder.RegisterType(typeof(UdpServiceExecutor)).As(typeof(IServiceExecutor)) + .Named(CommunicationProtocol.Udp.ToString()).SingleInstance(); + if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.Dns) + { + RegisterDefaultProtocol(builder); + } + else if (CPlatform.AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) + { + RegisterUdpProtocol(builder); + } + } + + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DotNettyUdpServerMessageListener(provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var serviceExecutor = provider.ResolveKeyed(CommunicationProtocol.Udp.ToString()); + var messageListener = provider.Resolve(); + return new UdpServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, serviceExecutor); + + }).As(); + } + + private static void RegisterUdpProtocol(ContainerBuilderWrapper builder) + { + + builder.Register(provider => + { + return new DotNettyUdpServerMessageListener(provider.Resolve>(), + provider.Resolve() + ); + }).SingleInstance(); + builder.Register(provider => + { + var serviceExecutor = provider.ResolveKeyed(CommunicationProtocol.Udp.ToString()); + var messageListener = provider.Resolve(); + return new UdpServiceHost(async endPoint => + { + await messageListener.StartAsync(endPoint); + return messageListener; + }, serviceExecutor); + + }).As(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/UdpServiceExecutor.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/UdpServiceExecutor.cs new file mode 100644 index 000000000..d75c7839e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/UdpServiceExecutor.cs @@ -0,0 +1,110 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Transport; +using Surging.Core.Protocol.Udp.Extensions; +using Surging.Core.Protocol.Udp.Runtime; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Udp +{ + public class UdpServiceExecutor : IServiceExecutor + { + #region Field + + private readonly IUdpServiceEntryProvider _udpServiceEntryProvider; + private readonly ILogger _logger; + + #endregion Field + + #region Constructor + + public UdpServiceExecutor(IUdpServiceEntryProvider dnsServiceEntryProvider, + ILogger logger) + { + _udpServiceEntryProvider = dnsServiceEntryProvider; + _logger = logger; + } + + #endregion Constructor + + #region Implementation of IServiceExecutor + + /// + /// 执行。 + /// + /// 消息发送者。 + /// 调用消息。 + public async Task ExecuteAsync(IMessageSender sender, TransportMessage message) + { + if (_logger.IsEnabled(LogLevel.Trace)) + _logger.LogTrace("服务提供者接收到消息。"); + + + byte[] udpMessage = null; + try + { + if (message.IsUdpDispatchMessage()) + udpMessage = message.GetContent(); + } + catch (Exception exception) + { + _logger.LogError(exception, "将接收到的消息反序列化成 TransportMessage 时发送了错误。"); + return; + } + var entry = _udpServiceEntryProvider.GetEntry(); + if (entry == null) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError($"未实现UdpBehavior实例。"); + return; + } + if (udpMessage != null) + await LocalExecuteAsync(entry, udpMessage); + + await SendRemoteInvokeResult(sender, udpMessage); + } + + #endregion Implementation of IServiceExecutor + + #region Private Method + + + private async Task LocalExecuteAsync(UdpServiceEntry entry, byte [] bytes) + { + HttpResultMessage resultMessage = new HttpResultMessage(); + try + { + await entry.Behavior.Dispatch(bytes); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "执行本地逻辑时候发生了错误。"); + } + } + + private async Task SendRemoteInvokeResult(IMessageSender sender, byte[] resultMessage) + { + try + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("准备发送响应消息。"); + + await sender.SendAndFlushAsync(new TransportMessage(resultMessage)); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("响应消息发送成功。"); + } + catch (Exception exception) + { + if (_logger.IsEnabled(LogLevel.Error)) + _logger.LogError(exception, "发送响应消息时候发生了异常。"); + } + } + + #endregion Private Method + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.Udp/UdpServiceHost.cs b/src/Surging.Core/Surging.Core.Protocol.Udp/UdpServiceHost.cs new file mode 100644 index 000000000..d8c4c1a35 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.Udp/UdpServiceHost.cs @@ -0,0 +1,64 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation; +using Surging.Core.CPlatform.Transport; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.Udp +{ + class UdpServiceHost : ServiceHostAbstract + { + #region Field + + private readonly Func> _messageListenerFactory; + private IMessageListener _serverMessageListener; + + #endregion Field + + public UdpServiceHost(Func> messageListenerFactory, IServiceExecutor serviceExecutor) : base(serviceExecutor) + { + _messageListenerFactory = messageListenerFactory; + } + + #region Overrides of ServiceHostAbstract + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public override void Dispose() + { + (_serverMessageListener as IDisposable)?.Dispose(); + } + + /// + /// 启动主机。 + /// + /// 主机终结点。 + /// 一个任务。 + public override async Task StartAsync(EndPoint endPoint) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(endPoint); + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + public override async Task StartAsync(string ip, int port) + { + if (_serverMessageListener != null) + return; + _serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), AppConfig.ServerOptions.Ports.UdpPort)); + _serverMessageListener.Received += async (sender, message) => + { + await MessageListener.OnReceived(sender, message); + }; + } + + #endregion Overrides of ServiceHostAbstract + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/Attributes/BehaviorContractAttribute.cs b/src/Surging.Core/Surging.Core.Protocol.WS/Attributes/BehaviorContractAttribute.cs new file mode 100644 index 000000000..ab81e0756 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WS/Attributes/BehaviorContractAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.WS.Attributes +{ + public class BehaviorContractAttribute : Attribute + { + + public bool IgnoreExtensions { get; set; } + + public bool EmitOnPing { get; set; } + + public string Protocol { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/Configurations/BehaviorOption.cs b/src/Surging.Core/Surging.Core.Protocol.WS/Configurations/BehaviorOption.cs new file mode 100644 index 000000000..7bb3a65a4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WS/Configurations/BehaviorOption.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.WS.Configurations +{ + public class BehaviorOption + { + public bool IgnoreExtensions { get; set; } + + public bool EmitOnPing { get; set; } + + public string Protocol { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/Configurations/WebSocketOptions.cs b/src/Surging.Core/Surging.Core.Protocol.WS/Configurations/WebSocketOptions.cs new file mode 100644 index 000000000..de8add798 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WS/Configurations/WebSocketOptions.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Protocol.WS.Configurations +{ + public class WebSocketOptions + { + /// + /// Gets or sets the time to wait for the response to the WebSocket Ping or + /// Close. + /// + /// + /// The set operation does nothing if the server has already started or + /// it is shutting down. + /// + /// + /// + /// A to wait for the response. + /// + /// + /// The default value is the same as 1 second. + /// + /// + /// + /// The value specified for a set operation is zero or less. + /// + public int WaitTime { get; set; } = 1; + + public bool KeepClean + { + get; + set; + } = false; + + public BehaviorOption Behavior { get; set; } + } + +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/DefaultWSServerMessageListener.cs b/src/Surging.Core/Surging.Core.Protocol.WS/DefaultWSServerMessageListener.cs index ea82f89cb..5f72b8c3e 100644 --- a/src/Surging.Core/Surging.Core.Protocol.WS/DefaultWSServerMessageListener.cs +++ b/src/Surging.Core/Surging.Core.Protocol.WS/DefaultWSServerMessageListener.cs @@ -9,6 +9,7 @@ using WebSocketCore.Server; using Surging.Core.Protocol.WS.Runtime; using Microsoft.Extensions.Logging; +using Surging.Core.Protocol.WS.Configurations; namespace Surging.Core.Protocol.WS { @@ -17,10 +18,14 @@ public class DefaultWSServerMessageListener : IMessageListener, IDisposable private readonly List _entries; private WebSocketServer _wssv; private readonly ILogger _logger; - public DefaultWSServerMessageListener(ILogger logger,IWSServiceEntryProvider wsServiceEntryProvider) + private readonly WebSocketOptions _options; + + public DefaultWSServerMessageListener(ILogger logger, + IWSServiceEntryProvider wsServiceEntryProvider, WebSocketOptions options) { _logger = logger; _entries = wsServiceEntryProvider.GetEntries().ToList(); + _options = options; } public async Task StartAsync(EndPoint endPoint) { @@ -29,8 +34,11 @@ public async Task StartAsync(EndPoint endPoint) try { foreach (var entry in _entries) - _wssv.AddWebSocketService(entry.Path, entry.Behavior); - _wssv.KeepClean = false; + _wssv.AddWebSocketService(entry.Path, entry.FuncBehavior); + _wssv.KeepClean = _options.KeepClean; + _wssv.WaitTime = TimeSpan.FromSeconds(_options.WaitTime); + //允许转发请求 + _wssv.AllowForwardedRequest = true; _wssv.Start(); if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug($"WS服务主机启动成功,监听地址:{endPoint}。"); diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/Implementation/DefaultWSServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/Implementation/DefaultWSServiceEntryProvider.cs index 34ad87d7e..45f1498c7 100644 --- a/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/Implementation/DefaultWSServiceEntryProvider.cs +++ b/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/Implementation/DefaultWSServiceEntryProvider.cs @@ -4,6 +4,8 @@ using Surging.Core.CPlatform.Routing.Template; using Surging.Core.CPlatform.Runtime.Server; using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using Surging.Core.Protocol.WS.Attributes; +using Surging.Core.Protocol.WS.Configurations; using System; using System.Collections.Generic; using System.Linq; @@ -21,16 +23,21 @@ public class DefaultWSServiceEntryProvider : IWSServiceEntryProvider private readonly ILogger _logger; private readonly CPlatformContainer _serviceProvider; private List _wSServiceEntries; + private WebSocketOptions _options; #endregion Field #region Constructor - public DefaultWSServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, ILogger logger, CPlatformContainer serviceProvider) + public DefaultWSServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider, + WebSocketOptions options) { _types = serviceEntryProvider.GetTypes(); _logger = logger; _serviceProvider = serviceProvider; + _options = options; } #endregion Constructor @@ -68,6 +75,7 @@ public WSServiceEntry CreateServiceEntry(Type service) { WSServiceEntry result = null; var routeTemplate = service.GetCustomAttribute(); + var behaviorContract = service.GetCustomAttribute(); var objInstance = _serviceProvider.GetInstances(service); var behavior = objInstance as WebSocketBehavior; var path = RoutePatternParser.Parse(routeTemplate.RouteTemplate, service.Name); @@ -78,9 +86,31 @@ public WSServiceEntry CreateServiceEntry(Type service) { Behavior = behavior, Type = behavior.GetType(), - Path = path + Path = path, + FuncBehavior = () => + { + return GetWebSocketBehavior(service, _options?.Behavior, behaviorContract); + } }; return result; } + + private WebSocketBehavior GetWebSocketBehavior(Type service,BehaviorOption option, BehaviorContractAttribute contractAttribute) + { + var wsBehavior = _serviceProvider.GetInstances(service) as WebSocketBehavior; + if (option != null) + { + wsBehavior.IgnoreExtensions = option.IgnoreExtensions; + wsBehavior.Protocol = option.Protocol; + wsBehavior.EmitOnPing = option.EmitOnPing; + } + if (contractAttribute != null) + { + wsBehavior.IgnoreExtensions = contractAttribute.IgnoreExtensions; + wsBehavior.Protocol = contractAttribute.Protocol; + wsBehavior.EmitOnPing = contractAttribute.EmitOnPing; + } + return wsBehavior; + } } } diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/WSServiceEntry.cs b/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/WSServiceEntry.cs index 760199eca..574ad5005 100644 --- a/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/WSServiceEntry.cs +++ b/src/Surging.Core/Surging.Core.Protocol.WS/Runtime/WSServiceEntry.cs @@ -1,4 +1,5 @@ -using System; +using Surging.Core.Protocol.WS.Configurations; +using System; using System.Collections.Generic; using System.Text; using WebSocketCore.Server; @@ -11,6 +12,8 @@ public class WSServiceEntry public Type Type { get; set; } - public WebSocketBehavior Behavior { get; set; } + public WebSocketBehavior Behavior { get; set; } + + public Func FuncBehavior { get; set; } } } diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/Surging.Core.Protocol.WS.csproj b/src/Surging.Core/Surging.Core.Protocol.WS/Surging.Core.Protocol.WS.csproj index 826742f7b..48322d0ac 100644 --- a/src/Surging.Core/Surging.Core.Protocol.WS/Surging.Core.Protocol.WS.csproj +++ b/src/Surging.Core/Surging.Core.Protocol.WS/Surging.Core.Protocol.WS.csproj @@ -1,7 +1,20 @@ - netcoreapp2.1 + net6.0 + 1.1.0.0 + fanly + fanly + surging Micro Service Framework + surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec + Copyright © fanly All Rights Reserved. + https://github.com/dotnetcore/surging/blob/master/LICENSE + https://github.com/dotnetcore/surging + MicroService surging + 1.multiple register center cluster +2. fix bug + 1.1.0.0 + 1.1.0.0 diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/WSServiceBase.cs b/src/Surging.Core/Surging.Core.Protocol.WS/WSBehavior.cs similarity index 74% rename from src/Surging.Core/Surging.Core.Protocol.WS/WSServiceBase.cs rename to src/Surging.Core/Surging.Core.Protocol.WS/WSBehavior.cs index b386543b8..b18a152c0 100644 --- a/src/Surging.Core/Surging.Core.Protocol.WS/WSServiceBase.cs +++ b/src/Surging.Core/Surging.Core.Protocol.WS/WSBehavior.cs @@ -8,11 +8,43 @@ using System; using WebSocketCore.Server; using System.Linq; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Messages; namespace Surging.Core.Protocol.WS { - public abstract class WSServiceBase : WebSocketBehavior, IServiceBehavior - { + public abstract class WSBehavior : WebSocketBehavior, IServiceBehavior + { + private ServerReceivedDelegate received; + public event ServerReceivedDelegate Received + { + add + { + if (received == null) + { + received += value; + } + } + remove + { + received -= value; + } + } + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await received(message); + } public T CreateProxy(string key) where T : class { return ServiceLocator.GetService().CreateProxy(key); diff --git a/src/Surging.Core/Surging.Core.Protocol.WS/WSProtocolModule.cs b/src/Surging.Core/Surging.Core.Protocol.WS/WSProtocolModule.cs index 06250b7c0..9293d3833 100644 --- a/src/Surging.Core/Surging.Core.Protocol.WS/WSProtocolModule.cs +++ b/src/Surging.Core/Surging.Core.Protocol.WS/WSProtocolModule.cs @@ -1,4 +1,5 @@ using Autofac; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Surging.Core.CPlatform; using Surging.Core.CPlatform.Module; @@ -6,6 +7,7 @@ using Surging.Core.CPlatform.Runtime.Server.Implementation; using Surging.Core.CPlatform.Serialization; using Surging.Core.CPlatform.Transport.Codec; +using Surging.Core.Protocol.WS.Configurations; using Surging.Core.Protocol.WS.Runtime; using Surging.Core.Protocol.WS.Runtime.Implementation; using System; @@ -14,11 +16,11 @@ namespace Surging.Core.Protocol.WS { - public class WSProtocolModule : EnginePartModule + public class WSProtocolModule : EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { - base.Initialize(serviceProvider); + base.Initialize(context); } /// @@ -27,25 +29,39 @@ public override void Initialize(CPlatformContainer serviceProvider) /// protected override void RegisterBuilder(ContainerBuilderWrapper builder) { + var options = new WebSocketOptions(); + var section = AppConfig.GetSection("WebSocket"); + if (section.Exists()) + options = section.Get(); base.RegisterBuilder(builder); - builder.RegisterType(typeof(DefaultWSServiceEntryProvider)).As(typeof(IWSServiceEntryProvider)).SingleInstance(); + builder.Register(provider => + { + return new DefaultWSServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve(), + options + ); + }).As(typeof(IWSServiceEntryProvider)).SingleInstance(); if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.WS) { - RegisterDefaultProtocol(builder); + RegisterDefaultProtocol(builder, options); } else if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.None) { - RegisterWSProtocol(builder); + RegisterWSProtocol(builder, options); } } - private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) + private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder, WebSocketOptions options) { + builder.Register(provider => { return new DefaultWSServerMessageListener( provider.Resolve>(), - provider.Resolve() + provider.Resolve(), + options ); }).SingleInstance(); builder.Register(provider => @@ -60,12 +76,13 @@ private static void RegisterDefaultProtocol(ContainerBuilderWrapper builder) }).As(); } - private static void RegisterWSProtocol(ContainerBuilderWrapper builder) + private static void RegisterWSProtocol(ContainerBuilderWrapper builder, WebSocketOptions options) { builder.Register(provider => { return new DefaultWSServerMessageListener(provider.Resolve>(), - provider.Resolve() + provider.Resolve(), + options ); }).SingleInstance(); builder.Register(provider => diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/IWebServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/IWebServiceEntryProvider.cs new file mode 100644 index 000000000..efb974742 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/IWebServiceEntryProvider.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.WebService.Runtime +{ + public interface IWebServiceEntryProvider + { + IEnumerable GetEntries(); + + List CreateServiceEntries(Type service); + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/DefaultWebServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/DefaultWebServiceEntryProvider.cs new file mode 100644 index 000000000..2c14f379b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/DefaultWebServiceEntryProvider.cs @@ -0,0 +1,96 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.WebService.Runtime.Implementation +{ + public class DefaultWebServiceEntryProvider : IWebServiceEntryProvider + { + #region Field + private readonly IServiceEntryProvider _serviceEntryProvider; + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private List _webServiceEntries; + + #endregion Field + + #region Constructor + + public DefaultWebServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _serviceEntryProvider = serviceEntryProvider; + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of IServiceEntryProvider + + /// + /// 获取服务条目集合。 + /// + /// 服务条目集合。 + public IEnumerable GetEntries() + { + var services = _types.ToArray(); + if (_webServiceEntries == null) + { + _webServiceEntries = new List(); + foreach (var service in services) + { + var entries = CreateServiceEntries(service); + if (entries != null) + { + _webServiceEntries.AddRange(entries); + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下WebService服务:{string.Join(",", _webServiceEntries.Select(i => i.Type.FullName))}。"); + } + } + return _webServiceEntries; + } + #endregion + + + public List CreateServiceEntries(Type service) + { + List result = new List(); + var routeTemplate = service.GetCustomAttribute(); + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as WebServiceBehavior; + var path = RoutePatternParser.Parse(routeTemplate?.RouteTemplate, service.Name); + if (path.Length > 0 && path[0] != '/') + path = $"/{path}"; + if (behavior != null) + { + var entries = _serviceEntryProvider.GetALLEntries().Where(p => p.Type == service).ToList(); + foreach (var entry in entries) + { + result.Add(new WebServiceEntry + { + Behavior = behavior, + BaseType = service, + Type = behavior.GetType(), + Path = entry.RoutePath, + }); + } + } + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/HeaderValue.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/HeaderValue.cs new file mode 100644 index 000000000..1552d4c66 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/HeaderValue.cs @@ -0,0 +1,9 @@ + + +namespace Surging.Core.Protocol.WebService.Runtime.Implementation +{ + public class HeaderValue + { + public string Token { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/ServiceOperationTuner.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/ServiceOperationTuner.cs new file mode 100644 index 000000000..98d873303 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/Implementation/ServiceOperationTuner.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Http; +using SoapCore.Extensibility; +using SoapCore.ServiceModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.WebService.Runtime.Implementation +{ + public class ServiceOperationTuner : IServiceOperationTuner + { + public void Tune(HttpContext httpContext, object serviceInstance, OperationDescription operation) + { + var service = serviceInstance as WebServiceBehavior; + service?.ParseHeaderFromBody(httpContext.Request.Body); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/WebServiceBehavior.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/WebServiceBehavior.cs new file mode 100644 index 000000000..edff7fd0e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/WebServiceBehavior.cs @@ -0,0 +1,152 @@ +using Autofac; +using Surging.Core.ApiGateWay.OAuth; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.Protocol.WebService.Runtime.Implementation; +using Surging.Core.ProxyGenerator; +using System.Xml; + +namespace Surging.Core.Protocol.WebService.Runtime +{ + public abstract class WebServiceBehavior : IServiceBehavior + { + private HeaderValue _headerValue ; + + public WebServiceBehavior() + { + _headerValue = new HeaderValue(); + } + + public HeaderValue HeaderValue + { + get { return _headerValue; } + } + private ServerReceivedDelegate _received; + public event ServerReceivedDelegate Received + { + add + { + + _received += value; + } + remove + { + _received -= value; + } + } + + + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + + + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (_received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await _received(message); + } + public T CreateProxy(string key) where T : class + { + return ServiceLocator.GetService().CreateProxy(key); + } + + public object CreateProxy(Type type) + { + return ServiceLocator.GetService().CreateProxy(type); + } + + public object CreateProxy(string key, Type type) + { + return ServiceLocator.GetService().CreateProxy(key, type); + } + + public T CreateProxy() where T : class + { + return ServiceLocator.GetService().CreateProxy(); + } + + public T GetService(string key) where T : class + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return ServiceLocator.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public T GetService() where T : class + { + if (ServiceLocator.Current.IsRegistered()) + return ServiceLocator.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return ServiceLocator.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return ServiceLocator.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + public void ParseHeaderFromBody(Stream body) + { + try + { + body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(body); + var xml = reader.ReadToEndAsync().GetAwaiter().GetResult(); + if (string.IsNullOrEmpty(xml)) + { + return; + } + var envelope = new XmlDocument(); + envelope.LoadXml(xml); + var node = envelope.DocumentElement?.ChildNodes.Cast().FirstOrDefault(n => n.LocalName == "Header")?.FirstChild; + if (node == null) + { + return; + } + var cns = node.ChildNodes.Cast(); + _headerValue.Token = cns.FirstOrDefault(d => d.LocalName == "Token")?.InnerText; + } + catch (Exception ex) + { + throw ex; + } + } + + public async Task ValidateAuthentication(string token) + { + return await GetService().ValidateClientAuthentication(token); + } + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + } +} + diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/WebServiceEntry.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/WebServiceEntry.cs new file mode 100644 index 000000000..41c93ad08 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Runtime/WebServiceEntry.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Protocol.WebService.Runtime +{ + public class WebServiceEntry + { + public string Path { get; set; } + + public Type Type { get; set; } + + public Type BaseType { get; set; } + + public WebServiceBehavior Behavior { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/Surging.Core.Protocol.WebService.csproj b/src/Surging.Core/Surging.Core.Protocol.WebService/Surging.Core.Protocol.WebService.csproj new file mode 100644 index 000000000..864b3a1c5 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/Surging.Core.Protocol.WebService.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Protocol.WebService/WebServiceModule.cs b/src/Surging.Core/Surging.Core.Protocol.WebService/WebServiceModule.cs new file mode 100644 index 000000000..bde3ac436 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Protocol.WebService/WebServiceModule.cs @@ -0,0 +1,70 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using SoapCore; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.KestrelHttpServer; +using Surging.Core.Protocol.WebService.Runtime; +using Surging.Core.Protocol.WebService.Runtime.Implementation; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using System.ServiceModel; +using System.Xml; + +namespace Surging.Core.Protocol.WebService +{ + public class WebServiceModule : KestrelHttpModule + { + private IWebServiceEntryProvider _webServiceEntryProvider; + public override void Initialize(AppModuleContext context) + { + _webServiceEntryProvider = context.ServiceProvoider.GetInstances(); + } + + public override void Initialize(ApplicationInitializationContext builder) + { + var webServiceEntries = _webServiceEntryProvider.GetEntries(); + var binging = new BasicHttpBinding(); + + binging.ReaderQuotas.MaxStringContentLength = int.MaxValue; + builder.Builder.UseRouting(); + builder.Builder.Use((context, next) => { context.Request.EnableBuffering(); return next(); }); + builder.Builder.UseEndpoints(endpoints => + { + foreach (var webServiceEntry in webServiceEntries) + { + endpoints.UseSoapEndpoint(webServiceEntry.BaseType, $"/{webServiceEntry.Path}.asmx", new SoapEncoderOptions() + { + ReaderQuotas = new XmlDictionaryReaderQuotas() + { + MaxStringContentLength = int.MaxValue, + MaxArrayLength = int.MaxValue, + MaxDepth = int.MaxValue + } + }, SoapSerializer.XmlSerializer); + } + }); + + } + + + public override void RegisterBuilder(ConfigurationContext context) + { + context.Services.AddSoapServiceOperationTuner(new ServiceOperationTuner()); + // context.Services.AddSoapCore(); + } + + protected async override void RegisterBuilder(ContainerBuilderWrapper builder) + { + builder.Register(provider => + { + return new DefaultWebServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(IWebServiceEntryProvider)).SingleInstance(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/ContainerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/ContainerBuilderExtensions.cs index 21fc3c35d..0e72fe058 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/ContainerBuilderExtensions.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/ContainerBuilderExtensions.cs @@ -5,12 +5,20 @@ using Surging.Core.ProxyGenerator.Interceptors; using Surging.Core.ProxyGenerator.Interceptors.Implementation; using Surging.Core.CPlatform.Runtime.Client; -using Surging.Core.CPlatform.Convertibles; +using Surging.Core.CPlatform.Convertibles; +using Surging.Core.ProxyGenerator.Diagnostics; +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Routing; namespace Surging.Core.ProxyGenerator { public static class ContainerBuilderExtensions { + /// + /// 添加客户端代理 + /// + /// 服务构建者 + /// 服务构建者。 public static IServiceBuilder AddClientProxy(this IServiceBuilder builder) { var services = builder.Services; @@ -20,6 +28,7 @@ public static IServiceBuilder AddClientProxy(this IServiceBuilder builder) provider.Resolve(), provider.Resolve(), provider.Resolve(), + provider.Resolve(), builder.GetInterfaceService(), builder.GetDataContractName() )).As().SingleInstance(); @@ -34,6 +43,19 @@ public static IServiceBuilder AddClientIntercepted(this IServiceBuilder builder, return builder; } + public static IServiceBuilder AddRpcTransportDiagnostic(this IServiceBuilder builder) + { + var services = builder.Services; + services.RegisterType().As().SingleInstance(); + return builder; + } + + /// + /// 添加客户端拦截 + /// + /// + /// + /// 服务构建者 public static IServiceBuilder AddClientIntercepted(this IServiceBuilder builder, Type interceptorServiceType) { var services = builder.Services; @@ -50,11 +72,21 @@ public static IServiceBuilder AddClient(this ContainerBuilder services) .AddClientProxy(); } - public static IServiceBuilder AddRelateService(this IServiceBuilder builder) + /// + /// 添加关联服务 + /// + /// + /// 服务构建者 + public static IServiceBuilder AddRelateService(this IServiceBuilder builder) { return builder.AddRelateServiceRuntime().AddClientProxy(); } - + + /// + /// 添加客户端属性注入 + /// + /// 服务构建者 + /// 服务构建者 public static IServiceBuilder AddClient(this IServiceBuilder builder) { return builder @@ -62,6 +94,7 @@ public static IServiceBuilder AddClient(this IServiceBuilder builder) .RegisterRepositories() .RegisterServiceBus() .RegisterModules() + .RegisterInstanceByConstraint() .AddClientRuntime() .AddClientProxy(); } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Diagnostics/RpcTransportCarrierHeaderCollection.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Diagnostics/RpcTransportCarrierHeaderCollection.cs new file mode 100644 index 000000000..61b3c8bdd --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Diagnostics/RpcTransportCarrierHeaderCollection.cs @@ -0,0 +1,33 @@ +using Surging.Core.CPlatform.Diagnostics; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator.Diagnostics +{ + public class RpcTransportCarrierHeaderCollection : ICarrierHeaderCollection + { + private readonly TracingHeaders _tracingHeaders; + + public RpcTransportCarrierHeaderCollection(TracingHeaders tracingHeaders) + { + _tracingHeaders = tracingHeaders; + } + + public IEnumerator> GetEnumerator() + { + return _tracingHeaders.GetEnumerator(); + } + + public void Add(string key, string value) + { + _tracingHeaders.Add(key, value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _tracingHeaders.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Diagnostics/RpcTransportDiagnosticProcessor.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Diagnostics/RpcTransportDiagnosticProcessor.cs new file mode 100644 index 000000000..a42f9d730 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Diagnostics/RpcTransportDiagnosticProcessor.cs @@ -0,0 +1,96 @@ + +using Surging.Core.CPlatform.Diagnostics; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Serialization; +using Surging.Core.CPlatform.Utilities; +using System; +using System.Collections.Concurrent; +using System.Text; +using SurgingEvents = Surging.Core.CPlatform.Diagnostics.DiagnosticListenerExtensions; + +namespace Surging.Core.ProxyGenerator.Diagnostics +{ + public class RpcTransportDiagnosticProcessor : ITracingDiagnosticProcessor + { + private Func _transportOperationNameResolver; + public string ListenerName => SurgingEvents.DiagnosticListenerName; + + + private readonly ConcurrentDictionary _resultDictionary = + new ConcurrentDictionary(); + + private readonly ISerializer _serializer; + private readonly ITracingContext _tracingContext; + + public Func TransportOperationNameResolver + { + get + { + return _transportOperationNameResolver ?? + (_transportOperationNameResolver = (data) => "Rpc-Transport:: " + data.Message.MessageName); + } + set => _transportOperationNameResolver = + value ?? throw new ArgumentNullException(nameof(TransportOperationNameResolver)); + } + + public RpcTransportDiagnosticProcessor(ITracingContext tracingContext, ISerializer serializer) + { + _tracingContext = tracingContext; + _serializer = serializer; + } + + [DiagnosticName(SurgingEvents.SurgingBeforeTransport, TransportType.Rpc)] + public void TransportBefore([Object] TransportEventData eventData) + { + var message = eventData.Message.GetContent(); + var operationName = TransportOperationNameResolver(eventData); + var context = _tracingContext.CreateEntrySegmentContext(operationName, + new RpcTransportCarrierHeaderCollection(eventData.Headers)); + if (!string.IsNullOrEmpty(eventData.TraceId)) + context.TraceId = ConvertUniqueId(eventData); + context.Span.AddLog(LogEvent.Message($"Worker running at: {DateTime.Now}")); + context.Span.SpanLayer = SpanLayer.RPC_FRAMEWORK; + context.Span.Peer = new StringOrIntValue(eventData.RemoteAddress); + context.Span.AddTag(Tags.RPC_METHOD, eventData.Method.ToString()); + context.Span.AddTag(Tags.RPC_PARAMETERS, _serializer.Serialize(message.Parameters)); + context.Span.AddTag(Tags.RPC_LOCAL_ADDRESS, NetUtils.GetHostAddress().ToString()); + _resultDictionary.TryAdd(eventData.OperationId.ToString(), context); + } + + [DiagnosticName(SurgingEvents.SurgingAfterTransport, TransportType.Rpc)] + public void TransportAfter([Object] ReceiveEventData eventData) + { + _resultDictionary.TryRemove(eventData.OperationId.ToString(), out SegmentContext context); + if (context != null) + { + _tracingContext.Release(context); + } + } + + [DiagnosticName(SurgingEvents.SurgingErrorTransport, TransportType.Rpc)] + public void TransportError([Object] TransportErrorEventData eventData) + { + _resultDictionary.TryRemove(eventData.OperationId.ToString(),out SegmentContext context); + if (context != null) + { + context.Span.ErrorOccurred(eventData.Exception); + _tracingContext.Release(context); + } + } + + public UniqueId ConvertUniqueId(TransportEventData eventData) + { + long part1 = 0, part2 = 0, part3 = 0; + UniqueId uniqueId = new UniqueId(); + var bytes = Encoding.Default.GetBytes(eventData.TraceId); + part1 = BitConverter.ToInt64(bytes, 0); + if (eventData.TraceId.Length > 8) + part2 = BitConverter.ToInt64(bytes, 8); + if (eventData.TraceId.Length > 16) + part3 = BitConverter.ToInt64(bytes, 16); + if (!string.IsNullOrEmpty(eventData.TraceId)) + uniqueId = new UniqueId(part1, part2, part3); + return uniqueId; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/IServiceProxyProvider.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/IServiceProxyProvider.cs index 77075f333..3d2a66fdf 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/IServiceProxyProvider.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/IServiceProxyProvider.cs @@ -5,6 +5,9 @@ namespace Surging.Core.ProxyGenerator { + /// + /// 代理服务接口 + /// public interface IServiceProxyProvider { Task Invoke(IDictionary parameters, string routePath); diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/RemoteServiceProxy.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/RemoteServiceProxy.cs index 76d52f017..858bfac3f 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/RemoteServiceProxy.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/RemoteServiceProxy.cs @@ -22,7 +22,7 @@ public RemoteServiceProxy(string serviceKey, CPlatformContainer serviceProvider) public RemoteServiceProxy(IRemoteInvokeService remoteInvokeService, ITypeConvertibleService typeConvertibleService, String serviceKey, CPlatformContainer serviceProvider, IServiceRouteProvider serviceRouteProvider - ):base(remoteInvokeService, typeConvertibleService, serviceKey, serviceProvider) + ):base(remoteInvokeService, typeConvertibleService, serviceKey, serviceProvider, serviceRouteProvider) { } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyBase.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyBase.cs index db7cff56d..625542efe 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyBase.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyBase.cs @@ -11,6 +11,8 @@ using Autofac; using Surging.Core.CPlatform.Utilities; using System.Linq; +using Surging.Core.CPlatform.Routing; +using Surging.Core.ProxyGenerator.Interceptors.Implementation; namespace Surging.Core.ProxyGenerator.Implementation { @@ -24,16 +26,16 @@ public abstract class ServiceProxyBase private readonly ITypeConvertibleService _typeConvertibleService; private readonly string _serviceKey; private readonly CPlatformContainer _serviceProvider; + private readonly IServiceRouteProvider _serviceRouteProvider; private readonly IServiceCommandProvider _commandProvider; private readonly IBreakeRemoteInvokeService _breakeRemoteInvokeService; - private readonly IEnumerable _interceptors; - private readonly IInterceptor _cacheInterceptor; + private readonly IEnumerable _interceptors; #endregion Field #region Constructor protected ServiceProxyBase(IRemoteInvokeService remoteInvokeService, - ITypeConvertibleService typeConvertibleService, String serviceKey, CPlatformContainer serviceProvider) + ITypeConvertibleService typeConvertibleService, String serviceKey, CPlatformContainer serviceProvider, IServiceRouteProvider serviceRouteProvider) { _remoteInvokeService = remoteInvokeService; _typeConvertibleService = typeConvertibleService; @@ -41,15 +43,12 @@ protected ServiceProxyBase(IRemoteInvokeService remoteInvokeService, _serviceProvider = serviceProvider; _commandProvider = serviceProvider.GetInstances(); _breakeRemoteInvokeService = serviceProvider.GetInstances(); + _serviceRouteProvider = serviceRouteProvider; _interceptors = new List(); if (serviceProvider.Current.IsRegistered()) - { - var interceptors = serviceProvider.GetInstances>(); - _interceptors = interceptors.Where(p => !typeof(CacheInterceptor).IsAssignableFrom(p.GetType())); - _cacheInterceptor = interceptors.Where(p => typeof(CacheInterceptor).IsAssignableFrom(p.GetType())).FirstOrDefault(); - } - - + { + _interceptors = serviceProvider.GetInstances>(); + } } #endregion Constructor @@ -64,12 +63,14 @@ protected ServiceProxyBase(IRemoteInvokeService remoteInvokeService, protected async Task Invoke(IDictionary parameters, string serviceId) { object result = default(T); - var command = await _commandProvider.GetCommand(serviceId); + var vt = _commandProvider.GetCommand(serviceId); + var command = vt.IsCompletedSuccessfully ? vt.Result : await vt; RemoteInvokeResultMessage message = null; var decodeJOject = typeof(T) == UtilityType.ObjectType; IInvocation invocation = null; - var existsInterceptor = _interceptors.Any(); - if ((!command.RequestCacheEnabled || decodeJOject) && !existsInterceptor) + var serviceRoute =await _serviceRouteProvider.Locate(serviceId); + if ((serviceRoute == null || !serviceRoute.ServiceDescriptor.ExistIntercept()) || + (!serviceRoute.ServiceDescriptor.GetCacheIntercept("Cache").EnableStageCache && decodeJOject)) { message = await _breakeRemoteInvokeService.InvokeAsync(parameters, serviceId, _serviceKey, decodeJOject); if (message == null) @@ -86,14 +87,7 @@ protected async Task Invoke(IDictionary parameters, string } } } - if (command.RequestCacheEnabled && !decodeJOject) - { - invocation = GetCacheInvocation(parameters, serviceId, typeof(T)); - var interceptReuslt = await Intercept(_cacheInterceptor, invocation); - message = interceptReuslt.Item1; - result = interceptReuslt.Item2 == null ? default(T) : interceptReuslt.Item2; - } - if (existsInterceptor) + else { invocation = invocation == null ? GetInvocation(parameters, serviceId, typeof(T)) : invocation; foreach (var interceptor in _interceptors) @@ -104,7 +98,10 @@ protected async Task Invoke(IDictionary parameters, string } } if (message != null) - result = _typeConvertibleService.Convert(message.Result, typeof(T)); + { + if (message.Result == null) result = message.Result; + else result = _typeConvertibleService.Convert(message.Result, typeof(T)); + } return (T)result; } @@ -118,7 +115,8 @@ public async Task CallInvoke(IInvocation invocation) type == typeof(Task) ? false : true); if (message == null) { - var command = await _commandProvider.GetCommand(serviceId); + var vt = _commandProvider.GetCommand(serviceId); + var command = vt.IsCompletedSuccessfully ? vt.Result : await vt; if (command.FallBackName != null && _serviceProvider.IsRegistered(command.FallBackName) && command.Strategy == StrategyType.FallBack) { var invoker = _serviceProvider.GetInstances(command.FallBackName); @@ -144,7 +142,8 @@ protected async Task Invoke(IDictionary parameters, string servi { var existsInterceptor = _interceptors.Any(); RemoteInvokeResultMessage message = null; - if (!existsInterceptor) + var serviceRoute = await _serviceRouteProvider.Locate(serviceId); + if (serviceRoute == null || !serviceRoute.ServiceDescriptor.ExistIntercept()) message = await _breakeRemoteInvokeService.InvokeAsync(parameters, serviceId, _serviceKey, false); else { @@ -157,7 +156,8 @@ protected async Task Invoke(IDictionary parameters, string servi } if (message == null) { - var command = await _commandProvider.GetCommand(serviceId); + var vt = _commandProvider.GetCommand(serviceId); + var command = vt.IsCompletedSuccessfully ? vt.Result : await vt; if (command.FallBackName != null && _serviceProvider.IsRegistered(command.FallBackName) && command.Strategy == StrategyType.FallBack) { var invoker = _serviceProvider.GetInstances(command.FallBackName); @@ -178,8 +178,7 @@ private async Task> Intercept(IIntercep ? invocation.ReturnValue as RemoteInvokeResultMessage : null; return new Tuple(message, invocation.ReturnValue); } - - + private IInvocation GetInvocation(IDictionary parameters, string serviceId, Type returnType) { var invocation = _serviceProvider.GetInstances(); diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyFactory.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyFactory.cs index c04db1be7..87d8d6061 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyFactory.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyFactory.cs @@ -8,6 +8,8 @@ using Surging.Core.CPlatform.Support; using System.Collections.Generic; using Surging.Core.CPlatform.DependencyResolution; +using System.Runtime.CompilerServices; +using Surging.Core.CPlatform.Routing; namespace Surging.Core.ProxyGenerator.Implementation { @@ -20,21 +22,23 @@ public class ServiceProxyFactory : IServiceProxyFactory private readonly IRemoteInvokeService _remoteInvokeService; private readonly ITypeConvertibleService _typeConvertibleService; private readonly IServiceProvider _serviceProvider; - private Type[] _serviceTypes; + private readonly IServiceRouteProvider _serviceRouteProvider; + private Type[] _serviceTypes=new Type[0]; #endregion Field #region Constructor public ServiceProxyFactory(IRemoteInvokeService remoteInvokeService, ITypeConvertibleService typeConvertibleService, - IServiceProvider serviceProvider):this(remoteInvokeService, typeConvertibleService, serviceProvider,null,null) + IServiceProvider serviceProvider, IServiceRouteProvider serviceRouteProvider) :this(remoteInvokeService, typeConvertibleService, serviceProvider, serviceRouteProvider,null, null) { } public ServiceProxyFactory(IRemoteInvokeService remoteInvokeService, ITypeConvertibleService typeConvertibleService, - IServiceProvider serviceProvider, IEnumerable types, IEnumerable namespaces) + IServiceProvider serviceProvider,IServiceRouteProvider serviceRouteProvider, IEnumerable types, IEnumerable namespaces) { + _serviceRouteProvider = serviceRouteProvider; _remoteInvokeService = remoteInvokeService; _typeConvertibleService = typeConvertibleService; _serviceProvider = serviceProvider; @@ -48,7 +52,7 @@ public ServiceProxyFactory(IRemoteInvokeService remoteInvokeService, ITypeConver #region Implementation of IServiceProxyFactory - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public object CreateProxy(Type type) { var instance = ServiceResolver.Current.GetService(type); @@ -56,12 +60,13 @@ public object CreateProxy(Type type) { var proxyType = _serviceTypes.Single(type.GetTypeInfo().IsAssignableFrom); instance = proxyType.GetTypeInfo().GetConstructors().First().Invoke(new object[] { _remoteInvokeService, _typeConvertibleService, null, - _serviceProvider.GetService()}); + _serviceProvider.GetService(),_serviceRouteProvider}); ServiceResolver.Current.Register(null, instance, type); } return instance; } - + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public object CreateProxy(string key,Type type) { var instance = ServiceResolver.Current.GetService(type,key); @@ -69,12 +74,13 @@ public object CreateProxy(string key,Type type) { var proxyType = _serviceTypes.Single(type.GetTypeInfo().IsAssignableFrom); instance = proxyType.GetTypeInfo().GetConstructors().First().Invoke(new object[] { _remoteInvokeService, _typeConvertibleService, key, - _serviceProvider.GetService()}); + _serviceProvider.GetService(),_serviceRouteProvider}); ServiceResolver.Current.Register(key, instance, type); } return instance; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public T CreateProxy(string key) where T:class { var instanceType = typeof(T); @@ -83,7 +89,7 @@ public T CreateProxy(string key) where T:class { var proxyType = _serviceTypes.Single(typeof(T).GetTypeInfo().IsAssignableFrom); instance = proxyType.GetTypeInfo().GetConstructors().First().Invoke(new object[] { _remoteInvokeService, _typeConvertibleService,key, - _serviceProvider.GetService() }); + _serviceProvider.GetService(),_serviceRouteProvider }); ServiceResolver.Current.Register(key, instance, instanceType); } return instance as T; @@ -94,11 +100,14 @@ public T CreateProxy() where T : class return CreateProxy(null); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterProxType(string[] namespaces,params Type[] types) { var proxyGenerater = _serviceProvider.GetService(); - _serviceTypes = proxyGenerater.GenerateProxys(types, namespaces).ToArray(); + var serviceTypes = proxyGenerater.GenerateProxys(types, namespaces).ToArray(); + _serviceTypes= _serviceTypes.Except(serviceTypes).Concat(serviceTypes).ToArray(); proxyGenerater.Dispose(); + GC.Collect(); } #endregion Implementation of IServiceProxyFactory diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyGenerater.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyGenerater.cs index 4380a8f94..9e9304988 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyGenerater.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyGenerater.cs @@ -22,6 +22,7 @@ using Microsoft.Extensions.Logging; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing; namespace Surging.Core.ProxyGenerator.Implementation { @@ -62,7 +63,7 @@ public IEnumerable GenerateProxys(IEnumerable interfacTypes, IEnumer types = interfacTypes.Except(types); foreach (var t in types) { - assemblys = assemblys.Append(t.Assembly); + assemblys = assemblys.Append(t.Assembly).ToArray(); } var trees = interfacTypes.Select(p=>GenerateProxyTree(p,namespaces)).ToList(); var stream = CompilationUtilitys.CompileClientProxy(trees, @@ -172,6 +173,7 @@ private static SyntaxList GetUsings(IEnumerable na UsingDirective(GetQualifiedNameSyntax("System.Collections.Generic")), UsingDirective(GetQualifiedNameSyntax(typeof(ITypeConvertibleService).Namespace)), UsingDirective(GetQualifiedNameSyntax(typeof(IRemoteInvokeService).Namespace)), + UsingDirective(GetQualifiedNameSyntax(typeof(IServiceRouteProvider).Namespace)), UsingDirective(GetQualifiedNameSyntax(typeof(CPlatformContainer).Namespace)), UsingDirective(GetQualifiedNameSyntax(typeof(ISerializer<>).Namespace)), UsingDirective(GetQualifiedNameSyntax(typeof(ServiceProxyBase).Namespace)) @@ -207,7 +209,12 @@ private static ConstructorDeclarationSyntax GetConstructorDeclaration(string cla Parameter( Identifier("serviceProvider")) .WithType( - IdentifierName("CPlatformContainer")) + IdentifierName("CPlatformContainer")), + Token(SyntaxKind.CommaToken), + Parameter( + Identifier("serviceRouteProvider")) + .WithType( + IdentifierName("IServiceRouteProvider")) }))) .WithInitializer( ConstructorInitializer( @@ -225,7 +232,10 @@ private static ConstructorDeclarationSyntax GetConstructorDeclaration(string cla IdentifierName("serviceKey")), Token(SyntaxKind.CommaToken), Argument( - IdentifierName("serviceProvider")) + IdentifierName("serviceProvider")), + Token(SyntaxKind.CommaToken), + Argument( + IdentifierName("serviceRouteProvider")) })))) .WithBody(Block()); } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyProvider.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyProvider.cs index daa7d6c95..c8e2e98ad 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyProvider.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Implementation/ServiceProxyProvider.cs @@ -17,30 +17,33 @@ public ServiceProxyProvider( IServiceRouteProvider serviceRouteProvider _serviceProvider = serviceProvider; } - public async Task Invoke(IDictionary parameters, string routePath) + public async Task Invoke(IDictionary parameters, string routePath) { var serviceRoute= await _serviceRouteProvider.GetRouteByPath(routePath.ToLower()); T result = default(T); if (parameters.ContainsKey("serviceKey")) { var serviceKey = parameters["serviceKey"].ToString(); - var proxy = ServiceResolver.Current.GetService(serviceKey); - if (proxy == null) - { - proxy = new RemoteServiceProxy(serviceKey.ToString(), _serviceProvider); - ServiceResolver.Current.Register(serviceKey.ToString(), proxy); - } + //var proxy = ServiceResolver.Current.GetService(serviceKey); + //if (proxy == null) + //{ + // proxy = new RemoteServiceProxy(serviceKey.ToString(), _serviceProvider); + // ServiceResolver.Current.Register(serviceKey.ToString(), proxy); + //} + var proxy = new RemoteServiceProxy(serviceKey, _serviceProvider); result = await proxy.Invoke(parameters, serviceRoute.ServiceDescriptor.Id); } else { - var proxy = ServiceResolver.Current.GetService(); - if (proxy == null) - { - proxy = new RemoteServiceProxy(null, _serviceProvider); - ServiceResolver.Current.Register(null, proxy); - } + //var proxy = ServiceResolver.Current.GetService(); + + //if (proxy == null) + //{ + // proxy = new RemoteServiceProxy(null, _serviceProvider); + // ServiceResolver.Current.Register(null, proxy); + //} + var proxy = new RemoteServiceProxy(null, _serviceProvider); result = await proxy.Invoke(parameters, serviceRoute.ServiceDescriptor.Id); } return result; @@ -52,22 +55,26 @@ public async Task Invoke(IDictionary parameters, string ro T result = default(T); if (!string.IsNullOrEmpty(serviceKey)) { - var proxy = ServiceResolver.Current.GetService(serviceKey); - if (proxy == null) - { - proxy = new RemoteServiceProxy(serviceKey, _serviceProvider); - ServiceResolver.Current.Register(serviceKey, proxy); - } + // var proxy = ServiceResolver.Current.GetService(serviceKey); + + //if (proxy == null) + //{ + // proxy = new RemoteServiceProxy(serviceKey, _serviceProvider); + // ServiceResolver.Current.Register(serviceKey, proxy); + //} + var proxy = new RemoteServiceProxy(serviceKey, _serviceProvider); result = await proxy.Invoke(parameters, serviceRoute.ServiceDescriptor.Id); } else { - var proxy = ServiceResolver.Current.GetService(); - if (proxy == null) - { - proxy = new RemoteServiceProxy(null, _serviceProvider); - ServiceResolver.Current.Register(null, proxy); - } + //var proxy = ServiceResolver.Current.GetService(); + + //if (proxy == null) + //{ + // proxy = new RemoteServiceProxy(null, _serviceProvider); + // ServiceResolver.Current.Register(null, proxy); + //} + var proxy = new RemoteServiceProxy(null, _serviceProvider); result = await proxy.Invoke(parameters, serviceRoute.ServiceDescriptor.Id); } return result; diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/IInterceptorProvider.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/IInterceptorProvider.cs index 8f401f7d3..d3f282092 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/IInterceptorProvider.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/IInterceptorProvider.cs @@ -9,5 +9,7 @@ public interface IInterceptorProvider IInvocation GetInvocation(object proxy, IDictionary parameters, string serviceId, Type returnType); IInvocation GetCacheInvocation(object proxy, IDictionary parameters,string serviceId, Type returnType); + + string[] GetCacheKeyVaule(IDictionary parameterValue); } } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/InterceptorProvider.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/InterceptorProvider.cs index b27afad80..4d01cc6f7 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/InterceptorProvider.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/InterceptorProvider.cs @@ -36,7 +36,7 @@ public IInvocation GetInvocation(object proxy, IDictionary param public IInvocation GetCacheInvocation(object proxy, IDictionary parameters, string serviceId, Type returnType) { - var entry = (from q in _serviceEntryManager.GetEntries() + var entry = (from q in _serviceEntryManager.GetAllEntries() let k = q.Attributes where q.Descriptor.Id == serviceId select q).FirstOrDefault(); @@ -51,6 +51,11 @@ public IInvocation GetCacheInvocation(object proxy, IDictionary }) as IInvocation; } + public string[] GetCacheKeyVaule(IDictionary parameterValue) + { + return this.GetKey(parameterValue); + } + private string[] GetKey(IDictionary parameterValue) { var param = parameterValue.Values.FirstOrDefault(); @@ -88,5 +93,7 @@ private bool IsKeyAttributeDerivedType(Type baseType,Type derivedType) } return result; } + + } } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/CacheTargetType.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/CacheTargetType.cs new file mode 100644 index 000000000..d038fe4f1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/CacheTargetType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator.Interceptors.Implementation.Metadatas +{ + public enum CacheTargetType + { + Redis, + CouchBase, + Memcached, + MemoryCache, + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/CachingMethod.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/CachingMethod.cs new file mode 100644 index 000000000..bc98b2ea7 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/CachingMethod.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator.Interceptors.Implementation.Metadatas +{ + public enum CachingMethod + { + Get, + Put, + Remove + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceCacheIntercept.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceCacheIntercept.cs new file mode 100644 index 000000000..08d7016f6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceCacheIntercept.cs @@ -0,0 +1,120 @@ +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator.Interceptors.Implementation.Metadatas +{ + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public class ServiceCacheIntercept : ServiceIntercept + { + #region 字段 + + #endregion + + #region 构造函数 + /// + /// 初始化一个新的InterceptMethodAttribute类型。 + /// + /// 缓存方式。 + public ServiceCacheIntercept(CachingMethod method) + { + this.Method = method; + } + /// + /// 初始化一个新的InterceptMethodAttribute类型。 + /// + /// 缓存方式。 + /// 与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。 + public ServiceCacheIntercept(CachingMethod method, params string[] correspondingMethodNames) + : this(method) + { + this.CorrespondingKeys = correspondingMethodNames; + } + + internal ServiceCacheIntercept(string[] serviceInterceptItem) + { + Key = serviceInterceptItem[0]; + L2Key = serviceInterceptItem[1]; + EnableL2Cache = serviceInterceptItem[2] == "1" ? true : false; + Enum.TryParse(serviceInterceptItem[3], out CacheTargetType mode); + Mode = mode; + CacheSectionType = serviceInterceptItem[4]; + Enum.TryParse(serviceInterceptItem[5], out CachingMethod method); + Method = method; + Force = serviceInterceptItem[6] == "1" ? true : false; ; + Time = Convert.ToInt32(serviceInterceptItem[7]); + if (!string.IsNullOrEmpty(serviceInterceptItem[8])) + { + CorrespondingKeys = serviceInterceptItem[8].Split(","); + } + if (serviceInterceptItem.Length > 9) + EnableStageCache = serviceInterceptItem[9] == "1" ? true : false; + } + #endregion + + #region 公共属性 + /// + /// 有效时间 + /// + public int Time { get; set; } = 60; + /// + /// 采用什么进行缓存 + /// + public CacheTargetType Mode { get; set; } = CacheTargetType.MemoryCache; + + ///// + ///// 设置SectionType + ///// + public string CacheSectionType + { + get; + set; + } = ""; + + public string L2Key + { + get; set; + } = ""; + + public bool EnableL2Cache + { + get; set; + } + + public string Key { get; set; } = ""; + /// + /// 获取或设置缓存方式。 + /// + public CachingMethod Method { get; set; } + + /// + /// 获取或设置一个值,该值表示当缓存方式为Put时,是否强制将值写入缓存中。 + /// + public bool Force { get; set; } + + public bool EnableStageCache { get; set; } = AppConfig.ServerOptions.RequestCacheEnabled; + /// + /// 获取或设置与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。 + /// + public string[] CorrespondingKeys { get; set; } + protected override string MetadataId { get; set; } = "Cache"; + + public override void Apply(ServiceDescriptor descriptor) + { + descriptor.Intercept(MetadataId).Key(Key, MetadataId) + .L2Key(L2Key, MetadataId) + .EnableL2Cache(EnableL2Cache, MetadataId) + .Mode(Mode, MetadataId) + .CacheSectionType(CacheSectionType, MetadataId) + .Method(Method, MetadataId) + .Force(Force, MetadataId) + .CacheTime(Time, MetadataId) + .CorrespondingKeys(CorrespondingKeys, MetadataId) + .EnableStageCache(EnableStageCache, MetadataId); + } + + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceIntercept.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceIntercept.cs new file mode 100644 index 000000000..82a7c8c9d --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceIntercept.cs @@ -0,0 +1,13 @@ +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator.Interceptors.Implementation.Metadatas +{ + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public abstract class ServiceIntercept : ServiceDescriptorAttribute + { + protected abstract string MetadataId { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceLogIntercept.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceLogIntercept.cs new file mode 100644 index 000000000..5f1fb03cd --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/Metadatas/ServiceLogIntercept.cs @@ -0,0 +1,31 @@ +using Surging.Core.CPlatform; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator.Interceptors.Implementation.Metadatas +{ + public class ServiceLogIntercept : ServiceIntercept + { + protected override string MetadataId { get; set; } = "Log"; + + + #region 构造函数 + /// + /// 初始化一个新的InterceptMethodAttribute类型。 + /// + public ServiceLogIntercept() + { + + } + #endregion + + #region 公共属性 + #endregion + + public override void Apply(ServiceDescriptor descriptor) + { + descriptor.Intercept(MetadataId); + } + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/ServiceDescriptorExtensions.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/ServiceDescriptorExtensions.cs new file mode 100644 index 000000000..f772bddf9 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Interceptors/Implementation/ServiceDescriptorExtensions.cs @@ -0,0 +1,199 @@ +using Surging.Core.CPlatform; +using Surging.Core.ProxyGenerator.Interceptors.Implementation.Metadatas; +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using Newtonsoft.Json.Linq; + +namespace Surging.Core.ProxyGenerator.Interceptors.Implementation +{ + public static class ServiceDescriptorExtensions + { + public static ServiceDescriptor CacheTime(this ServiceDescriptor descriptor,int time, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = time.ToString(); + else + metadata.Item1 += $"|{time}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor Mode(this ServiceDescriptor descriptor, CacheTargetType cacheTargetType, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + var targetType= Convert.ToInt32(cacheTargetType).ToString(); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = targetType; + else + metadata.Item1 += $"|{targetType}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor Method(this ServiceDescriptor descriptor, CachingMethod cachingMethod, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + var iCachingMethod = Convert.ToInt32(cachingMethod).ToString(); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = iCachingMethod; + else + metadata.Item1 += $"|{iCachingMethod}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor CacheSectionType(this ServiceDescriptor descriptor, string cacheSectionType, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = cacheSectionType; + else + metadata.Item1 += $"|{cacheSectionType}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor Force(this ServiceDescriptor descriptor, bool Force, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + var iForce = Convert.ToInt32(Force).ToString(); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = iForce; + else + metadata.Item1 += $"|{iForce}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor Key(this ServiceDescriptor descriptor, string key, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = key; + else + metadata.Item1 += $"|{key}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor Intercept(this ServiceDescriptor descriptor, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor L2Key(this ServiceDescriptor descriptor, string L2Key, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = L2Key; + else + metadata.Item1 += $"|{L2Key}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor EnableL2Cache(this ServiceDescriptor descriptor, bool enableL2Cache,string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + var iEnableL2Cache = Convert.ToInt32(enableL2Cache).ToString(); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = iEnableL2Cache; + else + metadata.Item1 += $"|{iEnableL2Cache}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor CorrespondingKeys(this ServiceDescriptor descriptor, string[] CorrespondingKeys, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + if (CorrespondingKeys != null) + { + var correspondingKey = string.Join(",", CorrespondingKeys); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = correspondingKey; + else + metadata.Item1 += $"|{correspondingKey}"; + } + else + { + metadata.Item1 += "|"; + } + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + public static ServiceDescriptor EnableStageCache(this ServiceDescriptor descriptor, bool enableStageCache, string metadataId) + { + var metadata = GetInterceptMetadata(descriptor, metadataId); + var iEnableL2Cache = Convert.ToInt32(enableStageCache).ToString(); + if (string.IsNullOrEmpty(metadata.Item1)) + metadata.Item1 = iEnableL2Cache; + else + metadata.Item1 += $"|{iEnableL2Cache}"; + metadata.Item2[metadataId] = metadata.Item1; + descriptor.Metadatas["Intercept"] = metadata.Item2; + return descriptor; + } + + + public static ServiceCacheIntercept GetCacheIntercept(this ServiceDescriptor descriptor,string metadataId) + { + var metadata= descriptor.GetMetadata("Intercept",new JObject()); + if( metadata.ContainsKey(metadataId)) + { + return new ServiceCacheIntercept(metadata[metadataId].ToString().Split("|")); + } + return default; + } + + public static string GetIntercept(this ServiceDescriptor descriptor, string metadataId) + { + var metadata = descriptor.GetMetadata("Intercept", new JObject()); + if (metadata.ContainsKey(metadataId)) + { + return metadata[metadataId].ToString(); + } + return null; + } + + public static bool ExistIntercept(this ServiceDescriptor descriptor) + { + var metadata = descriptor.GetMetadata("Intercept", null); + + return metadata!=null; + } + + private static (string,Dictionary) GetInterceptMetadata( ServiceDescriptor descriptor, string metadataId) + { + var result = ""; + var metadata = descriptor.GetMetadata>("Intercept", new Dictionary()); + if (metadata.ContainsKey(metadataId)) + { + result= metadata[metadataId].ToString(); + } + else + { + metadata.Add(metadataId, result); + } + return (result, metadata); + } + + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/ProxyServiceBase.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/ProxyServiceBase.cs index 6d6dae7b7..3be66b073 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/ProxyServiceBase.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/ProxyServiceBase.cs @@ -4,6 +4,7 @@ using Autofac; using Surging.Core.CPlatform.EventBus.Events; using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.DependencyResolution; namespace Surging.Core.ProxyGenerator { @@ -12,58 +13,117 @@ public abstract class ProxyServiceBase: ServiceBase [Obsolete("This method is Obsolete, use GetService")] public T CreateProxy(string key) where T : class { - return ServiceLocator.GetService().CreateProxy(key); + // return ServiceLocator.GetService().CreateProxy(key); + var result = ServiceResolver.Current.GetService(key); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(key); + ServiceResolver.Current.Register(key, result); + + } + return result; } [Obsolete("This method is Obsolete, use GetService")] public object CreateProxy(Type type) { - return ServiceLocator.GetService().CreateProxy(type); + var result = ServiceResolver.Current.GetService(type); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(type); + ServiceResolver.Current.Register(null, result); + + } + return result; } [Obsolete("This method is Obsolete, use GetService")] public object CreateProxy(string key, Type type) { - return ServiceLocator.GetService().CreateProxy(key, type); + var result = ServiceResolver.Current.GetService(type,key); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(key,type); + ServiceResolver.Current.Register(key, result); + } + return result; } [Obsolete("This method is Obsolete, use GetService")] public T CreateProxy() where T : class { - return ServiceLocator.GetService().CreateProxy(); + var result = ServiceResolver.Current.GetService(); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(); + ServiceResolver.Current.Register(null,result); + } + return result; } public override T GetService(string key) { - if( ServiceLocator.Current.IsRegisteredWithKey(key)) - return base.GetService(key); - else - return ServiceLocator.GetService().CreateProxy(key); + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return base.GetService(key); + else + { + var result = ServiceResolver.Current.GetService(key); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(key); + ServiceResolver.Current.Register(key, result); + } + return result; + } } public override T GetService() { if (ServiceLocator.Current.IsRegistered()) return base.GetService(); - else - return ServiceLocator.GetService().CreateProxy(); + else + { + var result = ServiceResolver.Current.GetService(); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(); + ServiceResolver.Current.Register(null, result); + } + return result; + } } public override object GetService(Type type) { if (ServiceLocator.Current.IsRegistered(type)) - return base.GetService(type); - else - return ServiceLocator.GetService().CreateProxy(type); + return base.GetService(type); + else + { + var result = ServiceResolver.Current.GetService(type); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(type); + ServiceResolver.Current.Register(null, result); + } + return result; + } } public override object GetService(string key, Type type) { - if (ServiceLocator.Current.IsRegisteredWithKey(key,type)) - return base.GetService(key,type); + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return base.GetService(key, type); else - return ServiceLocator.GetService().CreateProxy(key,type); + { + var result = ServiceResolver.Current.GetService(type, key); + if (result == null) + { + result = ServiceLocator.GetService().CreateProxy(key, type); + ServiceResolver.Current.Register(key, result); + } + return result; + } } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/RegistrationExtensions.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/RegistrationExtensions.cs new file mode 100644 index 000000000..b889f42a3 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/RegistrationExtensions.cs @@ -0,0 +1,25 @@ +using Surging.Core.CPlatform.Module; +using Surging.Core.ProxyGenerator.Interceptors; +using Surging.Core.ProxyGenerator.Interceptors.Implementation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ProxyGenerator +{ + public static class RegistrationExtensions + { + public static void AddClientIntercepted(this ContainerBuilderWrapper builder, Type interceptorServiceType) + { + builder.RegisterType(interceptorServiceType).As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + } + + public static void AddClientIntercepted(this ContainerBuilderWrapper builder, params Type[] interceptorServiceTypes) + { + builder.RegisterTypes(interceptorServiceTypes).As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + + } + } +} diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/ServiceProxyModule.cs b/src/Surging.Core/Surging.Core.ProxyGenerator/ServiceProxyModule.cs index d4ac1b3fa..f62c047b6 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/ServiceProxyModule.cs +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/ServiceProxyModule.cs @@ -1,19 +1,44 @@ -using Surging.Core.CPlatform; +using Autofac; +using Surging.Core.CPlatform; using Surging.Core.CPlatform.Convertibles; +using Surging.Core.CPlatform.Engines; using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Routing; using Surging.Core.CPlatform.Runtime.Client; using Surging.Core.ProxyGenerator.Implementation; using System; using System.Collections.Generic; using System.Text; +using System.Linq; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.ProxyGenerator.Diagnostics; +using Surging.Core.CPlatform.Diagnostics; namespace Surging.Core.ProxyGenerator { public class ServiceProxyModule: EnginePartModule { - public override void Initialize(CPlatformContainer serviceProvider) + public override void Initialize(AppModuleContext context) { + var serviceProvider = context.ServiceProvoider; serviceProvider.GetInstances(); + if (AppConfig.ServerOptions.ReloadOnChange) + { + //new ServiceRouteWatch(serviceProvider, + // () => + // { + // var builder = new ContainerBuilder(); + // var result = serviceProvider.GetInstances().ReBuild(builder); + // if (result != null) + // { + // builder.Update(serviceProvider.Current.ComponentRegistry); + // serviceProvider.GetInstances().UpdateEntries(serviceProvider.GetInstances>()); + // // serviceProvider.GetInstances().RegisterProxType(result.Value.Item2.ToArray(), result.Value.Item1.ToArray()); + // serviceProvider.GetInstances().RegisterRoutes(0); + // serviceProvider.GetInstances(); + // } + // }); + } } /// @@ -23,8 +48,7 @@ public override void Initialize(CPlatformContainer serviceProvider) protected override void RegisterBuilder(ContainerBuilderWrapper builder) { base.RegisterBuilder(builder); - + builder.RegisterType().As().SingleInstance(); } - } } diff --git a/src/Surging.Core/Surging.Core.ProxyGenerator/Surging.Core.ProxyGenerator.csproj b/src/Surging.Core/Surging.Core.ProxyGenerator/Surging.Core.ProxyGenerator.csproj index f3d105edb..406f0edf6 100644 --- a/src/Surging.Core/Surging.Core.ProxyGenerator/Surging.Core.ProxyGenerator.csproj +++ b/src/Surging.Core/Surging.Core.ProxyGenerator/Surging.Core.ProxyGenerator.csproj @@ -1,26 +1,26 @@  - netcoreapp2.1 - 0.8.0.2 + net6.0 + 1.1.0.0 fanly surging Micro Service Framework Copyright © fanly All Rights Reserved. - 1.Service host support multiple protocols -2.Exclude interface registration service + 1.multiple register center cluster +2. fix bug https://github.com/dotnetcore/surging https://github.com/dotnetcore/surging/blob/master/LICENSE MicroService surging - 0.8.0.2 - 0.8.0.2 + 1.1.0.0 + 1.1.0.0 surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec - - - + + + diff --git a/src/Surging.Core/Surging.Core.Serilog/SerilogFilter.cs b/src/Surging.Core/Surging.Core.Serilog/SerilogFilter.cs new file mode 100644 index 000000000..1a45a2fec --- /dev/null +++ b/src/Surging.Core/Surging.Core.Serilog/SerilogFilter.cs @@ -0,0 +1,55 @@ +using Serilog.Core; +using Serilog.Events; + +namespace Surging.Core.Serilog +{ + public class SerilogVerboseFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + return logEvent.Level == LogEventLevel.Verbose; + } + + } + + public class SerilogDebugFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + return logEvent.Level == LogEventLevel.Debug; + } + + } + + public class SerilogErrorFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + return logEvent.Level == LogEventLevel.Error; + } + } + + public class SerilogFatalFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + return logEvent.Level == LogEventLevel.Fatal; + } + } + + public class SerilogInformationFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + return logEvent.Level == LogEventLevel.Information; + } + } + + public class SerilogWarningFilter : ILogEventFilter + { + public bool IsEnabled(LogEvent logEvent) + { + return logEvent.Level == LogEventLevel.Warning; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Serilog/SerilogModule.cs b/src/Surging.Core/Surging.Core.Serilog/SerilogModule.cs new file mode 100644 index 000000000..610241995 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Serilog/SerilogModule.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Events; +using Serilog.Formatting.Elasticsearch; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.ServiceHosting.Internal; + +namespace Surging.Core.Serilog +{ + public class SerilogModule: EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); + + var logger = new LoggerConfiguration().ReadFrom.Configuration(AppConfig.Configuration) + //.WriteTo.RollingFile(new ElasticsearchJsonFormatter(renderMessageTemplate:false),"c:/logs/log-{Date}.log") + //.WriteTo.Logger(config => + //{ + // //config.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Information).ReadFrom.Configuration(AppConfig.Configuration.GetSection("Information")) + //}) + .CreateLogger(); + + serviceProvider.GetInstances().AddSerilog(logger); + serviceProvider.GetInstances().ApplicationStopped.Register(Log.CloseAndFlush); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Serilog/Surging.Core.Serilog.csproj b/src/Surging.Core/Surging.Core.Serilog/Surging.Core.Serilog.csproj new file mode 100644 index 000000000..c636fa0b4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Serilog/Surging.Core.Serilog.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/LocalTimeZoneEnum.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/LocalTimeZoneEnum.cs new file mode 100644 index 000000000..3c8a63f38 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/LocalTimeZoneEnum.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.ServiceHosting.Extensions.Rules +{ + public enum LocalTimeZoneEnum + { + Local=0, + Utc=1, + China = 1050, + Italy = 1000, + US = 1100, + GB =1150, + DE =1200, + FR =1250, + JP =1300, + ES=1350, + CA =1400, + MX =1450, + AU=1600, + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/RulePipePayloadParser.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/RulePipePayloadParser.cs new file mode 100644 index 000000000..c3366374c --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/RulePipePayloadParser.cs @@ -0,0 +1,435 @@ +using Jint; +using Surging.Core.ServiceHosting.Extensions.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.ServiceHosting.Extensions.Rules +{ + public class RulePipePayloadParser + { + private DateTime _currentTime = DateTime.Now; + private ISubject _subject = new ReplaySubject(); + private LocalTimeZoneEnum _zoneEnum = LocalTimeZoneEnum.Local; + private readonly List> _pipe = new List>(); + /// + /// 立即执行 + /// + public RulePipePayloadParser Immediately() + { + _pipe.Add(_lastExecTime => + { + return true; + }); + return this; + } + /// + /// 相隔几秒执行一次 + /// + public RulePipePayloadParser SecondAt(int value) + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Now.AddSeconds(value); + return (DateTime.Now - lastExecTime).TotalSeconds >= value; + }); + return this; + } + /// + /// 每分钟执行一次任务 + /// + public RulePipePayloadParser EveryMinute() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Now.AddMinutes(1); + return (DateTime.Now - lastExecTime).TotalMinutes >= 1; + }); + return this; + } + /// + /// 每五分钟执行一次任务 + /// + public RulePipePayloadParser EveryFiveMinutes() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Now.AddMinutes(5); + return (DateTime.Now - lastExecTime).TotalMinutes >= 5; + }); + return this; + } + /// + /// 每十分钟执行一次任务 + /// + public RulePipePayloadParser EveryTenMinutes() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Now.AddMinutes(10); + return (DateTime.Now - lastExecTime).TotalMinutes >= 10; + }); + return this; + } + /// + /// 每半小时执行一次任务 + /// + public RulePipePayloadParser EveryThirtyMinutes() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Now.AddMinutes(30); + return (DateTime.Now - lastExecTime).TotalMinutes >= 30; + }); + return this; + } + /// + /// 每小时执行一次任务 + /// + public RulePipePayloadParser Hourly() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Now.AddHours(60); + return (DateTime.Now - lastExecTime).TotalMinutes >= 60; + }); + return this; + } + /// + /// 每一个小时的第 17 分钟运行一次 + /// + public RulePipePayloadParser HourlyAt(int value) + { + _pipe.Add(lastExecTime => + { + var timeSpan = value + 60; + _currentTime = DateTime.Parse($"{DateTime.Now.AddHours(1).ToString("yyyy-MM-dd mm:00:00")}").AddMinutes(value); + return (DateTime.Now - lastExecTime).TotalMinutes >= timeSpan; + }); + return this; + } + /// + /// 每到午夜执行一次任务 + /// + public RulePipePayloadParser Daily() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd 23:59:59")}").AddSeconds(1); + return (DateTime.Now - DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd 23:59:59")}")).TotalSeconds >= 1; + }); + return this; + } + /// + /// 每天的 13:00 执行一次任务 + /// + public RulePipePayloadParser DailyAt(string value) + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {value}"); + return (DateTime.Now - DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {value}")).TotalSeconds >= 0; + }); + return this; + } + + /// + /// 每天的 1:00 和 13:00 分别执行一次任务 + /// + public RulePipePayloadParser TwiceDaily(string value1, string value2) + { + _pipe.Add(lastExecTime => + { + + if ((DateTime.Now - DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {value1}")).TotalSeconds >= 0) + { + _currentTime = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {value1}"); + return true; + } + else if ((DateTime.Now - DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {value2}")).TotalSeconds <= 0) + { + _currentTime = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {value2}"); + return true; + } + return false; + + }); + return this; + } + /// + /// 每周执行一次任务 + /// + public RulePipePayloadParser Weekly() + { + _pipe.Add(lastExecTime => + { + var timeSpan = Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))); + _currentTime = DateTime.Parse($"{DateTime.Now.AddDays(timeSpan).ToString("yyyy-MM-dd")}"); + return DateTime.Now >= _currentTime; + }); + return this; + } + /// + /// 每月执行一次任务 + /// + public RulePipePayloadParser Monthly() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(1); + return DateTime.Now >= _currentTime; + }); + return this; + } + /// + /// 在每个月的第四天的 15:00 执行一次任务 + /// + public RulePipePayloadParser MonthlyOn(int value1, string value2) + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Parse(DateTime.Now.ToString($"yyyy-MM-0{value1} {value2}")).AddMonths(1); + return DateTime.Now >= _currentTime; + }); + return this; + } + /// + /// 每季度执行一次任务 + /// + public RulePipePayloadParser Quarterly() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Parse(DateTime.Now.AddMonths(3 - ((DateTime.Now.Month - 1) % 3)).ToString("yyyy-MM-01")); + return DateTime.Now >= _currentTime; + }); + return this; + } + /// + /// 每年执行一次任务 + /// + public RulePipePayloadParser Yearly() + { + _pipe.Add(lastExecTime => + { + _currentTime = DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(1); + return DateTime.Now >= _currentTime; + }); + return this; + } + + public RulePipePayloadParser Weekdays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week >= 1 && week <= 5; + }); + return this; + } + + public RulePipePayloadParser Sundays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 0; + }); + return this; + } + + public RulePipePayloadParser Mondays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 1; + }); + return this; + } + + public RulePipePayloadParser Tuesdays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 2; + }); + return this; + } + + public RulePipePayloadParser Wednesdays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 3; + }); + return this; + } + + public RulePipePayloadParser Thursdays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 4; + }); + return this; + } + + public RulePipePayloadParser Fridays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 5; + }); + return this; + } + + public RulePipePayloadParser Saturdays() + { + _pipe.Add(lastExecTime => + { + var week = (int)ToLocalTimeZone(_currentTime).DayOfWeek; + return week == 6; + }); + return this; + } + + public RulePipePayloadParser Between(string value1, string value2) + { + + _pipe.Add(lastExecTime => + { + TimeSpan currentDt = ToLocalTimeZone(_currentTime).TimeOfDay; + TimeSpan workStartDT = ToLocalTimeZone(DateTime.Parse(value1)).TimeOfDay; + TimeSpan workEndDT = ToLocalTimeZone(DateTime.Parse(value2)).TimeOfDay; + return currentDt >= workStartDT && currentDt <= workEndDT; + }); + return this; + } + + public RulePipePayloadParser UnlessBetweenBetween(string value1, string value2) + { + _pipe.Add(lastExecTime => + { + TimeSpan currentDt = ToLocalTimeZone(_currentTime).TimeOfDay; + TimeSpan workStartDT = ToLocalTimeZone(DateTime.Parse(value1)).TimeOfDay; + TimeSpan workEndDT = ToLocalTimeZone(DateTime.Parse(value2)).TimeOfDay; + return currentDt < workStartDT || currentDt > workEndDT; + }); + return this; + } + + public void Build(DateTime dateTime) + { + if (_pipe.Any()) + { + var pipeResult = true; + foreach (var pipe in _pipe) + { + try + { + pipeResult = pipe.Invoke(dateTime); + if (!pipeResult) break; + } + catch (Exception ex) + { + throw ex; + } + } + _subject.OnNext(pipeResult); + } + } + + public ISubject HandlePayload() + { + return _subject; + } + + public RulePipePayloadParser When(string script) + { + var propertyName = "script"; + script = $"var {propertyName} ={script}"; + var engine = new Engine() + .SetValue("DateUtils", new DateUtils()).Execute(script); + _pipe.Add(lastExecTime => + { + try + { + var result = engine.Invoke(propertyName, ToLocalTimeZone(lastExecTime)); + return result.AsBoolean(); + } + catch (Exception ex) + { + throw ex; + } + }); + return this; + } + + public RulePipePayloadParser TimeZone(string text) + { + _zoneEnum = Enum.Parse(text, true); + return this; + } + + private DateTime ToLocalTimeZone(DateTime time) + { + DateTime easternTime = time; + if (_zoneEnum == LocalTimeZoneEnum.Utc) + { + easternTime = easternTime.ToUniversalTime(); + } + else if (_zoneEnum != LocalTimeZoneEnum.Local) + { + TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(LocalTimeZoneEnumLong(_zoneEnum)); + easternTime = TimeZoneInfo.ConvertTimeFromUtc(time, easternZone); + } + return easternTime; + } + + private string LocalTimeZoneEnumLong(LocalTimeZoneEnum time) => time switch + { + LocalTimeZoneEnum.China => "China Standard Time", + LocalTimeZoneEnum.Italy => "W. Europe Standard Time", + LocalTimeZoneEnum.US => "Pacific Standard Time", + LocalTimeZoneEnum.GB => "GMT Standard Time", + LocalTimeZoneEnum.DE => "W. Europe Standard Time", + LocalTimeZoneEnum.FR => "Romance Standard Time", + LocalTimeZoneEnum.JP => "Tokyo Standard Time", + LocalTimeZoneEnum.ES => "Romance Standard Time", + LocalTimeZoneEnum.CA => "Pacific Standard Time", + LocalTimeZoneEnum.MX => "Central Standard Time (Mexico)", + LocalTimeZoneEnum.AU => "E. Australia Standard Time", + LocalTimeZoneEnum.Utc => "utc", + _ => "" + }; + + public RulePipePayloadParser Skip(string script) + { + var propertyName = "script"; + script = $"var {propertyName} ={script}"; + var engine = new Engine() + .SetValue("DateUtils", new DateUtils()).Execute(script); + _pipe.Add(lastExecTime => + { + try + { + var result = engine.Invoke(propertyName, ToLocalTimeZone(lastExecTime)); + return !result.AsBoolean(); + } + catch (Exception ex) + { + throw ex; + } + }); + return this; + } + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/SchedulerRuleWorkflow.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/SchedulerRuleWorkflow.cs new file mode 100644 index 000000000..d406e056d --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Rules/SchedulerRuleWorkflow.cs @@ -0,0 +1,67 @@ +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Surging.Core.ServiceHosting.Extensions.Rules +{ + public class SchedulerRuleWorkflow + { + public SchedulerRuleWorkflow() : this("SchedulerRuleWorkflow", "SchedulerRule", "1 == 1", "OutputExpression", new Dictionary()) + { + + } + + public SchedulerRuleWorkflow(string actionExpression) : this() + { + var str = Regex.Replace(actionExpression, @"(\.When\()[.\r|\n|\t|\s]*?(?=(function))", ".When(\"", RegexOptions.IgnoreCase); + str = Regex.Replace(str, @"(\.Skip\()[.\r|\n|\t|\s]*?(?=(function))", ".Skip(\"", RegexOptions.IgnoreCase); + str = Regex.Replace(str, @"(})[.\r|\n|\t|\s]*?(?=(\)))", "}\"", RegexOptions.IgnoreCase); + Context.Add("expression", str ?? "1 == 1"); + } + + public SchedulerRuleWorkflow(string workflowName, string ruleName, string expression, string ruleActionName, Dictionary context) + { + WorkflowName = workflowName; + RuleName = ruleName; + Expression = expression; + RuleActionName = ruleActionName; + Context = context; + } + public string WorkflowName { get; set; } + + public string RuleName { get; set; } + + + public string Expression { get; set; } + + public string RuleActionName { get; set; } + + public new Dictionary Context { get; set; } + + public Workflow GetWorkflow() + { + var result = new Workflow + { + WorkflowName = WorkflowName, + + Rules = new List{ + new Rule{ + RuleName =RuleName, + Expression = Expression, + Actions = new RuleActions{ + OnSuccess = new ActionInfo{ + Name = RuleActionName, + Context =Context + } + } + } + } + }; + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/BackgroundServiceBehavior.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/BackgroundServiceBehavior.cs new file mode 100644 index 000000000..93e2e7194 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/BackgroundServiceBehavior.cs @@ -0,0 +1,156 @@ +using Autofac; +using Surging.Core.CPlatform.EventBus.Events; +using Surging.Core.CPlatform.EventBus.Implementation; +using Surging.Core.CPlatform.Ioc; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.ProxyGenerator; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.ServiceHosting.Extensions.Runtime +{ + public abstract class BackgroundServiceBehavior : IServiceBehavior, IDisposable + { + private ServerReceivedDelegate received; + public event ServerReceivedDelegate Received + { + add + { + if (received == null) + { + received += value; + } + } + remove + { + received -= value; + } + } + + public string MessageId { get; } = Guid.NewGuid().ToString("N"); + public async Task Write(object result, int statusCode = 200, string exceptionMessage = "") + { + if (received == null) + return; + var message = new TransportMessage(MessageId, new ReactiveResultMessage + { + ExceptionMessage = exceptionMessage, + StatusCode = statusCode, + Result = result + + }); + await received(message); + } + private Task _executingTask; + private CancellationTokenSource _stoppingCts = new CancellationTokenSource(); + + public T CreateProxy(string key) where T : class + { + return ServiceLocator.GetService().CreateProxy(key); + } + + public object CreateProxy(Type type) + { + return ServiceLocator.GetService().CreateProxy(type); + } + + public object CreateProxy(string key, Type type) + { + return ServiceLocator.GetService().CreateProxy(key, type); + } + + public T CreateProxy() where T : class + { + return ServiceLocator.GetService().CreateProxy(); + } + + public T GetService(string key) where T : class + { + if (ServiceLocator.Current.IsRegisteredWithKey(key)) + return ServiceLocator.GetService(key); + else + return ServiceLocator.GetService().CreateProxy(key); + } + + public T GetService() where T : class + { + if (ServiceLocator.Current.IsRegistered()) + return ServiceLocator.GetService(); + else + return ServiceLocator.GetService().CreateProxy(); + + } + + public object GetService(Type type) + { + if (ServiceLocator.Current.IsRegistered(type)) + return ServiceLocator.GetService(type); + else + return ServiceLocator.GetService().CreateProxy(type); + } + + public object GetService(string key, Type type) + { + if (ServiceLocator.Current.IsRegisteredWithKey(key, type)) + return ServiceLocator.GetService(key, type); + else + return ServiceLocator.GetService().CreateProxy(key, type); + + } + + public void Publish(IntegrationEvent @event) + { + GetService().Publish(@event); + } + + protected abstract Task ExecuteAsync(CancellationToken stoppingToken); + + public virtual Task StartAsync(CancellationToken cancellationToken) + { + _stoppingCts = new CancellationTokenSource(); + _executingTask = ExecutingAsync(_stoppingCts.Token); + + if (_executingTask.IsCompleted) + { + return _executingTask; + } + + return Task.CompletedTask; + } + + public virtual async Task StopAsync(CancellationToken cancellationToken) + { + if (_executingTask == null) + { + return; + } + + try + { + _stoppingCts.Cancel(); + } + finally + { + await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); + } + + } + + public virtual void Dispose() + { + _stoppingCts.Cancel(); + } + + private async Task ExecutingAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + await ExecuteAsync(stoppingToken); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/BackgroundServiceEntry.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/BackgroundServiceEntry.cs new file mode 100644 index 000000000..096595b42 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/BackgroundServiceEntry.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ServiceHosting.Extensions.Runtime +{ + public class BackgroundServiceEntry + { + public string Path { get; set; } + + public Type Type { get; set; } + + public BackgroundServiceBehavior Behavior { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/IBackgroundServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/IBackgroundServiceEntryProvider.cs new file mode 100644 index 000000000..b4ac9d1e2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/IBackgroundServiceEntryProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.ServiceHosting.Extensions.Runtime +{ + public interface IBackgroundServiceEntryProvider + { + IEnumerable GetEntries(); + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/Implementation/DefaultBackgroundServiceEntryProvider.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/Implementation/DefaultBackgroundServiceEntryProvider.cs new file mode 100644 index 000000000..89a914d6e --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Runtime/Implementation/DefaultBackgroundServiceEntryProvider.cs @@ -0,0 +1,82 @@ +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Routing.Template; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Surging.Core.ServiceHosting.Extensions.Runtime.Implementation +{ + public class DefaultBackgroundServiceEntryProvider: IBackgroundServiceEntryProvider + { + #region Field + private readonly IEnumerable _types; + private readonly ILogger _logger; + private readonly CPlatformContainer _serviceProvider; + private List _backgroundServiceEntries; + + #endregion Field + + #region Constructor + + public DefaultBackgroundServiceEntryProvider(IServiceEntryProvider serviceEntryProvider, + ILogger logger, + CPlatformContainer serviceProvider) + { + _types = serviceEntryProvider.GetTypes(); + _logger = logger; + _serviceProvider = serviceProvider; + } + + #endregion Constructor + + #region Implementation of IUdpServiceEntryProvider + + + public IEnumerable GetEntries() + { + var services = _types.ToArray(); + if (_backgroundServiceEntries == null) + { + _backgroundServiceEntries = new List(); + foreach (var service in services) + { + var entry = CreateServiceEntry(service); + if (entry != null) + { + _backgroundServiceEntries.Add(entry); + } + } + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug($"发现了以下后台托管服务:{string.Join(",", _backgroundServiceEntries.Select(i => i.Type.FullName))}。"); + } + } + return _backgroundServiceEntries; + } + + + public BackgroundServiceEntry CreateServiceEntry(Type service) + { + BackgroundServiceEntry result = null; + var routeTemplate = service.GetCustomAttribute(); + var objInstance = _serviceProvider.GetInstances(service); + var behavior = objInstance as BackgroundServiceBehavior; + var path = RoutePatternParser.Parse(routeTemplate.RouteTemplate, service.Name); + if (path.Length > 0 && path[0] != '/') + path = $"/{path}"; + if (behavior != null) + result = new BackgroundServiceEntry + { + Behavior = behavior, + Type = behavior.GetType(), + Path = path, + }; + return result; + } + #endregion + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/ServiceHostModule.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/ServiceHostModule.cs new file mode 100644 index 000000000..8b6fbbffa --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/ServiceHostModule.cs @@ -0,0 +1,56 @@ +using Autofac; +using Microsoft.Extensions.Logging; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Engines; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.ServiceHosting.Extensions.Runtime; +using Surging.Core.ServiceHosting.Extensions.Runtime.Implementation; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Surging.Core.ServiceHosting.Extensions +{ + public class ServiceHostModule : EnginePartModule + { + public override void Initialize(AppModuleContext context) + { + var serviceProvider = context.ServiceProvoider; + base.Initialize(context); + serviceProvider.GetInstances().ServiceEngineStarted.Register(() => + { + var provider = serviceProvider.GetInstances(); + var entries = provider.GetEntries(); + foreach(var entry in entries) + { + var cts = new CancellationTokenSource(); + Task.Run(() => + { + try + { + entry.Behavior.StartAsync(cts.Token); + } + catch + { + entry.Behavior.StopAsync(cts.Token); + } + }); + } + }); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + base.RegisterBuilder(builder); + builder.Register(provider => + { + return new DefaultBackgroundServiceEntryProvider( + provider.Resolve(), + provider.Resolve>(), + provider.Resolve() + ); + }).As(typeof(IBackgroundServiceEntryProvider)).SingleInstance(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Surging.Core.ServiceHosting.Extensions.csproj b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Surging.Core.ServiceHosting.Extensions.csproj new file mode 100644 index 000000000..620f917ba --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Surging.Core.ServiceHosting.Extensions.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Utils/DateUtils.cs b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Utils/DateUtils.cs new file mode 100644 index 000000000..4628e5280 --- /dev/null +++ b/src/Surging.Core/Surging.Core.ServiceHosting.Extensions/Utils/DateUtils.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.ServiceHosting.Extensions.Utils +{ + public class DateUtils + { + private readonly TimeSpan _OneMinute = new TimeSpan(0, 1, 0); + private readonly TimeSpan _TwoMinutes = new TimeSpan(0, 2, 0); + private readonly TimeSpan _OneHour = new TimeSpan(1, 0, 0); + private readonly TimeSpan _TwoHours = new TimeSpan(2, 0, 0); + private readonly TimeSpan _OneDay = new TimeSpan(1, 0, 0, 0); + private readonly TimeSpan _TwoDays = new TimeSpan(2, 0, 0, 0); + private readonly TimeSpan _OneWeek = new TimeSpan(7, 0, 0, 0); + private readonly TimeSpan _TwoWeeks = new TimeSpan(14, 0, 0, 0); + private readonly TimeSpan _OneMonth = new TimeSpan(31, 0, 0, 0); + private readonly TimeSpan _TwoMonths = new TimeSpan(62, 0, 0, 0); + private readonly TimeSpan _OneYear = new TimeSpan(365, 0, 0, 0); + private readonly TimeSpan _TwoYears = new TimeSpan(730, 0, 0, 0); + public TimeSpan GetTimeSpan(DateTime startTime, DateTime endTime) + { + return endTime - startTime; + } + public string ToDateTime(DateTime time) + { + return time.ToString("yyyy-MM-dd HH:mm:ss"); + } + public string ToDateTimeF(DateTime time) + { + return time.ToString("yyyy-MM-dd HH:mm:ss:fffffff"); + } + public int CalculateAge(DateTime dateOfBirth) + { + return CalculateAge(dateOfBirth, DateTime.Today); + } + public int CalculateAge(DateTime dateOfBirth, DateTime referenceDate) + { + int years = referenceDate.Year - dateOfBirth.Year; + if (referenceDate.Month < dateOfBirth.Month || (referenceDate.Month == dateOfBirth.Month && referenceDate.Day < dateOfBirth.Day)) --years; + return years; + } + public int GetCountDaysOfMonth(DateTime date) + { + var nextMonth = date.AddMonths(1); + return new DateTime(nextMonth.Year, nextMonth.Month, 1).AddDays(-1).Day; + } + public DateTime GetFirstDayOfMonth(DateTime date) + { + return new DateTime(date.Year, date.Month, 1); + } + public DateTime GetFirstDayOfMonth(DateTime date, DayOfWeek dayOfWeek) + { + var dt = GetFirstDayOfMonth(date); + while (dt.DayOfWeek != dayOfWeek) + { + dt = dt.AddDays(1); + } + return dt; + } + public DateTime GetLastDayOfMonth(DateTime date) + { + return new DateTime(date.Year, date.Month, GetCountDaysOfMonth(date)); + } + public DateTime GetLastDayOfMonth(DateTime date, DayOfWeek dayOfWeek) + { + var dt = GetLastDayOfMonth(date); + while (dt.DayOfWeek != dayOfWeek) + { + dt = dt.AddDays(-1); + } + return dt; + } + public bool IsToday(DateTime dt) + { + return (dt.Date == DateTime.Today); + } + public bool IsToday(DateTimeOffset dto) + { + return IsToday(dto.Date); + } + public DateTime SetTime(DateTime date, int hours, int minutes, int seconds) + { + return SetTime(date, new TimeSpan(hours, minutes, seconds)); + } + public DateTime SetTime(DateTime date, TimeSpan time) + { + return date.Date.Add(time); + } + public DateTimeOffset ToDateTimeOffset(DateTime localDateTime) + { + return ToDateTimeOffset(localDateTime, null); + } + public DateTimeOffset ToDateTimeOffset(DateTime localDateTime, TimeZoneInfo localTimeZone) + { + localTimeZone = (localTimeZone ?? TimeZoneInfo.Local); + + if (localDateTime.Kind != DateTimeKind.Unspecified) + { + localDateTime = new DateTime(localDateTime.Ticks, DateTimeKind.Unspecified); + } + + return TimeZoneInfo.ConvertTimeToUtc(localDateTime, localTimeZone); + } + public DateTime GetFirstDayOfWeek(DateTime date) + { + return GetFirstDayOfWeek(date, null); + } + public DateTime GetFirstDayOfWeek(DateTime date, CultureInfo cultureInfo) + { + cultureInfo = (cultureInfo ?? CultureInfo.CurrentCulture); + + var firstDayOfWeek = cultureInfo.DateTimeFormat.FirstDayOfWeek; + while (date.DayOfWeek != firstDayOfWeek) date = date.AddDays(-1); + + return date; + } + public DateTime GetLastDayOfWeek(DateTime date) + { + return GetLastDayOfWeek(date, null); + } + public DateTime GetLastDayOfWeek(DateTime date, CultureInfo cultureInfo) + { + return GetFirstDayOfWeek(date, cultureInfo).AddDays(6); + } + public DateTime GetWeekday(DateTime date, DayOfWeek weekday) + { + return GetWeekday(date, weekday, null); + } + public DateTime GetWeekday(DateTime date, DayOfWeek weekday, CultureInfo cultureInfo) + { + var firstDayOfWeek = GetFirstDayOfWeek(date, cultureInfo); + return GetNextWeekday(firstDayOfWeek, weekday); + } + public static DateTime GetNextWeekday(DateTime date, DayOfWeek weekday) + { + while (date.DayOfWeek != weekday) date = date.AddDays(1); + return date; + } + public DateTime GetPreviousWeekday(DateTime date, DayOfWeek weekday) + { + while (date.DayOfWeek != weekday) date = date.AddDays(-1); + return date; + } + + public DateTimeOffset SetTime(DateTimeOffset date, int hours, int minutes, int seconds) + { + return SetTime(date, new TimeSpan(hours, minutes, seconds)); + } + public DateTimeOffset SetTime(DateTimeOffset date, TimeSpan time) + { + return SetTime(date, time, null); + } + public DateTimeOffset SetTime(DateTimeOffset date, TimeSpan time, TimeZoneInfo localTimeZone) + { + var localDate = ToLocalDateTime(date, localTimeZone); + SetTime(localDate, time); + return ToDateTimeOffset(localDate, localTimeZone); + } + public DateTime ToLocalDateTime(DateTimeOffset dateTimeUtc) + { + return ToLocalDateTime(dateTimeUtc, null); + } + + + public DateTime ToLocalDateTime(DateTimeOffset dateTimeUtc, TimeZoneInfo localTimeZone) + { + localTimeZone = (localTimeZone ?? TimeZoneInfo.Local); + return TimeZoneInfo.ConvertTime(dateTimeUtc, localTimeZone).DateTime; + } + + + + public static int WeekOfYear(DateTime datetime) + { + System.Globalization.DateTimeFormatInfo dateinf = new System.Globalization.DateTimeFormatInfo(); + System.Globalization.CalendarWeekRule weekrule = dateinf.CalendarWeekRule; + DayOfWeek firstDayOfWeek = dateinf.FirstDayOfWeek; + System.Globalization.CultureInfo ciCurr = System.Globalization.CultureInfo.CurrentCulture; + return ciCurr.Calendar.GetWeekOfYear(datetime, weekrule, firstDayOfWeek); + } + + public bool IsWeekDay(DateTime date) + { + return !IsWeekend(date); + } + public bool IsWeekend(DateTime value) + { + return value.DayOfWeek == DayOfWeek.Sunday || value.DayOfWeek == DayOfWeek.Saturday; + } + + } +} diff --git a/src/Surging.Core/Surging.Core.ServiceHosting/Internal/Implementation/ConsoleLifetime.cs b/src/Surging.Core/Surging.Core.ServiceHosting/Internal/Implementation/ConsoleLifetime.cs index 2360fbb96..030dca744 100644 --- a/src/Surging.Core/Surging.Core.ServiceHosting/Internal/Implementation/ConsoleLifetime.cs +++ b/src/Surging.Core/Surging.Core.ServiceHosting/Internal/Implementation/ConsoleLifetime.cs @@ -6,11 +6,14 @@ namespace Surging.Core.ServiceHosting.Internal.Implementation { - public class ConsoleLifetime: IHostLifetime + /// + /// 服务端用来阻止Host主线程退出,直到按下Ctrl+C + /// + public class ConsoleLifetime : IHostLifetime { private readonly ManualResetEvent _shutdownBlock = new ManualResetEvent(false); public ConsoleLifetime(IApplicationLifetime applicationLifetime) - { + { ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime)); } @@ -18,14 +21,16 @@ public Task WaitForStartAsync(CancellationToken cancellationToken) { ApplicationLifetime.ApplicationStarted.Register(() => { - Console.WriteLine("服务已启动。 按下Ctrl + C关闭。"); + Console.WriteLine("服务已启动。 按下Ctrl + C关闭。"); }); AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => { ApplicationLifetime.StopApplication(); + //阻止程序主线程自动退出,等待退出信号 _shutdownBlock.WaitOne(); }; + //按下Ctrl+C退出程序 Console.CancelKeyPress += (sender, e) => { e.Cancel = true; diff --git a/src/Surging.Core/Surging.Core.ServiceHosting/Surging.Core.ServiceHosting.csproj b/src/Surging.Core/Surging.Core.ServiceHosting/Surging.Core.ServiceHosting.csproj index e07fe529c..617392fe6 100644 --- a/src/Surging.Core/Surging.Core.ServiceHosting/Surging.Core.ServiceHosting.csproj +++ b/src/Surging.Core/Surging.Core.ServiceHosting/Surging.Core.ServiceHosting.csproj @@ -1,30 +1,30 @@ - + - netcoreapp2.1 + net6.0 Surging.Core.ServiceHosting Copyright © fanly All Rights Reserved. - 0.8.0.2 + 1.1.0.0 fanly surging Micro Service Framework - 1.Service host support multiple protocols -2.Exclude interface registration service + 1.multiple register center cluster +2. fix bug MicroService surging https://github.com/dotnetcore/surging/blob/master/LICENSE https://github.com/dotnetcore/surging surging is a distributed micro service framework that provides high-performance RPC remote service calls, using Zookeeper, Consul as the registration center for surging services, integrating hash, random, polling as a load balancing algorithm, RPC integration using the netty framework, Using asynchronous transmission. Use json.net, protobuf, messagepack for serialization Codec - 0.8.0.2 - 0.8.0.2 + 1.1.0.0 + 1.1.0.0 - - - - - - + + + + + + diff --git a/src/Surging.Core/Surging.Core.Stage/AppConfig.cs b/src/Surging.Core/Surging.Core.Stage/AppConfig.cs new file mode 100644 index 000000000..f3305d79a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/AppConfig.cs @@ -0,0 +1,12 @@ +using Surging.Core.Stage.Configurations; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage +{ + public class AppConfig + { + public static StageOption Options { get; internal set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Configurations/AccessPolicyOption.cs b/src/Surging.Core/Surging.Core.Stage/Configurations/AccessPolicyOption.cs new file mode 100644 index 000000000..3ce00c705 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Configurations/AccessPolicyOption.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage.Configurations +{ + public class AccessPolicyOption + { + public string[] Origins { get; set; } + + public bool AllowAnyHeader { get; set; } + + public bool AllowAnyMethod { get; set; } + + public bool AllowAnyOrigin { get; set; } + + public bool AllowCredentials { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Configurations/AccessSettingOption.cs b/src/Surging.Core/Surging.Core.Stage/Configurations/AccessSettingOption.cs new file mode 100644 index 000000000..90fdd5379 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Configurations/AccessSettingOption.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage.Configurations +{ + public class AccessSettingOption + { + public string WhiteList { get; set; } + + public string BlackList { get; set; } + + public string RoutePath { get; set; } + + public bool Enable { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Configurations/ApiGetwayOption.cs b/src/Surging.Core/Surging.Core.Stage/Configurations/ApiGetwayOption.cs new file mode 100644 index 000000000..873b47209 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Configurations/ApiGetwayOption.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage.Configurations +{ + public class ApiGetwayOption + { + public string CacheMode{get;set; } + + public string AuthorizationServiceKey { get; set; } + + public string AuthorizationRoutePath { get; set; } + + public int AccessTokenExpireTimeSpan { get; set; } = 30; + + public string TokenEndpointPath{ get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Configurations/DataRateOption.cs b/src/Surging.Core/Surging.Core.Stage/Configurations/DataRateOption.cs new file mode 100644 index 000000000..7f5eecc9e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Configurations/DataRateOption.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage.Configurations +{ + public class DataRateOption + { + public double BytesPerSecond { get; set; } + public TimeSpan GracePeriod { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Configurations/StageOption.cs b/src/Surging.Core/Surging.Core.Stage/Configurations/StageOption.cs new file mode 100644 index 000000000..fb0a663f2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Configurations/StageOption.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Server.Kestrel.Core; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage.Configurations +{ + public class StageOption + { + public bool EnableHttps { get; set; } + + public string CertificateFileName { get; set; } + + public string CertificateLocation { get; set; } + + public string CertificatePassword { get; set; } + + public string HttpsPort { get; set; } + + public bool IsCamelCaseResolver { get; set; } + + public ApiGetwayOption ApiGetWay { get; set; } + + public HttpProtocols Protocols { get; set; } = HttpProtocols.Http1AndHttp2; + + public DataRateOption MinRequestBodyDataRate { get; set; } + + public DataRateOption MinResponseDataRate { get; set; } + + public long? MaxRequestBodySize { get; set; } + + public long? MaxConcurrentConnections { get; set; } + + public long? MaxConcurrentUpgradedConnections { get; set; } + + public long? MaxRequestBufferSize { get; set; } + + public int MaxRequestHeaderCount { get; set; } = 100; + + public int MaxRequestHeadersTotalSize { get; set; } = 32768; + + public int MaxRequestLineSize { get; set; } = 8192; + + public long? MaxResponseBufferSize { get; set; } + + public AccessPolicyOption AccessPolicy { get; set; } + + public List AccessSetting { get; set; } + + public string HttpPorts { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Filters/ActionFilterAttribute.cs b/src/Surging.Core/Surging.Core.Stage/Filters/ActionFilterAttribute.cs new file mode 100644 index 000000000..1035012c8 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Filters/ActionFilterAttribute.cs @@ -0,0 +1,123 @@ +using Autofac; +using Microsoft.AspNetCore.Http; +using Surging.Core.ApiGateWay; +using Surging.Core.ApiGateWay.OAuth; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Filters.Implementation; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Stage.Filters +{ + public class ActionFilterAttribute : IActionFilter + { + private readonly IAuthorizationServerProvider _authorizationServerProvider; + public ActionFilterAttribute() + { + _authorizationServerProvider = ServiceLocator.Current.Resolve(); + } + + public Task OnActionExecuted(ActionExecutedContext filterContext) + { + return Task.CompletedTask; + } + + public async Task OnActionExecuting(ActionExecutingContext filterContext) + { + var gatewayAppConfig = AppConfig.Options.ApiGetWay; + if (filterContext.Message.RoutePath == gatewayAppConfig.AuthorizationRoutePath) + { + var token = await _authorizationServerProvider.GenerateTokenCredential(new Dictionary(filterContext.Message.Parameters)); + if (token != null) + { + filterContext.Result = HttpResultMessage.Create(true, token); + filterContext.Result.StatusCode = (int)ServiceStatusCode.Success; + } + else + { + filterContext.Result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + } + } + else if (filterContext.Route.ServiceDescriptor.AuthType() == AuthorizationType.AppSecret.ToString()) + { + if (!ValidateAppSecretAuthentication(filterContext, out HttpResultMessage result)) + { + filterContext.Result = result; + } + } + } + + private bool ValidateAppSecretAuthentication(ActionExecutingContext filterContext, out HttpResultMessage result) + { + bool isSuccess = true; + DateTime time; + result = HttpResultMessage.Create(true,null); + var author = filterContext.Context.Request.Headers["Authorization"]; + var model = filterContext.Message.Parameters; + var route = filterContext.Route; + if (model.ContainsKey("timeStamp") && author.Count > 0) + { + if (long.TryParse(model["timeStamp"].ToString(), out long timeStamp)) + { + time = DateTimeConverter.UnixTimestampToDateTime(timeStamp); + var seconds = (DateTime.Now - time).TotalSeconds; + if (seconds <= 3560 && seconds >= 0) + { + if (GetMD5($"{route.ServiceDescriptor.Token}{time.ToString("yyyy-MM-dd hh:mm:ss") }") != author.ToString()) + { + result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + isSuccess = false; + } + } + else + { + result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + isSuccess = false; + } + } + else + { + result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + isSuccess = false; + } + } + else + { + result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; + isSuccess = false; + } + return isSuccess; + } + + public string GetMD5(string encypStr) + { + try + { + var md5 = MD5.Create(); + var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(encypStr)); + var sb = new StringBuilder(); + foreach (byte b in bs) + { + sb.Append(b.ToString("X2")); + } + return sb.ToString().ToLower(); + } + catch (Exception e) + { + Console.Error.WriteLine(e.StackTrace); + return null; + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Filters/AuthorizationFilterAttribute.cs b/src/Surging.Core/Surging.Core.Stage/Filters/AuthorizationFilterAttribute.cs new file mode 100644 index 000000000..26ad7e267 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Filters/AuthorizationFilterAttribute.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Authorization; +using Surging.Core.ApiGateWay; +using Surging.Core.ApiGateWay.OAuth; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.DependencyResolution; +using Surging.Core.CPlatform.Filters.Implementation; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.CPlatform.Utilities; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using System.Threading.Tasks; +using Autofac; +using System; +using Surging.Core.KestrelHttpServer.Internal; + +namespace Surging.Core.Stage.Filters +{ + public class AuthorizationFilterAttribute : IAuthorizationFilter + { + private readonly IAuthorizationServerProvider _authorizationServerProvider; + public AuthorizationFilterAttribute() + { + _authorizationServerProvider = ServiceLocator.Current.Resolve(); + } + public async Task OnAuthorization(AuthorizationFilterContext filterContext) + { + var gatewayAppConfig = AppConfig.Options.ApiGetWay; + if (filterContext.Route != null && filterContext.Route.ServiceDescriptor.DisableNetwork()) + filterContext.Result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.RequestError, Message = "Request error" }; + else + { + if (filterContext.Route != null && filterContext.Route.ServiceDescriptor.EnableAuthorization()) + { + if (filterContext.Route.ServiceDescriptor.AuthType() == AuthorizationType.JWT.ToString()) + { + var author = filterContext.Context.Request.Headers["Authorization"]; + if (author.Count > 0) + { + var isSuccess = await _authorizationServerProvider.ValidateClientAuthentication(author); + if (!isSuccess) + { + filterContext.Result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + } + else + { + var payload = _authorizationServerProvider.GetPayloadString(author); + RestContext.GetContext().SetAttachment("payload", payload); + } + } + else + filterContext.Result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Invalid authentication credentials" }; + + } + } + } + + if (String.Compare(filterContext.Path.ToLower(), gatewayAppConfig.TokenEndpointPath, true) == 0) + filterContext.Context.Items.Add("path", gatewayAppConfig.AuthorizationRoutePath); + + } + } +} + diff --git a/src/Surging.Core/Surging.Core.Stage/Filters/IPFilterAttribute.cs b/src/Surging.Core/Surging.Core.Stage/Filters/IPFilterAttribute.cs new file mode 100644 index 000000000..1cde840e6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Filters/IPFilterAttribute.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.Http; +using Surging.Core.ApiGateWay; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Transport.Implementation; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.KestrelHttpServer.Filters.Implementation; +using Surging.Core.KestrelHttpServer.Internal; +using Surging.Core.Stage.Internal; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Surging.Core.Stage.Filters +{ + public class IPFilterAttribute : IActionFilter + { + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IIPChecker _ipChecker; + public IPFilterAttribute(IHttpContextAccessor httpContextAccessor, IIPChecker ipChecker) + { + _httpContextAccessor = httpContextAccessor; + _ipChecker = ipChecker; + } + public Task OnActionExecuted(ActionExecutedContext filterContext) + { + return Task.CompletedTask; + } + + public Task OnActionExecuting(ActionExecutingContext filterContext) + { + var address = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress; + RestContext.GetContext().SetAttachment("RemoteIpAddress", address.ToString()); + if (_ipChecker.IsBlackIp(address,filterContext.Message.RoutePath)) + { + filterContext.Result = new HttpResultMessage { IsSucceed = false, StatusCode = (int)ServiceStatusCode.AuthorizationFailed, Message = "Your IP address is not allowed" }; + } + return Task.CompletedTask; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Internal/IIPChecker.cs b/src/Surging.Core/Surging.Core.Stage/Internal/IIPChecker.cs new file mode 100644 index 000000000..2f0ce487a --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Internal/IIPChecker.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Surging.Core.Stage.Internal +{ + public interface IIPChecker + { + bool IsBlackIp(IPAddress ip, string routePath); + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Internal/IWebServerListener.cs b/src/Surging.Core/Surging.Core.Stage/Internal/IWebServerListener.cs new file mode 100644 index 000000000..5c7826290 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Internal/IWebServerListener.cs @@ -0,0 +1,12 @@ +using Surging.Core.KestrelHttpServer; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Stage.Internal +{ + public interface IWebServerListener + { + void Listen(WebHostContext context); + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/IPAddressChecker.cs b/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/IPAddressChecker.cs new file mode 100644 index 000000000..9743085cb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/IPAddressChecker.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Net; +using System.Linq; + +namespace Surging.Core.Stage.Internal.Implementation +{ + public class IPAddressChecker : IIPChecker + { + private readonly ConcurrentDictionary, List>> _ipNetworkSegments = new ConcurrentDictionary, List>>(); + private readonly ConcurrentDictionary, List>> _ipAddresses = new ConcurrentDictionary, List>>(); + public IPAddressChecker() + { + Init(); + } + + public bool IsBlackIp(IPAddress ip,string routePath) + { + var result =false; + if (AppConfig.Options.AccessSetting != null) + { + var longIpAddress = IPToLong(ip); + var ipNetworkSegments = GetIPNetworkSegments(routePath); + var ipAddresses = GetIPAddresses(routePath); + result = ipNetworkSegments.Item1.Count > 0 && ipAddresses.Item1.Count > 0; + if (ipNetworkSegments.Item2.Count > 0|| ipAddresses.Item2.Count>0) + { + result = ipNetworkSegments.Item2.Any(p => p.LongFirstUsable >= longIpAddress && p.LongLastUsable <= longIpAddress); + if (!result) + result = ipAddresses.Item2.Any(p => p == ip.ToString()); + } + if (ipNetworkSegments.Item1.Count > 0 || ipAddresses.Item1.Count > 0) + { + result = !ipNetworkSegments.Item1.Any(p => p.LongFirstUsable >= longIpAddress && p.LongLastUsable <= longIpAddress); + if (result) + result = !ipAddresses.Item1.Any(p => p == ip.ToString()); + } + } + return result; + } + + public void Init() + { + var settings = AppConfig.Options.AccessSetting; + if (settings != null) + { + settings.ForEach(setting => + { + if (setting.Enable) + { + var whiteList = setting.WhiteList?.Split(","); + var blackList = setting.BlackList?.Split(","); + var whiteIPNetworkSegments = GetIPNetworkSegments(whiteList); + var blackIPNetworkSegments = GetIPNetworkSegments(blackList); + _ipNetworkSegments.TryAdd(setting.RoutePath ?? "", new ValueTuple, List>(whiteIPNetworkSegments, blackIPNetworkSegments)); + _ipAddresses.TryAdd(setting.RoutePath ?? "", new ValueTuple, List>(GetIPAddresses(whiteList), GetIPAddresses(blackList))); + } + } + ); + } + } + + private List GetIPNetworkSegments(IEnumerable ipAddresses) + { + var ipNetworkSegments = new List(); + if (ipAddresses != null) + { + var addresses = ipAddresses.Where(p => p.AsSpan().IndexOf("/") > 0); + foreach (var ipAddress in addresses) + { + IPNetwork ipnetwork = IPNetwork.Parse(ipAddress); + var ipNetworkSegment = new IPNetworkSegment + { + Cidr = ipnetwork.Cidr, + FirstUsable = ipnetwork.FirstUsable, + LastUsable = ipnetwork.LastUsable, + LongFirstUsable = IPToLong(ipnetwork.FirstUsable), + LongLastUsable = IPToLong(ipnetwork.LastUsable), + }; + ipNetworkSegments.Add(ipNetworkSegment); + } + } + return ipNetworkSegments; + } + + private (List,List) GetIPNetworkSegments(string routePath) + { + var whiteIPNetworkSegments = new List(); + var blackIPNetworkSegments = new List(); + var valueTuple = _ipNetworkSegments.GetValueOrDefault(routePath); + if (valueTuple == (null, null)) + { + var keys = _ipNetworkSegments.Keys.Where(p => routePath.Contains(p)); + foreach (var key in keys) + { + whiteIPNetworkSegments.AddRange(_ipNetworkSegments[key].Item1); + blackIPNetworkSegments.AddRange(_ipNetworkSegments[key].Item2); + } + _ipNetworkSegments.AddOrUpdate(routePath, + new ValueTuple, + List>(whiteIPNetworkSegments, blackIPNetworkSegments), + (key, value) => new ValueTuple, List>(whiteIPNetworkSegments, blackIPNetworkSegments)); + } + else + { + whiteIPNetworkSegments = valueTuple.Item1; + blackIPNetworkSegments = valueTuple.Item2; + } + return (whiteIPNetworkSegments, blackIPNetworkSegments); + } + + private (List,List) GetIPAddresses(string routePath) + { + var whiteIPAddresses = new List(); + var blackIPAddresses = new List(); + var valueTuple = _ipAddresses.GetValueOrDefault(routePath); + if (valueTuple == (null, null)) + { + var keys = _ipAddresses.Keys.Where(p => routePath.Contains(p)); + foreach (var key in keys) + { + whiteIPAddresses.AddRange(_ipAddresses[key].Item1); + blackIPAddresses.AddRange(_ipAddresses[key].Item2); + } + _ipAddresses.AddOrUpdate(routePath, + new ValueTuple, + List>(whiteIPAddresses, blackIPAddresses), + (key, value) => new ValueTuple, List>(whiteIPAddresses, blackIPAddresses)); + } + else + { + whiteIPAddresses = valueTuple.Item1; + blackIPAddresses = valueTuple.Item2; + } + return (whiteIPAddresses, blackIPAddresses); + } + + private List GetIPAddresses(IEnumerable ipAddresses) + { + var result = new List(); + if (ipAddresses != null) + result = ipAddresses.Where(p => p.AsSpan().IndexOf("/") < 0).ToList(); + return result; + } + + private long IPToLong(IPAddress ip) + { + long result = 0; + byte[] ipAdds = ip.GetAddressBytes(); + foreach (byte b in ipAdds) + { + result <<= 8; + result |= b & (uint)0xff; + } + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/IPNetworkSegment.cs b/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/IPNetworkSegment.cs new file mode 100644 index 000000000..47822c1af --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/IPNetworkSegment.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Surging.Core.Stage.Internal.Implementation +{ + public class IPNetworkSegment + { + public IPAddress LastUsable { get; set; } + public long LongLastUsable { get; set; } + public byte Cidr { get; set; } + public IPAddress FirstUsable { get; set; } + public long LongFirstUsable { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/WebServerListener.cs b/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/WebServerListener.cs new file mode 100644 index 000000000..54c50380b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Internal/Implementation/WebServerListener.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using System.Linq; +using Microsoft.AspNetCore.Hosting; +using Surging.Core.KestrelHttpServer; +using System.IO; +using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Server.Kestrel.Core; + +namespace Surging.Core.Stage.Internal.Implementation +{ + public class WebServerListener : IWebServerListener + { + private readonly ILogger _logger; + public WebServerListener(ILogger logger) + { + _logger = logger; + } + + void IWebServerListener.Listen(WebHostContext context) + { + + var httpsPorts = AppConfig.Options.HttpsPort?.Split(",") ?? new string[] { "443" }; + var httpPorts = AppConfig.Options.HttpPorts?.Split(","); + if (AppConfig.Options.EnableHttps) + { + foreach (var httpsPort in httpsPorts) + { + int.TryParse(httpsPort, out int port); + if (string.IsNullOrEmpty(AppConfig.Options.HttpsPort)) port = 443; + if (port > 0) + { + context.KestrelOptions.Listen(context.Address, port, listOptions => + { + X509Certificate2 certificate2 = null; + listOptions.Protocols = AppConfig.Options.Protocols; + var fileName = AppConfig.Options.CertificateFileName; + var password = AppConfig.Options.CertificatePassword; + if (fileName != null && password != null) + { + var pfxFile = Path.Combine(AppContext.BaseDirectory, AppConfig.Options.CertificateFileName); + if (File.Exists(pfxFile)) + certificate2 = new X509Certificate2(pfxFile, AppConfig.Options.CertificatePassword); + else + { + var paths = GetPaths(AppConfig.Options.CertificateLocation); + foreach (var path in paths) + { + pfxFile = Path.Combine(path, AppConfig.Options.CertificateFileName); + if (File.Exists(pfxFile)) + certificate2 = new X509Certificate2(pfxFile, AppConfig.Options.CertificatePassword); + + } + } + } + listOptions = certificate2 == null ? listOptions.UseHttps() : listOptions.UseHttps(certificate2); + }); + } + } + } + + if (httpPorts != null) + { + foreach (var httpPort in httpPorts) + { + int.TryParse(httpPort, out int port); + if (port > 0) + context.KestrelOptions.Listen(context.Address, port); + } + } + SetKestrelOptions(context); + } + + private string[] GetPaths(params string[] virtualPaths) + { + var result = new List(); + string rootPath = string.IsNullOrEmpty(CPlatform.AppConfig.ServerOptions.RootPath) ? + AppContext.BaseDirectory : CPlatform.AppConfig.ServerOptions.RootPath; + foreach (var virtualPath in virtualPaths) + { + var path = Path.Combine(rootPath, virtualPath); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"准备查找路径{path}下的证书。"); + if (Directory.Exists(path)) + { + var dirs = Directory.GetDirectories(path); + result.AddRange(dirs.Select(dir => Path.Combine(rootPath,virtualPath, new DirectoryInfo(dir).Name))); + } + else + { + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug($"未找到路径:{path}。"); + } + } + return result.ToArray(); + } + + private void SetKestrelOptions(WebHostContext context) + { + var requestBodyDataRate = AppConfig.Options.MinRequestBodyDataRate; + var responseBodyDataRate = AppConfig.Options.MinResponseDataRate; + context.KestrelOptions.Limits.MinRequestBodyDataRate = requestBodyDataRate == null ? null : new MinDataRate(requestBodyDataRate.BytesPerSecond, requestBodyDataRate.GracePeriod); + context.KestrelOptions.Limits.MinResponseDataRate = responseBodyDataRate == null ? null : new MinDataRate(responseBodyDataRate.BytesPerSecond, responseBodyDataRate.GracePeriod); + context.KestrelOptions.Limits.MaxConcurrentConnections = AppConfig.Options.MaxConcurrentConnections; + context.KestrelOptions.Limits.MaxConcurrentUpgradedConnections = AppConfig.Options.MaxConcurrentUpgradedConnections; + context.KestrelOptions.Limits.MaxRequestBodySize = AppConfig.Options.MaxRequestBodySize; + context.KestrelOptions.Limits.MaxRequestBufferSize = AppConfig.Options.MaxRequestBufferSize; + context.KestrelOptions.Limits.MaxRequestHeaderCount = AppConfig.Options.MaxRequestHeaderCount; + context.KestrelOptions.Limits.MaxRequestHeadersTotalSize = AppConfig.Options.MaxRequestHeadersTotalSize; + context.KestrelOptions.Limits.MaxRequestLineSize = AppConfig.Options.MaxRequestLineSize; + context.KestrelOptions.Limits.MaxResponseBufferSize = AppConfig.Options.MaxResponseBufferSize; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/StageModule.cs b/src/Surging.Core/Surging.Core.Stage/StageModule.cs new file mode 100644 index 000000000..4647565bf --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/StageModule.cs @@ -0,0 +1,116 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Surging.Core.CPlatform.Module; +using Surging.Core.KestrelHttpServer; +using Surging.Core.KestrelHttpServer.Extensions; +using Surging.Core.KestrelHttpServer.Filters; +using Surging.Core.KestrelHttpServer.Internal; +using Surging.Core.Stage.Configurations; +using Surging.Core.Stage.Filters; +using Surging.Core.Stage.Internal; +using Surging.Core.Stage.Internal.Implementation; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Text.Json; + +namespace Surging.Core.Stage +{ + public class StageModule : KestrelHttpModule + { + private IWebServerListener _listener; + public override void Initialize(AppModuleContext context) + { + _listener = context.ServiceProvoider.GetInstances(); + } + + public override void RegisterBuilder(WebHostContext context) + { + _listener.Listen(context); + } + + public override void Initialize(ApplicationInitializationContext context) + { + var policy = AppConfig.Options.AccessPolicy; + if (policy != null) + { + context.Builder.UseCors(builder => + { + if(policy.Origins!=null) + builder.WithOrigins(policy.Origins); + if (policy.AllowAnyHeader) + builder.AllowAnyHeader(); + if (policy.AllowAnyMethod) + builder.AllowAnyMethod(); + if (policy.AllowAnyOrigin) + builder.AllowAnyOrigin(); + if (policy.AllowCredentials) + builder.AllowCredentials(); + }); + } + } + + public override void RegisterBuilder(ConfigurationContext context) + { + var apiConfig = AppConfig.Options.ApiGetWay; + if (apiConfig != null) + { + ApiGateWay.AppConfig.CacheMode = apiConfig.CacheMode; + ApiGateWay.AppConfig.AuthorizationServiceKey = apiConfig.AuthorizationServiceKey; + ApiGateWay.AppConfig.AccessTokenExpireTimeSpan =TimeSpan.FromMinutes(apiConfig.AccessTokenExpireTimeSpan); + ApiGateWay.AppConfig.AuthorizationRoutePath = apiConfig.AuthorizationRoutePath; + ApiGateWay.AppConfig.TokenEndpointPath = apiConfig.TokenEndpointPath; + } + context.Services.AddMvc().AddJsonOptions(options => { + options.JsonSerializerOptions.Converters.Add(new DateTimeConverter()); + options.JsonSerializerOptions.Converters.Add(new DateTimeNullConverter()); + if (AppConfig.Options.IsCamelCaseResolver) + { + JsonConvert.DefaultSettings= new Func(() => + { + JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings(); + setting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + setting.ContractResolver = new CamelCasePropertyNamesContractResolver(); + return setting; + }); + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + } + else + { + JsonConvert.DefaultSettings = new Func(() => + { + JsonSerializerSettings setting = new JsonSerializerSettings(); + setting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + setting.ContractResolver= new DefaultContractResolver(); + return setting; + }); + options.JsonSerializerOptions.PropertyNamingPolicy = null; + } + }); + + context.Services.AddSingleton(); + context.Services.AddFilters(typeof(AuthorizationFilterAttribute)); + context.Services.AddFilters(typeof(ActionFilterAttribute)); + context.Services.AddFilters(typeof(IPFilterAttribute)); + } + + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + CPlatform.AppConfig.ServerOptions.DisableServiceRegistration = true; + var section = CPlatform.AppConfig.GetSection("Stage"); + if (section.Exists()) + { + AppConfig.Options = section.Get(); + } + + builder.RegisterType().As().SingleInstance(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Stage/Surging.Core.Stage.csproj b/src/Surging.Core/Surging.Core.Stage/Surging.Core.Stage.csproj new file mode 100644 index 000000000..5ee7869d3 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Stage/Surging.Core.Stage.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger/AppConfig.cs b/src/Surging.Core/Surging.Core.Swagger/AppConfig.cs new file mode 100644 index 000000000..6d0c759a7 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/AppConfig.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Swagger +{ + public class AppConfig + { + public static Info SwaggerOptions + { + get; internal set; + } + + public static DocumentConfiguration SwaggerConfig + { + get; internal set; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Internal/DefaultServiceSchemaProvider.cs b/src/Surging.Core/Surging.Core.Swagger/Internal/DefaultServiceSchemaProvider.cs new file mode 100644 index 000000000..d62355b3e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Internal/DefaultServiceSchemaProvider.cs @@ -0,0 +1,36 @@ +using Surging.Core.CPlatform.Engines; +using Surging.Core.CPlatform.Runtime.Server; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Surging.Core.Swagger.Internal +{ + public class DefaultServiceSchemaProvider : IServiceSchemaProvider + { + private readonly IServiceEntryProvider _serviceEntryProvider; + + public DefaultServiceSchemaProvider( IServiceEntryProvider serviceEntryProvider) + { + _serviceEntryProvider = serviceEntryProvider; + } + + public IEnumerable GetSchemaFilesPath() + { + var result = new List(); + var assemblieFiles = _serviceEntryProvider.GetALLEntries() + .Select(p => p.Type.Assembly.Location).Distinct(); + + foreach (var assemblieFile in assemblieFiles) + { + var fileSpan = assemblieFile.AsSpan(); + var path = $"{fileSpan.Slice(0, fileSpan.LastIndexOf(".")).ToString()}.xml"; + if (File.Exists(path)) + result.Add(path); + } + return result; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Internal/IServiceSchemaProvider.cs b/src/Surging.Core/Surging.Core.Swagger/Internal/IServiceSchemaProvider.cs new file mode 100644 index 000000000..997c888db --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Internal/IServiceSchemaProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Surging.Core.Swagger.Internal +{ + public interface IServiceSchemaProvider + { + IEnumerable GetSchemaFilesPath(); + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Surging.Core.Swagger.csproj b/src/Surging.Core/Surging.Core.Swagger/Surging.Core.Swagger.csproj new file mode 100644 index 000000000..026c3ea68 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Surging.Core.Swagger.csproj @@ -0,0 +1,59 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerBuilderExtensions.cs new file mode 100644 index 000000000..53bd50688 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerBuilderExtensions.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.AspNetCore.Builder; + +namespace Surging.Core.Swagger.Builder +{ + public static class SwaggerBuilderExtensions + { + public static IApplicationBuilder UseSwagger( + this IApplicationBuilder app, + Action setupAction = null) + { + if (setupAction == null) + { + // Don't pass options so it can be configured/injected via DI container instead + app.UseMiddleware(); + } + else + { + // Configure an options instance here and pass directly to the middleware + var options = new SwaggerOptions(); + setupAction.Invoke(options); + + app.UseMiddleware(options); + } + + return app; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerContractResolver.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerContractResolver.cs new file mode 100644 index 000000000..9f129e29e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerContractResolver.cs @@ -0,0 +1,50 @@ +using System; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Surging.Core.Swagger +{ + public class SwaggerContractResolver : DefaultContractResolver + { + private readonly JsonConverter _applicationTypeConverter; + + public SwaggerContractResolver(JsonSerializerSettings applicationSerializerSettings) + { + NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = false }; + _applicationTypeConverter = new ApplicationTypeConverter(applicationSerializerSettings); + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var jsonProperty = base.CreateProperty(member, memberSerialization); + + if (member.Name == "Example" || member.Name == "Examples" || member.Name == "Default") + jsonProperty.Converter = _applicationTypeConverter; + + return jsonProperty; + } + + private class ApplicationTypeConverter : JsonConverter + { + private JsonSerializer _applicationTypeSerializer; + + public ApplicationTypeConverter(JsonSerializerSettings applicationSerializerSettings) + { + _applicationTypeSerializer = JsonSerializer.Create(applicationSerializerSettings); + } + + public override bool CanConvert(Type objectType) { return true; } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + _applicationTypeSerializer.Serialize(writer, value); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerMiddleware.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerMiddleware.cs new file mode 100644 index 000000000..9ecc0af8e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerMiddleware.cs @@ -0,0 +1,98 @@ +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Template; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; + +namespace Surging.Core.Swagger +{ + public class SwaggerMiddleware + { + private readonly RequestDelegate _next; + private readonly JsonSerializer _swaggerSerializer; + private readonly SwaggerOptions _options; + private readonly TemplateMatcher _requestMatcher; + + public SwaggerMiddleware( + RequestDelegate next, + IOptions mvcJsonOptionsAccessor, + IOptions optionsAccessor) + : this(next, mvcJsonOptionsAccessor, optionsAccessor.Value) + { } + + public SwaggerMiddleware( + RequestDelegate next, + IOptions mvcJsonOptions, + SwaggerOptions options) + { + _next = next; + _swaggerSerializer = SwaggerSerializerFactory.Create(mvcJsonOptions); + _options = options ?? new SwaggerOptions(); + _requestMatcher = new TemplateMatcher(TemplateParser.Parse(options.RouteTemplate), new RouteValueDictionary()); + } + + public async Task Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) + { + if (!RequestingSwaggerDocument(httpContext.Request, out string documentName)) + { + await _next(httpContext); + return; + } + + var basePath = string.IsNullOrEmpty(httpContext.Request.PathBase) + ? null + : httpContext.Request.PathBase.ToString(); + + try + { + var swagger = swaggerProvider.GetSwagger(documentName, null, basePath); + + // One last opportunity to modify the Swagger Document - this time with request context + foreach (var filter in _options.PreSerializeFilters) + { + filter(swagger, httpContext.Request); + } + + await RespondWithSwaggerJson(httpContext.Response, swagger); + } + catch (UnknownSwaggerDocument) + { + RespondWithNotFound(httpContext.Response); + } + } + + private bool RequestingSwaggerDocument(HttpRequest request, out string documentName) + { + documentName = null; + if (request.Method != "GET") return false; + + var routeValues = new RouteValueDictionary(); + if (!_requestMatcher.TryMatch(request.Path, routeValues) || !routeValues.ContainsKey("documentName")) return false; + + documentName = routeValues["documentName"].ToString(); + return true; + } + + private void RespondWithNotFound(HttpResponse response) + { + response.StatusCode = 404; + } + + private async Task RespondWithSwaggerJson(HttpResponse response, SwaggerDocument swagger) + { + response.StatusCode = 200; + response.ContentType = "application/json;charset=utf-8"; + + var jsonBuilder = new StringBuilder(); + using (var writer = new StringWriter(jsonBuilder)) + { + _swaggerSerializer.Serialize(writer, swagger); + await response.WriteAsync(jsonBuilder.ToString(), new UTF8Encoding(false)); + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerOptions.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerOptions.cs new file mode 100644 index 000000000..1f6065028 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerOptions.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; + +namespace Surging.Core.Swagger +{ + public class SwaggerOptions + { + public SwaggerOptions() + { + PreSerializeFilters = new List>(); + } + + /// + /// Sets a custom route for the Swagger JSON endpoint(s). Must include the {documentName} parameter + /// + public string RouteTemplate { get; set; } = "swagger/{documentName}/swagger.json"; + + /// + /// Actions that can be applied SwaggerDocument's before they're serialized to JSON. + /// Useful for setting metadata that's derived from the current request + /// + public List> PreSerializeFilters { get; private set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerSerializerFactory.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerSerializerFactory.cs new file mode 100644 index 000000000..5cc5ff22e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Application/SwaggerSerializerFactory.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; + +namespace Surging.Core.Swagger +{ + public class SwaggerSerializerFactory + { + public static JsonSerializer Create(IOptions applicationJsonOptions) + { + // TODO: Should this handle case where mvcJsonOptions.Value == null? + return new JsonSerializer + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = applicationJsonOptions.Value.SerializerSettings.Formatting, + ContractResolver = new SwaggerContractResolver(applicationJsonOptions.Value.SerializerSettings) + }; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Filters/AddAuthorizationOperationFilter.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Filters/AddAuthorizationOperationFilter.cs new file mode 100644 index 000000000..a490f401e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Filters/AddAuthorizationOperationFilter.cs @@ -0,0 +1,66 @@ +using Surging.Core.CPlatform.Filters.Implementation; +using Surging.Core.SwaggerGen; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Surging.Core.Swagger.Swagger.Filters +{ + public class AddAuthorizationOperationFilter : IOperationFilter + { + + public AddAuthorizationOperationFilter() + { + } + + public void Apply(Operation operation, OperationFilterContext context) + { + if (operation.Parameters == null) + { + operation.Parameters = new List(); + } + + + var attribute = + context.ServiceEntry.Attributes.Where(p => p is AuthorizationAttribute) + .Select(p => p as AuthorizationAttribute).FirstOrDefault(); + if (attribute != null && attribute.AuthType == AuthorizationType.JWT) + { + operation.Parameters.Add(new BodyParameter + { + Name = "Authorization", + In = "header", + Required = false, + Schema = new Schema + { + Type = "string" + } + }); + } + else if( attribute != null && attribute.AuthType == AuthorizationType.AppSecret) + { + operation.Parameters.Add(new BodyParameter + { + Name = "Authorization", + In = "header", + Required = false, + Schema = new Schema + { + Type = "string" + } + }); + operation.Parameters.Add(new BodyParameter + { + Name = "timeStamp", + In = "query", + Required = false, + Schema = new Schema + { + Type = "string" + } + }); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/ApiKeyScheme.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/ApiKeyScheme.cs new file mode 100644 index 000000000..f50f01aaf --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/ApiKeyScheme.cs @@ -0,0 +1,14 @@ +namespace Surging.Core.Swagger +{ + public class ApiKeyScheme : SecurityScheme + { + public string Name { get; set; } + + public string In { get; set; } + + public ApiKeyScheme() + { + Type = "apiKey"; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/BasicAuthScheme.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/BasicAuthScheme.cs new file mode 100644 index 000000000..f59338ee4 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/BasicAuthScheme.cs @@ -0,0 +1,10 @@ +namespace Surging.Core.Swagger +{ + public class BasicAuthScheme : SecurityScheme + { + public BasicAuthScheme() + { + Type = "basic"; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/ISwaggerProvider.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/ISwaggerProvider.cs new file mode 100644 index 000000000..2b1220341 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/ISwaggerProvider.cs @@ -0,0 +1,20 @@ +using System; + +namespace Surging.Core.Swagger +{ + public interface ISwaggerProvider + { + SwaggerDocument GetSwagger( + string documentName, + string host = null, + string basePath = null, + string[] schemes = null); + } + + public class UnknownSwaggerDocument : Exception + { + public UnknownSwaggerDocument(string documentName) + : base(string.Format("Unknown Swagger document - {0}", documentName)) + {} + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/OAuth2Scheme.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/OAuth2Scheme.cs new file mode 100644 index 000000000..c2eb0b55d --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/OAuth2Scheme.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace Surging.Core.Swagger +{ + public class OAuth2Scheme : SecurityScheme + { + public OAuth2Scheme() + { + Type = "oauth2"; + } + + public string Flow { get; set; } + + public string AuthorizationUrl { get; set; } + + public string TokenUrl { get; set; } + + public IDictionary Scopes { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/SecurityScheme.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/SecurityScheme.cs new file mode 100644 index 000000000..6693c8cf1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/SecurityScheme.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Surging.Core.Swagger +{ + public abstract class SecurityScheme + { + public SecurityScheme() + { + Extensions = new Dictionary(); + } + + public string Type { get; set; } + + public string Description { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/SwaggerDocument.cs b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/SwaggerDocument.cs new file mode 100644 index 000000000..650c6d23c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/Swagger/Model/SwaggerDocument.cs @@ -0,0 +1,401 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Surging.Core.Swagger +{ + public class SwaggerDocument + { + public SwaggerDocument() + { + Extensions = new Dictionary(); + } + + public string Swagger + { + get { return "2.0"; } + } + + public Info Info { get; set; } + + public string Host { get; set; } + + public string BasePath { get; set; } + + public IList Schemes { get; set; } + + public IList Consumes { get; set; } + + public IList Produces { get; set; } + + public IDictionary Paths { get; set; } + + public IDictionary Definitions { get; set; } + + public IDictionary Parameters { get; set; } + + public IDictionary Responses { get; set; } + + public IDictionary SecurityDefinitions { get; set; } + + public IList>> Security { get; set; } + + public IList Tags { get; set; } + + public ExternalDocs ExternalDocs { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class DocumentConfiguration + { + public Info Info { get; set; } = null; + + public DocumentOptions Options { get; set; } = null; + } + + public class DocumentOptions + { + public bool IgnoreFullyQualified { get; set; } + + public string IngressName { get; set; } + + public IEnumerable MapRoutePaths { get; set; } + } + + public class MapRoutePath + { + public string SourceRoutePath { get; set; } + + public string TargetRoutePath { get; set; } + } + + public class Info + { + public Info() + { + Extensions = new Dictionary(); + } + + public string Version { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } + + public string TermsOfService { get; set; } + + public Contact Contact { get; set; } + + public License License { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class Contact + { + public string Name { get; set; } + + public string Url { get; set; } + + public string Email { get; set; } + } + + public class License + { + public string Name { get; set; } + + public string Url { get; set; } + } + + public class PathItem + { + public PathItem() + { + Extensions = new Dictionary(); + } + + [JsonProperty("$ref")] + public string Ref { get; set; } + + public Operation Get { get; set; } + + public Operation Put { get; set; } + + public Operation Post { get; set; } + + public Operation Delete { get; set; } + + public Operation Options { get; set; } + + public Operation Head { get; set; } + + public Operation Patch { get; set; } + + public IList Parameters { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class Operation + { + public Operation() + { + Extensions = new Dictionary(); + } + + public IList Tags { get; set; } + + public string Summary { get; set; } + + public string Description { get; set; } + + public ExternalDocs ExternalDocs { get; set; } + + public string OperationId { get; set; } + + public IList Consumes { get; set; } + + public IList Produces { get; set; } + + public IList Parameters { get; set; } + + public IDictionary Responses { get; set; } + + public IList Schemes { get; set; } + + public bool? Deprecated { get; set; } + + public IList>> Security { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class Tag + { + public Tag() + { + Extensions = new Dictionary(); + } + + public string Name { get; set; } + + public string Description { get; set; } + + public ExternalDocs ExternalDocs { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class ExternalDocs + { + public string Description { get; set; } + + public string Url { get; set; } + } + + + public interface IParameter + { + string Name { get; set; } + + string In { get; set; } + + string Description { get; set; } + + bool Required { get; set; } + + Dictionary Extensions { get; } + } + + public class BodyParameter : IParameter + { + public BodyParameter() + { + In = "body"; + Extensions = new Dictionary(); + } + + public string Name { get; set; } + + public string In { get; set; } + + public string Description { get; set; } + + public bool Required { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + + public Schema Schema { get; set; } + } + + public class NonBodyParameter : PartialSchema, IParameter + { + public string Name { get; set; } + + public string In { get; set; } + + public string Description { get; set; } + + public bool Required { get; set; } + } + + public class Schema + { + public Schema() + { + Extensions = new Dictionary(); + } + + [JsonProperty("$ref")] + public string Ref { get; set; } + + public string Format { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } + + public object Default { get; set; } + + public int? MultipleOf { get; set; } + + public double? Maximum { get; set; } + + public bool? ExclusiveMaximum { get; set; } + + public double? Minimum { get; set; } + + public bool? ExclusiveMinimum { get; set; } + + public int? MaxLength { get; set; } + + public int? MinLength { get; set; } + + public string Pattern { get; set; } + + public int? MaxItems { get; set; } + + public int? MinItems { get; set; } + + public bool? UniqueItems { get; set; } + + public int? MaxProperties { get; set; } + + public int? MinProperties { get; set; } + + public IList Required { get; set; } + + public IList Enum { get; set; } + + public string Type { get; set; } + + public Schema Items { get; set; } + + public IList AllOf { get; set; } + + public IDictionary Properties { get; set; } + + public Schema AdditionalProperties { get; set; } + + public string Discriminator { get; set; } + + public bool? ReadOnly { get; set; } + + public Xml Xml { get; set; } + + public ExternalDocs ExternalDocs { get; set; } + + public object Example { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class PartialSchema + { + public PartialSchema() + { + Extensions = new Dictionary(); + } + + public string Type { get; set; } + + public string Format { get; set; } + + public PartialSchema Items { get; set; } + + public string CollectionFormat { get; set; } + + public object Default { get; set; } + + public double? Maximum { get; set; } + + public bool? ExclusiveMaximum { get; set; } + + public double? Minimum { get; set; } + + public bool? ExclusiveMinimum { get; set; } + + public int? MaxLength { get; set; } + + public int? MinLength { get; set; } + + public string Pattern { get; set; } + + public int? MaxItems { get; set; } + + public int? MinItems { get; set; } + + public bool? UniqueItems { get; set; } + + public IList Enum { get; set; } + + public int? MultipleOf { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class Response + { + public Response() + { + Extensions = new Dictionary(); + } + + public string Description { get; set; } + + public Schema Schema { get; set; } + + public IDictionary Headers { get; set; } + + public object Examples { get; set; } + + [JsonExtensionData] + public Dictionary Extensions { get; private set; } + } + + public class Header : PartialSchema + { + public string Description { get; set; } + } + + public class Xml + { + public string Name { get; set; } + + public string Namespace { get; set; } + + public string Prefix { get; set; } + + public bool? Attribute { get; set; } + + public bool? Wrapped { get; set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/ConfigureSchemaRegistryOptions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/ConfigureSchemaRegistryOptions.cs new file mode 100644 index 000000000..b48175a49 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/ConfigureSchemaRegistryOptions.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + internal class ConfigureSchemaRegistryOptions : IConfigureOptions + { + private readonly IServiceProvider _serviceProvider; + private readonly SwaggerGenOptions _swaggerGenOptions; + + public ConfigureSchemaRegistryOptions( + IServiceProvider serviceProvider, + IOptions swaggerGenOptionsAccessor) + { + _serviceProvider = serviceProvider; + _swaggerGenOptions = swaggerGenOptionsAccessor.Value; + } + + public void Configure(SchemaRegistryOptions options) + { + DeepCopy(_swaggerGenOptions.SchemaRegistryOptions, options); + + // Create and add any filters that were specified through the FilterDescriptor lists + _swaggerGenOptions.SchemaFilterDescriptors.ForEach( + filterDescriptor => options.SchemaFilters.Add(CreateFilter(filterDescriptor))); + } + + private void DeepCopy(SchemaRegistryOptions source, SchemaRegistryOptions target) + { + target.CustomTypeMappings = new Dictionary>(source.CustomTypeMappings); + target.DescribeAllEnumsAsStrings = source.DescribeAllEnumsAsStrings; + target.IgnoreFullyQualified = source.IgnoreFullyQualified; + target.DescribeStringEnumsInCamelCase = source.DescribeStringEnumsInCamelCase; + target.UseReferencedDefinitionsForEnums = source.UseReferencedDefinitionsForEnums; + target.SchemaIdSelector = source.SchemaIdSelector; + target.IgnoreObsoleteProperties = source.IgnoreObsoleteProperties; + target.SchemaFilters = new List(source.SchemaFilters); + } + + private TFilter CreateFilter(FilterDescriptor filterDescriptor) + { + return (TFilter)ActivatorUtilities + .CreateInstance(_serviceProvider, filterDescriptor.Type, filterDescriptor.Arguments); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/ConfigureSwaggerGeneratorOptions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/ConfigureSwaggerGeneratorOptions.cs new file mode 100644 index 000000000..6e1674ac9 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/ConfigureSwaggerGeneratorOptions.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + internal class ConfigureSwaggerGeneratorOptions : IConfigureOptions + { + private readonly IServiceProvider _serviceProvider; + private readonly SwaggerGenOptions _swaggerGenOptions; + + public ConfigureSwaggerGeneratorOptions( + IServiceProvider serviceProvider, + IOptions swaggerGenOptionsAccessor) + { + _serviceProvider = serviceProvider; + _swaggerGenOptions = swaggerGenOptionsAccessor.Value; + } + + public void Configure(SwaggerGeneratorOptions options) + { + DeepCopy(_swaggerGenOptions.SwaggerGeneratorOptions, options); + + // Create and add any filters that were specified through the FilterDescriptor lists ... + + _swaggerGenOptions.ParameterFilterDescriptors.ForEach( + filterDescriptor => options.ParameterFilters.Add(CreateFilter(filterDescriptor))); + + _swaggerGenOptions.OperationFilterDescriptors.ForEach( + filterDescriptor => options.OperationFilters.Add(CreateFilter(filterDescriptor))); + + _swaggerGenOptions.DocumentFilterDescriptors.ForEach( + filterDescriptor => options.DocumentFilters.Add(CreateFilter(filterDescriptor))); + } + + public void DeepCopy(SwaggerGeneratorOptions source, SwaggerGeneratorOptions target) + { + target.SwaggerDocs = new Dictionary(source.SwaggerDocs); + target.DocInclusionPredicate = source.DocInclusionPredicate; + target.IgnoreObsoleteActions = source.IgnoreObsoleteActions; + target.DocInclusionPredicateV2 = source.DocInclusionPredicateV2; + target.ConflictingActionsResolver = source.ConflictingActionsResolver; + target.OperationIdSelector = source.OperationIdSelector; + target.TagsSelector = source.TagsSelector; + target.SortKeySelector = source.SortKeySelector; + target.DescribeAllParametersInCamelCase = source.DescribeAllParametersInCamelCase; + target.SecurityDefinitions = new Dictionary(source.SecurityDefinitions); + target.SecurityRequirements = new List>>(source.SecurityRequirements); + target.ParameterFilters = new List(source.ParameterFilters); + target.OperationFilters = new List(source.OperationFilters); + target.DocumentFilters = new List(source.DocumentFilters); + } + + private TFilter CreateFilter(FilterDescriptor filterDescriptor) + { + return (TFilter)ActivatorUtilities + .CreateInstance(_serviceProvider, filterDescriptor.Type, filterDescriptor.Arguments); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerApplicationConvention.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerApplicationConvention.cs new file mode 100644 index 000000000..9aa4b0664 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerApplicationConvention.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace Surging.Core.SwaggerGen +{ + public class SwaggerApplicationConvention : IApplicationModelConvention + { + public void Apply(ApplicationModel application) + { + application.ApiExplorer.IsVisible = true; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenOptions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenOptions.cs new file mode 100644 index 000000000..df1ab8beb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenOptions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace Surging.Core.SwaggerGen +{ + public class SwaggerGenOptions + { + public SwaggerGeneratorOptions SwaggerGeneratorOptions { get; set; } = new SwaggerGeneratorOptions(); + + public SchemaRegistryOptions SchemaRegistryOptions { get; set; } = new SchemaRegistryOptions(); + + // NOTE: Filter instances can be added directly to the options exposed above OR they can be specified in + // the following lists. In the latter case, they will be instantiated and added when options are injected + // into their target services. This "deferred instantiation" allows the filters to be created from the + // DI container, thus supporting contructor injection of services within filters. + + public List ParameterFilterDescriptors { get; set; } = new List(); + + public List OperationFilterDescriptors { get; set; } = new List(); + + public List DocumentFilterDescriptors { get; set; } = new List(); + + public List SchemaFilterDescriptors { get; set; } = new List(); + } + + public class FilterDescriptor + { + public Type Type { get; set; } + + public object[] Arguments { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenOptionsExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenOptionsExtensions.cs new file mode 100644 index 000000000..441b3195b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenOptionsExtensions.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Xml.XPath; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.Swagger; +using Surging.Core.SwaggerGen; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class SwaggerGenOptionsExtensions + { + /// + /// Define one or more documents to be created by the Swagger generator + /// + /// + /// A URI-friendly name that uniquely identifies the document + /// Global metadata to be included in the Swagger output + public static void SwaggerDoc( + this SwaggerGenOptions swaggerGenOptions, + string name, + Info info) + { + swaggerGenOptions.SwaggerGeneratorOptions.SwaggerDocs.Add(name, info); + } + + /// + /// Provide a custom strategy for selecting actions. + /// + /// + /// + /// A lambda that returns true/false based on document name and ApiDescription + /// + public static void DocInclusionPredicate( + this SwaggerGenOptions swaggerGenOptions, + Func predicate) + { + swaggerGenOptions.SwaggerGeneratorOptions.DocInclusionPredicate = predicate; + } + + public static void DocInclusionPredicateV2( + this SwaggerGenOptions swaggerGenOptions, + Func predicate) + { + swaggerGenOptions.SwaggerGeneratorOptions.DocInclusionPredicateV2 = predicate; + } + + public static void GenerateSwaggerDoc( + this SwaggerGenOptions swaggerGenOptions, IEnumerable entries) + { + + var result = new Dictionary(); + var assemblies = entries.Select(p => p.Type.Assembly).Distinct(); + foreach (var assembly in assemblies) + { + var version = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + var title = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + var des = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + if (version == null || title == null) + continue; + swaggerGenOptions.SwaggerDoc(title.Title, new Info() + { + Title = title.Title, + Version = version.Version, + Description = des?.Description, + + }); + } + } + + /// + /// Ignore any actions that are decorated with the ObsoleteAttribute + /// + public static void IgnoreObsoleteActions(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SwaggerGeneratorOptions.IgnoreObsoleteActions = true; + } + + /// + /// Merge actions that have conflicting HTTP methods and paths (must be unique for Swagger 2.0) + /// + /// + /// + public static void ResolveConflictingActions( + this SwaggerGenOptions swaggerGenOptions, + Func, ApiDescription> resolver) + { + swaggerGenOptions.SwaggerGeneratorOptions.ConflictingActionsResolver = resolver; + } + + /// + /// Provide a custom strategy for assigning "operationId" to operations + /// + public static void CustomOperationIds( + this SwaggerGenOptions swaggerGenOptions, + Func operationIdSelector) + { + swaggerGenOptions.SwaggerGeneratorOptions.OperationIdSelector = operationIdSelector; + } + + /// + /// Provide a custom strategy for assigning a default "tag" to operations + /// + /// + /// + [Obsolete("Deprecated: Use the overload that accepts a Func that returns a list of tags")] + public static void TagActionsBy( + this SwaggerGenOptions swaggerGenOptions, + Func tagSelector) + { + swaggerGenOptions.SwaggerGeneratorOptions.TagsSelector = (apiDesc) => new[] { tagSelector(apiDesc) }; + } + + /// + /// Provide a custom strategy for assigning "tags" to actions + /// + /// + /// + public static void TagActionsBy( + this SwaggerGenOptions swaggerGenOptions, + Func> tagsSelector) + { + swaggerGenOptions.SwaggerGeneratorOptions.TagsSelector = tagsSelector; + } + + /// + /// Provide a custom strategy for sorting actions before they're transformed into the Swagger format + /// + /// + /// + public static void OrderActionsBy( + this SwaggerGenOptions swaggerGenOptions, + Func sortKeySelector) + { + swaggerGenOptions.SwaggerGeneratorOptions.SortKeySelector = sortKeySelector; + } + + /// + /// Describe all parameters, regardless of how they appear in code, in camelCase + /// + public static void DescribeAllParametersInCamelCase(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SwaggerGeneratorOptions.DescribeAllParametersInCamelCase = true; + } + + /// + /// Add one or more "securityDefinitions", describing how your API is protected, to the generated Swagger + /// + /// + /// A unique name for the scheme, as per the Swagger spec. + /// + /// A description of the scheme - can be an instance of BasicAuthScheme, ApiKeyScheme or OAuth2Scheme + /// + public static void AddSecurityDefinition( + this SwaggerGenOptions swaggerGenOptions, + string name, + SecurityScheme securityScheme) + { + swaggerGenOptions.SwaggerGeneratorOptions.SecurityDefinitions.Add(name, securityScheme); + } + + /// + /// Adds a global security requirement + /// + /// + /// + /// A dictionary of required schemes (logical AND). Keys must correspond to schemes defined through AddSecurityDefinition + /// If the scheme is of type "oauth2", then the value is a list of scopes, otherwise it MUST be an empty array + /// + public static void AddSecurityRequirement( + this SwaggerGenOptions swaggerGenOptions, + IDictionary> requirement) + { + swaggerGenOptions.SwaggerGeneratorOptions.SecurityRequirements.Add(requirement); + } + + /// + /// Provide a custom mapping, for a given type, to the Swagger-flavored JSONSchema + /// + /// + /// System type + /// A factory method that generates Schema's for the provided type + public static void MapType( + this SwaggerGenOptions swaggerGenOptions, + Type type, + Func schemaFactory) + { + swaggerGenOptions.SchemaRegistryOptions.CustomTypeMappings.Add(type, schemaFactory); + } + + /// + /// Provide a custom mapping, for a given type, to the Swagger-flavored JSONSchema + /// + /// System type + /// + /// A factory method that generates Schema's for the provided type + public static void MapType( + this SwaggerGenOptions swaggerGenOptions, + Func schemaFactory) + { + swaggerGenOptions.MapType(typeof(T), schemaFactory); + } + + /// + /// Use the enum names, as opposed to their integer values, when describing enum types + /// + public static void DescribeAllEnumsAsStrings(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SchemaRegistryOptions.DescribeAllEnumsAsStrings = true; + } + + /// + /// If applicable, describe all enum names, regardless of how they appear in code, in camelCase. + /// + public static void DescribeStringEnumsInCamelCase(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SchemaRegistryOptions.DescribeStringEnumsInCamelCase = true; + } + + /// + /// Use referenced definitions for enum types within body parameter and response schemas + /// + public static void UseReferencedDefinitionsForEnums(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SchemaRegistryOptions.UseReferencedDefinitionsForEnums = true; + } + + /// + /// Provide a custom strategy for generating the unique Id's that are used to reference object Schema's + /// + /// + /// + /// A lambda that returns a unique identifier for the provided system type + /// + public static void CustomSchemaIds( + this SwaggerGenOptions swaggerGenOptions, + Func schemaIdSelector) + { + swaggerGenOptions.SchemaRegistryOptions.SchemaIdSelector = schemaIdSelector; + } + + /// + /// Ignore any properties that are decorated with the ObsoleteAttribute + /// + public static void IgnoreObsoleteProperties(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SchemaRegistryOptions.IgnoreObsoleteProperties = true; + } + + public static void IgnoreFullyQualified(this SwaggerGenOptions swaggerGenOptions) + { + swaggerGenOptions.SchemaRegistryOptions.IgnoreFullyQualified = true; + } + + /// + /// Extend the Swagger Generator with "filters" that can modify Schemas after they're initially generated + /// + /// A type that derives from ISchemaFilter + /// + /// Optionally inject parameters through filter constructors + public static void SchemaFilter( + this SwaggerGenOptions swaggerGenOptions, + params object[] arguments) + where TFilter : ISchemaFilter + { + swaggerGenOptions.SchemaFilterDescriptors.Add(new FilterDescriptor + { + Type = typeof(TFilter), + Arguments = arguments + }); + } + + /// + /// Extend the Swagger Generator with "filters" that can modify Parameters after they're initially generated + /// + /// A type that derives from IParameterFilter + /// + /// Optionally inject parameters through filter constructors + public static void ParameterFilter( + this SwaggerGenOptions swaggerGenOptions, + params object[] arguments) + where TFilter : IParameterFilter + { + swaggerGenOptions.ParameterFilterDescriptors.Add(new FilterDescriptor + { + Type = typeof(TFilter), + Arguments = arguments + }); + } + + /// + /// Extend the Swagger Generator with "filters" that can modify Operations after they're initially generated + /// + /// A type that derives from IOperationFilter + /// + /// Optionally inject parameters through filter constructors + public static void OperationFilter( + this SwaggerGenOptions swaggerGenOptions, + params object[] arguments) + where TFilter : IOperationFilter + { + swaggerGenOptions.OperationFilterDescriptors.Add(new FilterDescriptor + { + Type = typeof(TFilter), + Arguments = arguments + }); + } + + /// + /// Extend the Swagger Generator with "filters" that can modify SwaggerDocuments after they're initially generated + /// + /// A type that derives from IDocumentFilter + /// + /// Optionally inject parameters through filter constructors + public static void DocumentFilter( + this SwaggerGenOptions swaggerGenOptions, + params object[] arguments) + where TFilter : IDocumentFilter + { + swaggerGenOptions.DocumentFilterDescriptors.Add(new FilterDescriptor + { + Type = typeof(TFilter), + Arguments = arguments + }); + } + + /// + /// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files + /// + /// + /// A factory method that returns XML Comments as an XPathDocument + /// + /// Flag to indicate if controller XML comments (i.e. summary) should be used to assign Tag descriptions. + /// Don't set this flag if you're customizing the default tag for operations via TagActionsBy. + /// + public static void IncludeXmlComments( + this SwaggerGenOptions swaggerGenOptions, + Func xmlDocFactory, + bool includeControllerXmlComments = false) + { + var xmlDoc = xmlDocFactory(); + swaggerGenOptions.OperationFilter(xmlDoc); + swaggerGenOptions.SchemaFilter(xmlDoc); + + if (includeControllerXmlComments) + swaggerGenOptions.DocumentFilter(xmlDoc); + } + + /// + /// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files + /// + /// + /// An abolsute path to the file that contains XML Comments + /// + /// Flag to indicate if controller XML comments (i.e. summary) should be used to assign Tag descriptions. + /// Don't set this flag if you're customizing the default tag for operations via TagActionsBy. + /// + public static void IncludeXmlComments( + this SwaggerGenOptions swaggerGenOptions, + string filePath, + bool includeControllerXmlComments = false) + { + swaggerGenOptions.IncludeXmlComments(() => new XPathDocument(filePath), includeControllerXmlComments); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenServiceCollectionExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenServiceCollectionExtensions.cs new file mode 100644 index 000000000..d09527145 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Application/SwaggerGenServiceCollectionExtensions.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Surging.Core.Swagger; +using Surging.Core.SwaggerGen; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class SwaggerGenServiceCollectionExtensions + { + public static IServiceCollection AddSwaggerGen( + this IServiceCollection services, + Action setupAction = null) + { + // Add Mvc convention to ensure ApiExplorer is enabled for all actions + services.Configure(c => + c.Conventions.Add(new SwaggerApplicationConvention())); + + // Register generator and it's dependencies + services.AddTransient(); + services.AddTransient(); + + // Register custom configurators that assign values from SwaggerGenOptions (i.e. high level config) + // to the service-specific options (i.e. lower-level config) + services.AddTransient, ConfigureSwaggerGeneratorOptions>(); + services.AddTransient, ConfigureSchemaRegistryOptions>(); + + if (setupAction != null) services.ConfigureSwaggerGen(setupAction); + + return services; + } + + public static void ConfigureSwaggerGen( + this IServiceCollection services, + Action setupAction) + { + services.Configure(setupAction); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiDescriptionExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiDescriptionExtensions.cs new file mode 100644 index 000000000..f7b8403fb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiDescriptionExtensions.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Controllers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Surging.Core.SwaggerGen +{ + public static class ApiDescriptionExtensions + { + [Obsolete("Deprecated: Use TryGetMethodInfo")] + public static IEnumerable ControllerAttributes(this ApiDescription apiDescription) + { + var controllerActionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor; + return (controllerActionDescriptor == null) + ? Enumerable.Empty() + : controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(true); + } + + [Obsolete("Deprecated: Use TryGetMethodInfo")] + public static IEnumerable ActionAttributes(this ApiDescription apiDescription) + { + var controllerActionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor; + return (controllerActionDescriptor == null) + ? Enumerable.Empty() + : controllerActionDescriptor.MethodInfo.GetCustomAttributes(true); + } + + public static bool TryGetMethodInfo(this ApiDescription apiDescription, out MethodInfo methodInfo) + { + var controllerActionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor; + + methodInfo = controllerActionDescriptor?.MethodInfo; + + return (methodInfo != null); + } + + internal static string RelativePathSansQueryString(this ApiDescription apiDescription) + { + return apiDescription.RelativePath.Split('?').First(); + } + + internal static bool IsObsolete(this ApiDescription apiDescription) + { + if (!apiDescription.TryGetMethodInfo(out MethodInfo methodInfo)) + return false; + + return methodInfo.GetCustomAttributes(true) + .Union(methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true)) + .Any(attr => attr.GetType() == typeof(ObsoleteAttribute)); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiParameterDescriptionExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiParameterDescriptionExtensions.cs new file mode 100644 index 000000000..e99cca2e2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiParameterDescriptionExtensions.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Controllers; +using System.Linq; +using System.Reflection; + +namespace Surging.Core.SwaggerGen +{ + public static class ApiParameterDescriptionExtensions + { + internal static bool TryGetParameterInfo( + this ApiParameterDescription apiParameterDescription, + ApiDescription apiDescription, + out ParameterInfo parameterInfo) + { + var controllerParameterDescriptor = apiDescription.ActionDescriptor.Parameters + .OfType() + .FirstOrDefault(descriptor => + { + return (apiParameterDescription.Name == descriptor.BindingInfo?.BinderModelName) + || (apiParameterDescription.Name == descriptor.Name); + }); + + parameterInfo = controllerParameterDescriptor?.ParameterInfo; + + return (parameterInfo != null); + } + + internal static bool TryGetPropertyInfo( + this ApiParameterDescription apiParameterDescription, + out PropertyInfo propertyInfo) + { + var modelMetadata = apiParameterDescription.ModelMetadata; + + propertyInfo = (modelMetadata?.ContainerType != null) + ? modelMetadata.ContainerType.GetProperty(modelMetadata.PropertyName) + : null; + + return (propertyInfo != null); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiResponseTypeExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiResponseTypeExtensions.cs new file mode 100644 index 000000000..3bdf54071 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ApiResponseTypeExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using System; +using System.Reflection; + +namespace Surging.Core.SwaggerGen +{ + public static class ApiResponseTypeExtensions + { + internal static bool IsDefaultResponse(this ApiResponseType apiResponseType) + { + var propertyInfo = apiResponseType.GetType().GetProperty("IsDefaultResponse"); + if (propertyInfo != null) + { + return (bool)propertyInfo.GetValue(apiResponseType); + } + + // ApiExplorer < 2.1.0 does not support default response. + return false; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IDocumentFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IDocumentFilter.cs new file mode 100644 index 000000000..6c3305aca --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IDocumentFilter.cs @@ -0,0 +1,33 @@ + +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Surging.Core.Swagger; +using System; +using System.Collections.Generic; + +namespace Surging.Core.SwaggerGen +{ + public interface IDocumentFilter + { + void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context); + } + + public class DocumentFilterContext + { + public DocumentFilterContext( + ApiDescriptionGroupCollection apiDescriptionsGroups, + IEnumerable apiDescriptions, + ISchemaRegistry schemaRegistry) + { + ApiDescriptionsGroups = apiDescriptionsGroups; + ApiDescriptions = apiDescriptions; + SchemaRegistry = schemaRegistry; + } + + [Obsolete("Deprecated: Use ApiDescriptions")] + public ApiDescriptionGroupCollection ApiDescriptionsGroups { get; private set; } + + public IEnumerable ApiDescriptions { get; private set; } + + public ISchemaRegistry SchemaRegistry { get; private set; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IOperationFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IOperationFilter.cs new file mode 100644 index 000000000..f01368e9f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IOperationFilter.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public interface IOperationFilter + { + void Apply(Operation operation, OperationFilterContext context); + } + + public class OperationFilterContext + { + public OperationFilterContext( + ApiDescription apiDescription, + ISchemaRegistry schemaRegistry, + MethodInfo methodInfo):this(apiDescription,schemaRegistry,methodInfo,null) + { + + } + + public OperationFilterContext( + ApiDescription apiDescription, + ISchemaRegistry schemaRegistry, + MethodInfo methodInfo,ServiceEntry serviceEntry) + { + ApiDescription = apiDescription; + SchemaRegistry = schemaRegistry; + MethodInfo = methodInfo; + ServiceEntry = serviceEntry; + } + + public ServiceEntry ServiceEntry { get; set; } + + public ApiDescription ApiDescription { get; private set; } + + public ISchemaRegistry SchemaRegistry { get; private set; } + + public MethodInfo MethodInfo { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IParameterFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IParameterFilter.cs new file mode 100644 index 000000000..752f67e7f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/IParameterFilter.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public interface IParameterFilter + { + void Apply(IParameter parameter, ParameterFilterContext context); + } + + public class ParameterFilterContext + { + public ParameterFilterContext( + ApiParameterDescription apiParameterDescription, + ISchemaRegistry schemaRegistry, + ParameterInfo parameterInfo, + PropertyInfo propertyInfo) + { + ApiParameterDescription = apiParameterDescription; + SchemaRegistry = schemaRegistry; + ParameterInfo = parameterInfo; + PropertyInfo = propertyInfo; + } + + public ApiParameterDescription ApiParameterDescription { get; } + + public ISchemaRegistry SchemaRegistry { get; } + + public ParameterInfo ParameterInfo { get; } + + public PropertyInfo PropertyInfo { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaFilter.cs new file mode 100644 index 000000000..0fa18ed5e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaFilter.cs @@ -0,0 +1,30 @@ +using System; +using Newtonsoft.Json.Serialization; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public interface ISchemaFilter + { + void Apply(Schema schema, SchemaFilterContext context); + } + + public class SchemaFilterContext + { + public SchemaFilterContext( + Type systemType, + JsonContract jsonContract, + ISchemaRegistry schemaRegistry) + { + SystemType = systemType; + JsonContract = jsonContract; + SchemaRegistry = schemaRegistry; + } + + public Type SystemType { get; private set; } + + public JsonContract JsonContract { get; private set; } + + public ISchemaRegistry SchemaRegistry { get; private set; } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaRegistry.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaRegistry.cs new file mode 100644 index 000000000..867203486 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaRegistry.cs @@ -0,0 +1,14 @@ +using Surging.Core.Swagger; +using System; +using System.Collections.Generic; +namespace Surging.Core.SwaggerGen +{ + public interface ISchemaRegistry + { + Schema GetOrRegister(Type type); + + Schema GetOrRegister(string parmName, Type type); + + IDictionary Definitions { get; } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaRegistryFactory.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaRegistryFactory.cs new file mode 100644 index 000000000..530554a43 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/ISchemaRegistryFactory.cs @@ -0,0 +1,7 @@ +namespace Surging.Core.SwaggerGen +{ + public interface ISchemaRegistryFactory + { + ISchemaRegistry Create(); + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/JsonContractExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/JsonContractExtensions.cs new file mode 100644 index 000000000..a08d7f8fe --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/JsonContractExtensions.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json.Serialization; + +namespace Surging.Core.SwaggerGen +{ + internal static class JsonContractExtensions + { + internal static bool IsSelfReferencingArrayOrDictionary(this JsonContract jsonContract) + { + if (jsonContract is JsonArrayContract arrayContract) + return arrayContract.UnderlyingType == arrayContract.CollectionItemType; + + if (jsonContract is JsonDictionaryContract dictionaryContract) + return dictionaryContract.UnderlyingType == dictionaryContract.DictionaryValueType; + + return false; + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/JsonPropertyExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/JsonPropertyExtensions.cs new file mode 100644 index 000000000..9dd5b82fb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/JsonPropertyExtensions.cs @@ -0,0 +1,61 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Serialization; + +namespace Surging.Core.SwaggerGen +{ + internal static class JsonPropertyExtensions + { + internal static bool IsRequired(this JsonProperty jsonProperty) + { + if (jsonProperty.Required == Newtonsoft.Json.Required.AllowNull) + return true; + + if (jsonProperty.Required == Newtonsoft.Json.Required.Always) + return true; + + if (jsonProperty.HasAttribute()) + return true; + + return false; + } + + internal static bool IsObsolete(this JsonProperty jsonProperty) + { + return jsonProperty.HasAttribute(); + } + + internal static bool HasAttribute(this JsonProperty jsonProperty) + where T : Attribute + { + if (!jsonProperty.TryGetMemberInfo(out MemberInfo memberInfo)) + return false; + + return memberInfo.GetCustomAttribute() != null; + } + + internal static bool TryGetMemberInfo(this JsonProperty jsonProperty, out MemberInfo memberInfo) + { + if (jsonProperty.UnderlyingName == null) + { + memberInfo = null; + return false; + } + + var metadataAttribute = jsonProperty.DeclaringType.GetTypeInfo() + .GetCustomAttributes(typeof(ModelMetadataTypeAttribute), true) + .FirstOrDefault(); + + var typeToReflect = (metadataAttribute != null) + ? ((ModelMetadataTypeAttribute)metadataAttribute).MetadataType + : jsonProperty.DeclaringType; + + memberInfo = typeToReflect.GetMember(jsonProperty.UnderlyingName).FirstOrDefault(); + + return (memberInfo != null); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaExtensions.cs new file mode 100644 index 000000000..ad1c5c9e1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaExtensions.cs @@ -0,0 +1,89 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + internal static class SchemaExtensions + { + internal static Schema AssignAttributeMetadata(this Schema schema, IEnumerable attributes) + { + foreach (var attribute in attributes) + { + if (attribute is DefaultValueAttribute defaultValue) + schema.Default = defaultValue.Value; + + if (attribute is RegularExpressionAttribute regex) + schema.Pattern = regex.Pattern; + + if (attribute is RangeAttribute range) + { + if (Double.TryParse(range.Maximum.ToString(), out double maximum)) + schema.Maximum = maximum; + + if (Double.TryParse(range.Minimum.ToString(), out double minimum)) + schema.Minimum = minimum; + } + + if (attribute is MinLengthAttribute minLength) + schema.MinLength = minLength.Length; + + if (attribute is MaxLengthAttribute maxLength) + schema.MaxLength = maxLength.Length; + + if (attribute is StringLengthAttribute stringLength) + { + schema.MinLength = stringLength.MinimumLength; + schema.MaxLength = stringLength.MaximumLength; + } + + if (attribute is DataTypeAttribute dataTypeAttribute && schema.Type == "string") + { + if (DataTypeFormatMap.TryGetValue(dataTypeAttribute.DataType, out string format)) + schema.Format = format; + } + } + + return schema; + } + + internal static void PopulateFrom(this PartialSchema partialSchema, Schema schema) + { + if (schema == null) return; + + partialSchema.Type = schema.Type; + partialSchema.Format = schema.Format; + + if (schema.Items != null) + { + // TODO: Handle jagged primitive array and error on jagged object array + partialSchema.Items = new PartialSchema(); + partialSchema.Items.PopulateFrom(schema.Items); + partialSchema.CollectionFormat = "multi"; + } + + partialSchema.Default = schema.Default; + partialSchema.Maximum = schema.Maximum; + partialSchema.ExclusiveMaximum = schema.ExclusiveMaximum; + partialSchema.Minimum = schema.Minimum; + partialSchema.ExclusiveMinimum = schema.ExclusiveMinimum; + partialSchema.MaxLength = schema.MaxLength; + partialSchema.MinLength = schema.MinLength; + partialSchema.Pattern = schema.Pattern; + partialSchema.MaxItems = schema.MaxItems; + partialSchema.MinItems = schema.MinItems; + partialSchema.UniqueItems = schema.UniqueItems; + partialSchema.Enum = schema.Enum; + partialSchema.MultipleOf = schema.MultipleOf; + } + + private static readonly Dictionary DataTypeFormatMap = new Dictionary + { + { DataType.Date, "date" }, + { DataType.DateTime, "date-time" }, + { DataType.Password, "password" } + }; + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaIdManager.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaIdManager.cs new file mode 100644 index 000000000..f04bb3b13 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaIdManager.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Surging.Core.SwaggerGen +{ + public class SchemaIdManager + { + private readonly Func _schemaIdSelector; + private readonly IDictionary _schemaIdMap; + + public SchemaIdManager(Func schemaIdSelector) + { + _schemaIdSelector = schemaIdSelector; + _schemaIdMap = new Dictionary(); + } + + public string IdFor(Type type) + { + if (!_schemaIdMap.TryGetValue(type, out string schemaId)) + { + schemaId = _schemaIdSelector(type); + + // Raise an exception if another type with same schemaId + if (_schemaIdMap.Any(entry => entry.Value == schemaId)) + throw new InvalidOperationException(string.Format( + "Conflicting schemaIds: Identical schemaIds detected for types {0} and {1}. " + + "See config settings - \"CustomSchemaIds\" for a workaround", + type.FullName, _schemaIdMap.First(entry => entry.Value == schemaId).Key)); + + _schemaIdMap.Add(type, schemaId); + } + + return schemaId; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistry.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistry.cs new file mode 100644 index 000000000..35534bf81 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistry.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public class SchemaRegistry : ISchemaRegistry + { + private readonly JsonSerializerSettings _jsonSerializerSettings; + private readonly IContractResolver _jsonContractResolver; + private readonly SchemaRegistryOptions _options; + private readonly SchemaIdManager _schemaIdManager; + + public SchemaRegistry( + JsonSerializerSettings jsonSerializerSettings, + SchemaRegistryOptions options = null) + { + _jsonSerializerSettings = jsonSerializerSettings; + _jsonContractResolver = _jsonSerializerSettings.ContractResolver ?? new DefaultContractResolver(); + _options = options ?? new SchemaRegistryOptions(); + _schemaIdManager = new SchemaIdManager(_options.SchemaIdSelector); + Definitions = new Dictionary(); + } + + public IDictionary Definitions { get; private set; } + + public Schema GetOrRegister(Type type) + => GetOrRegister(null, type); + + public Schema GetOrRegister(string paramName, Type type) + { + var referencedTypes = new Queue(); + var schema = CreateSchema(paramName,type, referencedTypes); + + // Ensure all referenced types have a corresponding definition + while (referencedTypes.Any()) + { + var referencedType = referencedTypes.Dequeue(); + var schemaId = _schemaIdManager.IdFor(referencedType); + if (Definitions.ContainsKey(schemaId)) continue; + + // NOTE: Add the schemaId first with a null value. This indicates a work-in-progress + // and prevents a stack overflow by ensuring the above condition is met if the same + // type ends up back on the referencedTypes queue via recursion within 'CreateInlineSchema' + Definitions.Add(schemaId, null); + Definitions[schemaId] = CreateInlineSchema(paramName, referencedType, referencedTypes); + } + + return schema; + } + + private Schema CreateSchema(Type type, Queue referencedTypes) => + CreateSchema(null, type, referencedTypes); + + + private Schema CreateSchema(string paramName, Type type, Queue referencedTypes) + { + // If Option (F#), use the type argument + if (type.IsFSharpOption()) + type = type.GetGenericArguments()[0]; + + var jsonContract = _jsonContractResolver.ResolveContract(type); + + var createReference = !_options.CustomTypeMappings.ContainsKey(type) + && type != typeof(object) + && (// Type describes an object + jsonContract is JsonObjectContract || + // Type is self-referencing + jsonContract.IsSelfReferencingArrayOrDictionary() || + // Type is enum and opt-in flag set + (type.GetTypeInfo().IsEnum && _options.UseReferencedDefinitionsForEnums)); + + return createReference + ? CreateReferenceSchema(type, referencedTypes) + : CreateInlineSchema(paramName, type, referencedTypes); + } + + private Schema CreateReferenceSchema(Type type, Queue referencedTypes) + { + referencedTypes.Enqueue(type); + return new Schema { Ref = "#/definitions/" + _schemaIdManager.IdFor(type) }; + } + + private Schema CreateInlineSchema(string paramName, Type type, Queue referencedTypes) + { + Schema schema; + + var jsonContract = _jsonContractResolver.ResolveContract(type); + + if (_options.CustomTypeMappings.ContainsKey(type)) + { + schema = _options.CustomTypeMappings[type](); + } + else + { + // TODO: Perhaps a "Chain of Responsibility" would clean this up a little? + if (jsonContract is JsonPrimitiveContract) + schema = CreatePrimitiveSchema((JsonPrimitiveContract)jsonContract); + else if (jsonContract is JsonDictionaryContract) + schema = CreateDictionarySchema(paramName,(JsonDictionaryContract)jsonContract, referencedTypes); + else if (jsonContract is JsonArrayContract) + schema = CreateArraySchema((JsonArrayContract)jsonContract, referencedTypes); + else if (jsonContract is JsonObjectContract && type != typeof(object)) + schema = CreateObjectSchema((JsonObjectContract)jsonContract, referencedTypes); + else + // None of the above, fallback to abstract "object" + schema = new Schema { Type = "object" }; + } + + var filterContext = new SchemaFilterContext(type, jsonContract, this); + foreach (var filter in _options.SchemaFilters) + { + filter.Apply(schema, filterContext); + } + + return schema; + } + + private Schema CreatePrimitiveSchema(JsonPrimitiveContract primitiveContract) + { + // If Nullable, use the type argument + var type = primitiveContract.UnderlyingType.IsNullable() + ? Nullable.GetUnderlyingType(primitiveContract.UnderlyingType) + : primitiveContract.UnderlyingType; + + if (type.GetTypeInfo().IsEnum) + return CreateEnumSchema(primitiveContract, type); + + if (PrimitiveTypeMap.ContainsKey(type)) + return PrimitiveTypeMap[type](); + + // None of the above, fallback to string + return new Schema { Type = "string" }; + } + + private Schema CreateEnumSchema(JsonPrimitiveContract primitiveContract, Type type) + { + var stringEnumConverter = primitiveContract.Converter as StringEnumConverter + ?? _jsonSerializerSettings.Converters.OfType().FirstOrDefault(); + + if (_options.DescribeAllEnumsAsStrings || stringEnumConverter != null) + { + var camelCase = _options.DescribeStringEnumsInCamelCase + || (stringEnumConverter != null && stringEnumConverter.CamelCaseText); + + var enumNames = type.GetFields(BindingFlags.Public | BindingFlags.Static) + .Select(f => + { + var name = f.Name; + + var enumMemberAttribute = f.GetCustomAttributes().OfType().FirstOrDefault(); + if (enumMemberAttribute != null && enumMemberAttribute.Value != null) + { + name = enumMemberAttribute.Value; + } + + return camelCase ? name.ToCamelCase() : name; + }); + + return new Schema + { + Type = "string", + Enum = enumNames.ToArray() + }; + } + + return new Schema + { + Type = "integer", + Format = "int32", + Enum = Enum.GetValues(type).Cast().ToArray() + }; + } + + private Schema CreateDictionarySchema(string paramName, JsonDictionaryContract dictionaryContract, Queue referencedTypes) + { + var keyType = dictionaryContract.DictionaryKeyType ?? typeof(object); + var valueType = dictionaryContract.DictionaryValueType ?? typeof(object); + + if (keyType.GetTypeInfo().IsEnum) + { + return new Schema + { + Type = "object", + Properties = Enum.GetNames(keyType).ToDictionary( + (name) => dictionaryContract.DictionaryKeyResolver(name), + (name) => CreateSchema(valueType, referencedTypes) + ) + }; + } + else if(!string.IsNullOrEmpty(paramName)) + { + return new Schema + { + Type = "object", + Properties = new Dictionary { {paramName, + CreateSchema(valueType, referencedTypes) } } + + }; + } + else + { + return new Schema + { + Type = "object", + AdditionalProperties = CreateSchema(valueType, referencedTypes) + }; + } + } + + private Schema CreateArraySchema(JsonArrayContract arrayContract, Queue referencedTypes) + { + var type = arrayContract.UnderlyingType; + var itemType = arrayContract.CollectionItemType ?? typeof(object); + + var isASet = (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(ISet<>) + || type.GetInterfaces().Any(i => i.GetTypeInfo().IsGenericType && i.GetGenericTypeDefinition() == typeof(ISet<>))); + + return new Schema + { + Type = "array", + Items = CreateSchema(itemType, referencedTypes), + UniqueItems = isASet + }; + } + + private Schema CreateObjectSchema(JsonObjectContract jsonContract, Queue referencedTypes) + { + var applicableJsonProperties = jsonContract.Properties + .Where(prop => !prop.Ignored) + .Where(prop => !(_options.IgnoreObsoleteProperties && prop.IsObsolete())) + .Select(prop => prop); + + var required = applicableJsonProperties + .Where(prop => prop.IsRequired()) + .Select(propInfo => propInfo.PropertyName) + .ToList(); + + var hasExtensionData = jsonContract.ExtensionDataValueType != null; + + var properties = applicableJsonProperties + .ToDictionary( + prop => prop.PropertyName, + prop => CreatePropertySchema(prop, referencedTypes)); + + var schema = new Schema + { + Required = required.Any() ? required : null, // required can be null but not empty + Properties = properties, + AdditionalProperties = hasExtensionData ? new Schema { Type = "object" } : null, + Type = "object", + }; + + return schema; + } + + private Schema CreatePropertySchema(JsonProperty jsonProperty, Queue referencedTypes) + { + var schema = CreateSchema(jsonProperty.PropertyType, referencedTypes); + + if (!jsonProperty.Writable) + schema.ReadOnly = true; + + if (jsonProperty.TryGetMemberInfo(out MemberInfo memberInfo)) + schema.AssignAttributeMetadata(memberInfo.GetCustomAttributes(true)); + + return schema; + } + + private static readonly Dictionary> PrimitiveTypeMap = new Dictionary> + { + { typeof(short), () => new Schema { Type = "integer", Format = "int32" } }, + { typeof(ushort), () => new Schema { Type = "integer", Format = "int32" } }, + { typeof(int), () => new Schema { Type = "integer", Format = "int32" } }, + { typeof(uint), () => new Schema { Type = "integer", Format = "int32" } }, + { typeof(long), () => new Schema { Type = "integer", Format = "int64" } }, + { typeof(ulong), () => new Schema { Type = "integer", Format = "int64" } }, + { typeof(float), () => new Schema { Type = "number", Format = "float" } }, + { typeof(double), () => new Schema { Type = "number", Format = "double" } }, + { typeof(decimal), () => new Schema { Type = "number", Format = "double" } }, + { typeof(byte), () => new Schema { Type = "integer", Format = "int32" } }, + { typeof(sbyte), () => new Schema { Type = "integer", Format = "int32" } }, + { typeof(byte[]), () => new Schema { Type = "string", Format = "byte" } }, + { typeof(sbyte[]), () => new Schema { Type = "string", Format = "byte" } }, + { typeof(bool), () => new Schema { Type = "boolean" } }, + { typeof(DateTime), () => new Schema { Type = "string", Format = "date-time" } }, + { typeof(DateTimeOffset), () => new Schema { Type = "string", Format = "date-time" } }, + { typeof(Guid), () => new Schema { Type = "string", Format = "uuid" } } + }; + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistryFactory.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistryFactory.cs new file mode 100644 index 000000000..2e3803854 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistryFactory.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; + +namespace Surging.Core.SwaggerGen +{ + public class SchemaRegistryFactory : ISchemaRegistryFactory + { + private readonly JsonSerializerSettings _jsonSerializerSettings; + private readonly SchemaRegistryOptions _schemaRegistryOptions; + + public SchemaRegistryFactory( + IOptions mvcJsonOptionsAccessor, + IOptions schemaRegistryOptionsAccessor) + : this(mvcJsonOptionsAccessor.Value.SerializerSettings, schemaRegistryOptionsAccessor.Value) + { } + + public SchemaRegistryFactory( + JsonSerializerSettings jsonSerializerSettings, + SchemaRegistryOptions schemaRegistryOptions) + { + _jsonSerializerSettings = jsonSerializerSettings; + _schemaRegistryOptions = schemaRegistryOptions; + } + + public ISchemaRegistry Create() + { + return new SchemaRegistry(_jsonSerializerSettings, _schemaRegistryOptions); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistryOptions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistryOptions.cs new file mode 100644 index 000000000..ed5fdd7d6 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SchemaRegistryOptions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public class SchemaRegistryOptions + { + public SchemaRegistryOptions() + { + CustomTypeMappings = new Dictionary>(); + SchemaIdSelector = (type) => type.FriendlyId(IgnoreFullyQualified); + SchemaFilters = new List(); + } + + public IDictionary> CustomTypeMappings { get; set; } + + public bool DescribeAllEnumsAsStrings { get; set; } + + public bool DescribeStringEnumsInCamelCase { get; set; } + + public bool UseReferencedDefinitionsForEnums { get; set; } + + public Func SchemaIdSelector { get; set; } + + public bool IgnoreFullyQualified { get; set; } + + public bool IgnoreObsoleteProperties { get; set; } + + public IList SchemaFilters { get; set; } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/StringExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/StringExtensions.cs new file mode 100644 index 000000000..53991476e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/StringExtensions.cs @@ -0,0 +1,17 @@ +namespace Surging.Core.SwaggerGen +{ + internal static class StringExtensions + { + internal static string ToCamelCase(this string value) + { + if (string.IsNullOrEmpty(value)) return value; + return char.ToLowerInvariant(value[0]) + value.Substring(1); + } + + internal static string ToTitleCase(this string value) + { + if (string.IsNullOrEmpty(value)) return value; + return char.ToUpperInvariant(value[0]) + value.Substring(1); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SwaggerGenerator.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SwaggerGenerator.cs new file mode 100644 index 000000000..2fe04222b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SwaggerGenerator.cs @@ -0,0 +1,664 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Reflection; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Surging.Core.Swagger; +using Surging.Core.CPlatform.Runtime.Server; +using Microsoft.Extensions.DependencyInjection; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Utilities; +using Autofac; +using Microsoft.Extensions.Primitives; +using System.Threading.Tasks; +using Surging.Core.CPlatform.Messages; +using Surging.Core.CPlatform.Runtime.Server.Implementation.ServiceDiscovery.Attributes; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; + +namespace Surging.Core.SwaggerGen +{ + public class SwaggerGenerator : ISwaggerProvider + { + private readonly IApiDescriptionGroupCollectionProvider _apiDescriptionsProvider; + private readonly ISchemaRegistryFactory _schemaRegistryFactory; + private readonly SwaggerGeneratorOptions _options; + private readonly IServiceEntryProvider _serviceEntryProvider; + + public SwaggerGenerator( + IApiDescriptionGroupCollectionProvider apiDescriptionsProvider, + ISchemaRegistryFactory schemaRegistryFactory, + IOptions optionsAccessor) + : this (apiDescriptionsProvider, schemaRegistryFactory, optionsAccessor.Value) + { } + + public SwaggerGenerator( + IApiDescriptionGroupCollectionProvider apiDescriptionsProvider, + ISchemaRegistryFactory schemaRegistryFactory, + SwaggerGeneratorOptions options) + { + _apiDescriptionsProvider = apiDescriptionsProvider; + _schemaRegistryFactory = schemaRegistryFactory; + _options = options ?? new SwaggerGeneratorOptions(); + _serviceEntryProvider = ServiceLocator.Current.Resolve(); + } + + public SwaggerDocument GetSwagger( + string documentName, + string host = null, + string basePath = null, + string[] schemes = null) + { + if (!_options.SwaggerDocs.TryGetValue(documentName, out Info info)) + throw new UnknownSwaggerDocument(documentName); + + + var mapRoutePaths = Swagger.AppConfig.SwaggerConfig.Options?.MapRoutePaths; + var entries = _serviceEntryProvider.GetALLEntries(); + if (mapRoutePaths != null) + { + foreach (var path in mapRoutePaths) + { + var entry = entries.Where(p => p.RoutePath == path.SourceRoutePath).FirstOrDefault(); + if (entry != null) + { + entry.RoutePath = path.TargetRoutePath; + entry.Descriptor.RoutePath = path.TargetRoutePath; + } + } + } + entries = entries + .Where(apiDesc => _options.DocInclusionPredicateV2(documentName, apiDesc)); + + var schemaRegistry = _schemaRegistryFactory.Create(); + + var swaggerDoc = new SwaggerDocument + { + Info = info, + Host = host, + BasePath = basePath, + Schemes = schemes, + Paths = CreatePathItems(entries, schemaRegistry), + Definitions = schemaRegistry.Definitions, + SecurityDefinitions = _options.SecurityDefinitions.Any() ? _options.SecurityDefinitions : null, + Security = _options.SecurityRequirements.Any() ? _options.SecurityRequirements : null + }; + + return swaggerDoc; + } + + private Dictionary CreatePathItems( + IEnumerable apiDescriptions, + ISchemaRegistry schemaRegistry) + { + + return apiDescriptions + .OrderBy(p => p.RoutePath) + .GroupBy(apiDesc => apiDesc.Descriptor.RoutePath) + .ToDictionary(entry => + entry.Key.IndexOf("/") == 0 ? entry.Key : $"/{entry.Key}" + , entry => CreatePathItem(entry, schemaRegistry)); + } + + private Dictionary CreatePathItems( + IEnumerable apiDescriptions, + ISchemaRegistry schemaRegistry) + { + return apiDescriptions + .OrderBy(_options.SortKeySelector) + .GroupBy(apiDesc => apiDesc.RelativePathSansQueryString()) + .ToDictionary(group => "/" + group.Key, group => CreatePathItem(group, schemaRegistry)); + } + + private PathItem CreatePathItem( + IEnumerable apiDescriptions, + ISchemaRegistry schemaRegistry) + { + var pathItem = new PathItem(); + + // Group further by http method + var perMethodGrouping = apiDescriptions + .GroupBy(apiDesc => apiDesc.HttpMethod); + + foreach (var group in perMethodGrouping) + { + var httpMethod = group.Key; + + if (httpMethod == null) + throw new NotSupportedException(string.Format( + "Ambiguous HTTP method for action - {0}. " + + "Actions require an explicit HttpMethod binding for Swagger 2.0", + group.First().ActionDescriptor.DisplayName)); + + if (group.Count() > 1 && _options.ConflictingActionsResolver == null) + throw new NotSupportedException(string.Format( + "HTTP method \"{0}\" & path \"{1}\" overloaded by actions - {2}. " + + "Actions require unique method/path combination for Swagger 2.0. Use ConflictingActionsResolver as a workaround", + httpMethod, + group.First().RelativePathSansQueryString(), + string.Join(",", group.Select(apiDesc => apiDesc.ActionDescriptor.DisplayName)))); + + var apiDescription = (group.Count() > 1) ? _options.ConflictingActionsResolver(group) : group.Single(); + + switch (httpMethod) + { + case "GET": + pathItem.Get = CreateOperation(apiDescription, schemaRegistry); + break; + case "PUT": + pathItem.Put = CreateOperation(apiDescription, schemaRegistry); + break; + case "POST": + pathItem.Post = CreateOperation(apiDescription, schemaRegistry); + break; + case "DELETE": + pathItem.Delete = CreateOperation(apiDescription, schemaRegistry); + break; + case "OPTIONS": + pathItem.Options = CreateOperation(apiDescription, schemaRegistry); + break; + case "HEAD": + pathItem.Head = CreateOperation(apiDescription, schemaRegistry); + break; + case "PATCH": + pathItem.Patch = CreateOperation(apiDescription, schemaRegistry); + break; + } + } + + return pathItem; + } + + private PathItem CreatePathItem( + IEnumerable serviceEntries, ISchemaRegistry schemaRegistry) + { + var pathItem = new PathItem(); + foreach (var entry in serviceEntries) + { + var methodInfo = entry.Type.GetTypeInfo().DeclaredMethods.Where(p => p.Name == entry.MethodName).FirstOrDefault(); + var parameterInfo = methodInfo.GetParameters(); + + if (entry.Methods.Count() ==0) + { + if (parameterInfo != null && parameterInfo.Any(p => + !UtilityType.ConvertibleType.GetTypeInfo().IsAssignableFrom(p.ParameterType))) + pathItem.Post = CreateOperation(entry, methodInfo, schemaRegistry); + else + pathItem.Get = CreateOperation(entry, methodInfo, schemaRegistry); + } + else + { + foreach (var httpMethod in entry.Methods) + { + switch (httpMethod) + { + case "GET": + pathItem.Get = CreateOperation(entry, methodInfo, schemaRegistry); + break; + case "PUT": + pathItem.Put = CreateOperation(entry, methodInfo, schemaRegistry); + break; + case "POST": + pathItem.Post = CreateOperation(entry, methodInfo, schemaRegistry); + break; + case "DELETE": + pathItem.Delete = CreateOperation(entry, methodInfo, schemaRegistry); + break; + case "OPTIONS": + pathItem.Options = CreateOperation(entry, methodInfo, schemaRegistry); + break; + case "HEAD": + pathItem.Head = CreateOperation(entry, methodInfo, schemaRegistry); + break; + case "PATCH": + pathItem.Patch = CreateOperation(entry, methodInfo, schemaRegistry); + break; + } + } + } + } + return pathItem; + } + + private Operation CreateOperation(ServiceEntry serviceEntry, MethodInfo methodInfo, ISchemaRegistry schemaRegistry) + { + var customAttributes = Enumerable.Empty(); + if (methodInfo !=null) + { + customAttributes = methodInfo.GetCustomAttributes(true) + .Union(methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true)); + } + var isDeprecated = customAttributes.Any(attr => attr.GetType() == typeof(ObsoleteAttribute)); + + var operation = new Operation + { + Tags = new[] { serviceEntry.Type.Name }, + OperationId = serviceEntry.Descriptor.Id, + Parameters= CreateParameters(serviceEntry, methodInfo,schemaRegistry), + Deprecated = isDeprecated ? true : (bool?)null, + Responses = CreateResponses(serviceEntry,methodInfo, schemaRegistry), + + }; + + var filterContext = new OperationFilterContext( + null, + schemaRegistry, + methodInfo,serviceEntry); + + foreach (var filter in _options.OperationFilters) + { + filter.Apply(operation, filterContext); + } + return operation; + } + + private Operation CreateOperation( + ApiDescription apiDescription, + ISchemaRegistry schemaRegistry) + { + // Try to retrieve additional metadata that's not provided by ApiExplorer + MethodInfo methodInfo; + var customAttributes = Enumerable.Empty(); + + if (apiDescription.TryGetMethodInfo(out methodInfo)) + { + customAttributes = methodInfo.GetCustomAttributes(true) + .Union(methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true)); + } + + var isDeprecated = customAttributes.Any(attr => attr.GetType() == typeof(ObsoleteAttribute)); + + var operation = new Operation + { + OperationId = _options.OperationIdSelector(apiDescription), + Tags = _options.TagsSelector(apiDescription), + Consumes = CreateConsumes(apiDescription, customAttributes), + Produces = CreateProduces(apiDescription, customAttributes), + Parameters = CreateParameters(apiDescription, schemaRegistry), + Responses = CreateResponses(apiDescription, schemaRegistry), + Deprecated = isDeprecated ? true : (bool?)null + }; + + // Assign default value for Consumes if not yet assigned AND operation contains form params + if (operation.Consumes.Count() == 0 && operation.Parameters.Any(p => p.In == "formData")) + { + operation.Consumes.Add("multipart/form-data"); + } + + var filterContext = new OperationFilterContext( + apiDescription, + schemaRegistry, + methodInfo); + + foreach (var filter in _options.OperationFilters) + { + filter.Apply(operation, filterContext); + } + + return operation; + } + + private IList CreateConsumes(ApiDescription apiDescription, IEnumerable customAttributes) + { + var consumesAttribute = customAttributes.OfType().FirstOrDefault(); + + var mediaTypes = (consumesAttribute != null) + ? consumesAttribute.ContentTypes + : apiDescription.SupportedRequestFormats + .Select(apiRequestFormat => apiRequestFormat.MediaType); + + return mediaTypes.ToList(); + } + + private IList CreateProduces(ApiDescription apiDescription, IEnumerable customAttributes) + { + var producesAttribute = customAttributes.OfType().FirstOrDefault(); + + var mediaTypes = (producesAttribute != null) + ? producesAttribute.ContentTypes + : apiDescription.SupportedResponseTypes + .SelectMany(apiResponseType => apiResponseType.ApiResponseFormats) + .Select(apiResponseFormat => apiResponseFormat.MediaType) + .Distinct(); + + return mediaTypes.ToList(); + } + + private IList CreateParameters( + ApiDescription apiDescription, + ISchemaRegistry schemaRegistry) + { + var applicableParamDescriptions = apiDescription.ParameterDescriptions + .Where(paramDesc => + { + return paramDesc.Source.IsFromRequest + && (paramDesc.ModelMetadata == null || paramDesc.ModelMetadata.IsBindingAllowed); + }); + + return applicableParamDescriptions + .Select(paramDesc => CreateParameter(apiDescription, paramDesc, schemaRegistry)) + .ToList(); + } + + private IList CreateParameters(ServiceEntry serviceEntry, MethodInfo methodInfo, ISchemaRegistry schemaRegistry) + { + ParameterInfo[] parameterInfo = null; + if (methodInfo != null) + { + parameterInfo = methodInfo.GetParameters(); + + }; + if (parameterInfo.Count() > 1) + { + return parameterInfo != null && parameterInfo.Any(p => + !UtilityType.ConvertibleType.GetTypeInfo().IsAssignableFrom(p.ParameterType) && p.ParameterType.Name != "HttpFormCollection") + ? new List { CreateServiceKeyParameter() }.Union(new List { CreateBodyParameter(parameterInfo, schemaRegistry) }).ToList() : + new List { CreateServiceKeyParameter() }.Union(parameterInfo.Select(p => CreateNonBodyParameter(serviceEntry, p, schemaRegistry))).ToList(); + } + else + { + return parameterInfo != null && parameterInfo.Any(p => + !UtilityType.ConvertibleType.GetTypeInfo().IsAssignableFrom(p.ParameterType) && p.ParameterType.Name != "HttpFormCollection") + ? new List { CreateServiceKeyParameter() }.Union(parameterInfo.Select(p => CreateBodyParameter(p, schemaRegistry))).ToList() : + new List { CreateServiceKeyParameter() }.Union(parameterInfo.Select(p => CreateNonBodyParameter(serviceEntry, p, schemaRegistry))).ToList(); + } + } + + private IParameter CreateBodyParameter(ParameterInfo parameterInfo, ISchemaRegistry schemaRegistry) + { + + var schema = schemaRegistry.GetOrRegister(parameterInfo.Name,typeof(IDictionary<,>).MakeGenericType(typeof(string), parameterInfo.ParameterType)); + return new BodyParameter { Name = parameterInfo.Name,Schema=schema, Required = true }; + } + + private IParameter CreateBodyParameter(ParameterInfo[] parameterInfo, ISchemaRegistry schemaRegistry) + { + var schema = schemaRegistry.GetOrRegister(parameterInfo[0].Name, typeof(IDictionary<,>).MakeGenericType(typeof(string), parameterInfo[0].ParameterType)); + for (int i = 1; i < parameterInfo.Length; i++) + schema.Properties.Add(parameterInfo[i].Name, (schemaRegistry.GetOrRegister(null, parameterInfo[i].ParameterType))); + return new BodyParameter { Name = "parameters", Schema = schema, Required = true }; + } + + private IParameter CreateServiceKeyParameter() + { + var nonBodyParam = new NonBodyParameter + { + Name = "servicekey", + In = "query", + Required = false, + }; + var schema = new Schema(); + schema.Description = "ServiceKey"; + nonBodyParam.PopulateFrom(schema); + return nonBodyParam; + } + + private IParameter CreateNonBodyParameter(ServiceEntry serviceEntry, ParameterInfo parameterInfo, ISchemaRegistry schemaRegistry) + { + string reg = @"(?<={)[^{}]*(?=})"; + var nonBodyParam = new NonBodyParameter + { + Name = parameterInfo.Name, + In = "query", + Required = true, + }; + if (Regex.IsMatch(serviceEntry.RoutePath, reg) && GetParameters(serviceEntry.RoutePath).Contains(parameterInfo.Name)) + { + nonBodyParam.In = "path"; + } + + if (parameterInfo.ParameterType == null) + { + nonBodyParam.Type = "string"; + } + else if (typeof(IEnumerable>).IsAssignableFrom(parameterInfo.ParameterType) && + parameterInfo.ParameterType.Name== "HttpFormCollection") + { + nonBodyParam.Type = "file"; + nonBodyParam.In = "formData"; + } + else + { + // Retrieve a Schema object for the type and copy common fields onto the parameter + var schema = schemaRegistry.GetOrRegister(parameterInfo.ParameterType); + + // NOTE: While this approach enables re-use of SchemaRegistry logic, it introduces complexity + // and constraints elsewhere (see below) and needs to be refactored! + + if (schema.Ref != null) + { + // The registry created a referenced Schema that needs to be located. This means it's not neccessarily + // exclusive to this parameter and so, we can't assign any parameter specific attributes or metadata. + schema = schemaRegistry.Definitions[schema.Ref.Replace("#/definitions/", string.Empty)]; + } + else + { + // It's a value Schema. This means it's exclusive to this parameter and so, we can assign + // parameter specific attributes and metadata. Yep - it's hacky! + schema.Default = (parameterInfo != null && parameterInfo.IsOptional) + ? parameterInfo.DefaultValue + : null; + } + + nonBodyParam.PopulateFrom(schema); + } + return nonBodyParam; + } + + private static List GetParameters(string text) + { + var matchVale = new List(); + string Reg = @"(?<={)[^{}]*(?=})"; + string key = string.Empty; + foreach (Match m in Regex.Matches(text, Reg)) + { + matchVale.Add(m.Value); + } + return matchVale; + } + + private IParameter CreateParameter( + ApiDescription apiDescription, + ApiParameterDescription apiParameterDescription, + ISchemaRegistry schemaRegistry) + { + // Try to retrieve additional metadata that's not directly provided by ApiExplorer + ParameterInfo parameterInfo = null; + PropertyInfo propertyInfo = null; + var customAttributes = Enumerable.Empty(); + + if (apiParameterDescription.TryGetParameterInfo(apiDescription, out parameterInfo)) + customAttributes = parameterInfo.GetCustomAttributes(true); + else if (apiParameterDescription.TryGetPropertyInfo(out propertyInfo)) + customAttributes = propertyInfo.GetCustomAttributes(true); + + var name = _options.DescribeAllParametersInCamelCase + ? apiParameterDescription.Name.ToCamelCase() + : apiParameterDescription.Name; + + var isRequired = customAttributes.Any(attr => + new[] { typeof(RequiredAttribute), typeof(BindRequiredAttribute) }.Contains(attr.GetType())); + + var parameter = (apiParameterDescription.Source == BindingSource.Body) + ? CreateBodyParameter( + apiParameterDescription, + name, + isRequired, + schemaRegistry) + : CreateNonBodyParameter( + apiParameterDescription, + parameterInfo, + customAttributes, + name, + isRequired, + schemaRegistry); + + var filterContext = new ParameterFilterContext( + apiParameterDescription, + schemaRegistry, + parameterInfo, + propertyInfo); + + foreach (var filter in _options.ParameterFilters) + { + filter.Apply(parameter, filterContext); + } + + return parameter; + } + + private IParameter CreateBodyParameter( + ApiParameterDescription apiParameterDescription, + string name, + bool isRequired, + ISchemaRegistry schemaRegistry) + { + var schema = schemaRegistry.GetOrRegister(apiParameterDescription.Type); + + return new BodyParameter { Name = name, Schema = schema, Required = isRequired }; + } + + private IParameter CreateNonBodyParameter( + ApiParameterDescription apiParameterDescription, + ParameterInfo parameterInfo, + IEnumerable customAttributes, + string name, + bool isRequired, + ISchemaRegistry schemaRegistry) + { + var location = ParameterLocationMap.ContainsKey(apiParameterDescription.Source) + ? ParameterLocationMap[apiParameterDescription.Source] + : "query"; + + var nonBodyParam = new NonBodyParameter + { + Name = name, + In = location, + Required = (location == "path") ? true : isRequired, + }; + + if (apiParameterDescription.Type == null) + { + nonBodyParam.Type = "string"; + } + else if (typeof(IFormFile).IsAssignableFrom(apiParameterDescription.Type)) + { + nonBodyParam.Type = "file"; + } + else + { + // Retrieve a Schema object for the type and copy common fields onto the parameter + var schema = schemaRegistry.GetOrRegister(apiParameterDescription.Type); + + // NOTE: While this approach enables re-use of SchemaRegistry logic, it introduces complexity + // and constraints elsewhere (see below) and needs to be refactored! + + if (schema.Ref != null) + { + // The registry created a referenced Schema that needs to be located. This means it's not neccessarily + // exclusive to this parameter and so, we can't assign any parameter specific attributes or metadata. + schema = schemaRegistry.Definitions[schema.Ref.Replace("#/definitions/", string.Empty)]; + } + else + { + // It's a value Schema. This means it's exclusive to this parameter and so, we can assign + // parameter specific attributes and metadata. Yep - it's hacky! + schema.AssignAttributeMetadata(customAttributes); + schema.Default = (parameterInfo != null && parameterInfo.IsOptional) + ? parameterInfo.DefaultValue + : null; + } + + nonBodyParam.PopulateFrom(schema); + } + + return nonBodyParam; + } + + private IDictionary CreateResponses( + ApiDescription apiDescription, + ISchemaRegistry schemaRegistry) + { + var supportedApiResponseTypes = apiDescription.SupportedResponseTypes + .DefaultIfEmpty(new ApiResponseType { StatusCode = 200 }); + + return supportedApiResponseTypes + .ToDictionary( + apiResponseType => apiResponseType.IsDefaultResponse() ? "default" : apiResponseType.StatusCode.ToString(), + apiResponseType => CreateResponse(apiResponseType, schemaRegistry)); + } + + private IDictionary CreateResponses( + ServiceEntry apiDescription, + MethodInfo methodInfo, + ISchemaRegistry schemaRegistry) + { + return new Dictionary { + { "200", CreateResponse(apiDescription,methodInfo, schemaRegistry) } + }; + } + + private Response CreateResponse(ServiceEntry apiResponseType,MethodInfo methodInfo, ISchemaRegistry schemaRegistry) + { + var description = ResponseDescriptionMap + .FirstOrDefault((entry) => Regex.IsMatch("200", entry.Key)) + .Value; + + return new Response + { + Description = description, + Schema = (methodInfo.ReturnType != typeof(Task) && methodInfo.ReturnType != typeof(void)) + ? schemaRegistry.GetOrRegister(typeof(HttpResultMessage<>).MakeGenericType(methodInfo.ReturnType.GenericTypeArguments)) + : null + }; + } + + private Response CreateResponse(ApiResponseType apiResponseType, ISchemaRegistry schemaRegistry) + { + var description = ResponseDescriptionMap + .FirstOrDefault((entry) => Regex.IsMatch(apiResponseType.StatusCode.ToString(), entry.Key)) + .Value; + + return new Response + { + Description = description, + Schema = (apiResponseType.Type != null && apiResponseType.Type != typeof(void)) + ? schemaRegistry.GetOrRegister(apiResponseType.Type) + : null + }; + } + + private static Dictionary ParameterLocationMap = new Dictionary + { + { BindingSource.Form, "formData" }, + { BindingSource.FormFile, "formData" }, + { BindingSource.Body, "body" }, + { BindingSource.Header, "header" }, + { BindingSource.Path, "path" }, + { BindingSource.Query, "query" } + }; + + private static readonly Dictionary ResponseDescriptionMap = new Dictionary + { + { "1\\d{2}", "Information" }, + { "2\\d{2}", "Success" }, + { "3\\d{2}", "Redirect" }, + { "400", "Bad Request" }, + { "401", "Unauthorized" }, + { "403", "Forbidden" }, + { "404", "Not Found" }, + { "405", "Method Not Allowed" }, + { "406", "Not Acceptable" }, + { "408", "Request Timeout" }, + { "409", "Conflict" }, + { "4\\d{2}", "Client Error" }, + { "5\\d{2}", "Server Error" } + }; + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SwaggerGeneratorOptions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SwaggerGeneratorOptions.cs new file mode 100644 index 000000000..10d95778d --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/SwaggerGeneratorOptions.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public class SwaggerGeneratorOptions + { + public SwaggerGeneratorOptions() + { + SwaggerDocs = new Dictionary(); + DocInclusionPredicate = DefaultDocInclusionPredicate; + DocInclusionPredicateV2 = DefaultDocInclusionPredicateV2; + OperationIdSelector = DefaultOperationIdSelector; + TagsSelector = DefaultTagsSelector; + SortKeySelector = DefaultSortKeySelector; + SecurityDefinitions = new Dictionary(); + SecurityRequirements = new List>>(); + ParameterFilters = new List(); + OperationFilters = new List(); + DocumentFilters = new List(); + } + + public IDictionary SwaggerDocs { get; set; } + + public Func DocInclusionPredicate { get; set; } + + public Func DocInclusionPredicateV2 { get; set; } + + public bool IgnoreObsoleteActions { get; set; } + + public Func, ApiDescription> ConflictingActionsResolver { get; set; } + + public Func OperationIdSelector { get; set; } + + public Func> TagsSelector { get; set; } + + public Func SortKeySelector { get; set; } + + public bool DescribeAllParametersInCamelCase { get; set; } + + public IDictionary SecurityDefinitions { get; set; } + + public IList>> SecurityRequirements { get; set; } + + public IList ParameterFilters { get; set; } + + public List OperationFilters { get; set; } + + public IList DocumentFilters { get; set; } + + private bool DefaultDocInclusionPredicate(string documentName, ApiDescription apiDescription) + { + return apiDescription.GroupName == null || apiDescription.GroupName == documentName; + } + + private bool DefaultDocInclusionPredicateV2(string documentName, ServiceEntry apiDescription) + { + var assembly = apiDescription.Type.Assembly; + + var versions = assembly + .GetCustomAttributes(true) + .OfType(); + return versions != null; + } + + private string DefaultOperationIdSelector(ApiDescription apiDescription) + { + var routeName = apiDescription.ActionDescriptor.AttributeRouteInfo?.Name; + if (routeName != null) return routeName; + + if (apiDescription.TryGetMethodInfo(out MethodInfo methodInfo)) return methodInfo.Name; + + return null; + } + + private IList DefaultTagsSelector(ApiDescription apiDescription) + { + return new[] { apiDescription.ActionDescriptor.RouteValues["controller"] }; + } + + private string DefaultSortKeySelector(ApiDescription apiDescription) + { + return TagsSelector(apiDescription).First(); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/TypeExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/TypeExtensions.cs new file mode 100644 index 000000000..995919fdb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/Generator/TypeExtensions.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.SwaggerGen +{ + public static class TypeExtensions + { + public static string FriendlyId(this Type type, bool fullyQualified = false) + { + var typeName = fullyQualified + ? type.FullNameSansTypeArguments().Replace("+", ".") + : type.Name; + + if (type.GetTypeInfo().IsGenericType) + { + var genericArgumentIds = type.GetGenericArguments() + .Select(t => t.FriendlyId(fullyQualified)) + .ToArray(); + + return new StringBuilder(typeName) + .Replace(string.Format("`{0}", genericArgumentIds.Count()), string.Empty) + .Append(string.Format("[{0}]", string.Join(",", genericArgumentIds).TrimEnd(','))) + .ToString(); + } + + return typeName; + } + + internal static bool IsNullable(this Type type) + { + return Nullable.GetUnderlyingType(type) != null; + } + + internal static bool IsFSharpOption(this Type type) + { + return type.FullNameSansTypeArguments() == "Microsoft.FSharp.Core.FSharpOption`1"; + } + + private static string FullNameSansTypeArguments(this Type type) + { + if (string.IsNullOrEmpty(type.FullName)) return string.Empty; + + var fullName = type.FullName; + var chopIndex = fullName.IndexOf("[["); + return (chopIndex == -1) ? fullName : fullName.Substring(0, chopIndex); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs new file mode 100644 index 000000000..0bddfd9a9 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs @@ -0,0 +1,53 @@ +using System.Xml.XPath; +using System.Linq; +using Microsoft.AspNetCore.Mvc.Controllers; +using System.Collections.Generic; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public class XmlCommentsDocumentFilter : IDocumentFilter + { + private const string MemberXPath = "/doc/members/member[@name='{0}']"; + private const string SummaryTag = "summary"; + + private readonly XPathNavigator _xmlNavigator; + + public XmlCommentsDocumentFilter(XPathDocument xmlDoc) + { + _xmlNavigator = xmlDoc.CreateNavigator(); + } + + public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) + { + // Collect (unique) controller names and types in a dictionary + var controllerNamesAndTypes = context.ApiDescriptions + .Select(apiDesc => apiDesc.ActionDescriptor as ControllerActionDescriptor) + .SkipWhile(actionDesc => actionDesc == null) + .GroupBy(actionDesc => actionDesc.ControllerName) + .ToDictionary(grp => grp.Key, grp => grp.Last().ControllerTypeInfo.AsType()); + + foreach (var nameAndType in controllerNamesAndTypes) + { + var memberName = XmlCommentsMemberNameHelper.GetMemberNameForType(nameAndType.Value); + var typeNode = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName)); + + if (typeNode != null) + { + var summaryNode = typeNode.SelectSingleNode(SummaryTag); + if (summaryNode != null) + { + if (swaggerDoc.Tags == null) + swaggerDoc.Tags = new List(); + + swaggerDoc.Tags.Add(new Tag + { + Name = nameAndType.Key, + Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml) + }); + } + } + } + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsMemberNameHelper.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsMemberNameHelper.cs new file mode 100644 index 000000000..6a79b76bb --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsMemberNameHelper.cs @@ -0,0 +1,84 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.SwaggerGen +{ + public class XmlCommentsMemberNameHelper + { + public static string GetMemberNameForMethod(MethodInfo method) + { + var builder = new StringBuilder("M:"); + + builder.Append(QualifiedNameFor(method.DeclaringType)); + builder.Append($".{method.Name}"); + + var parameters = method.GetParameters(); + if (parameters.Any()) + { + var parametersNames = parameters.Select(p => + { + return p.ParameterType.IsGenericParameter + ? $"`{p.ParameterType.GenericParameterPosition}" + : QualifiedNameFor(p.ParameterType, expandGenericArgs: true); + }); + builder.Append($"({string.Join(",", parametersNames)})"); + } + + return builder.ToString(); + } + + public static string GetMemberNameForType(Type type) + { + var builder = new StringBuilder("T:"); + builder.Append(QualifiedNameFor(type)); + + return builder.ToString(); + } + + public static string GetMemberNameForMember(MemberInfo memberInfo) + { + var builder = new StringBuilder(((memberInfo.MemberType & MemberTypes.Field) != 0) ? "F:" : "P:"); + builder.Append(QualifiedNameFor(memberInfo.DeclaringType)); + builder.Append($".{memberInfo.Name}"); + + return builder.ToString(); + } + + private static string QualifiedNameFor(Type type, bool expandGenericArgs = false) + { + if (type.IsArray) + return $"{QualifiedNameFor(type.GetElementType(), expandGenericArgs)}[]"; + + var builder = new StringBuilder(); + + if (!string.IsNullOrEmpty(type.Namespace)) + builder.Append($"{type.Namespace}."); + + if (type.IsNested) + builder.Append($"{type.DeclaringType.Name}."); + + if (type.IsConstructedGenericType && expandGenericArgs) + { + var nameSansGenericArgs = type.Name.Split('`').First(); + builder.Append(nameSansGenericArgs); + + var genericArgsNames = type.GetGenericArguments().Select(t => + { + return t.IsGenericParameter + ? $"`{t.GenericParameterPosition}" + : QualifiedNameFor(t, true); + }); + + builder.Append($"{{{string.Join(",", genericArgsNames)}}}"); + } + else + { + builder.Append(type.Name); + } + + return builder.ToString(); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs new file mode 100644 index 000000000..e2e4a9591 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs @@ -0,0 +1,192 @@ +using System; +using System.Linq; +using System.Xml.XPath; +using System.Reflection; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Surging.Core.Swagger; +using Surging.Core.CPlatform.Runtime.Server; + +namespace Surging.Core.SwaggerGen +{ + public class XmlCommentsOperationFilter : IOperationFilter + { + private const string MemberXPath = "/doc/members/member[@name='{0}']"; + private const string SummaryXPath = "summary"; + private const string RemarksXPath = "remarks"; + private const string ParamXPath = "param[@name='{0}']"; + private const string ResponsesXPath = "response"; + + private readonly XPathNavigator _xmlNavigator; + + public XmlCommentsOperationFilter(XPathDocument xmlDoc) + { + _xmlNavigator = xmlDoc.CreateNavigator(); + } + + public void Apply(Operation operation, OperationFilterContext context) + { + if (context.MethodInfo == null) return; + + // If method is from a constructed generic type, look for comments from the generic type method + var targetMethod = context.MethodInfo.DeclaringType.IsConstructedGenericType + ? GetGenericTypeMethodOrNullFor(context.MethodInfo) + : context.MethodInfo; + + if (targetMethod == null) return; + + var memberName = XmlCommentsMemberNameHelper.GetMemberNameForMethod(targetMethod); + var methodNode = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName)); + + if (methodNode != null) + { + ApplyMethodXmlToOperation(operation, methodNode); + ApplyParamsXmlToActionParameters(operation.Parameters, methodNode, context.ServiceEntry); + ApplyResponsesXmlToResponses(operation.Responses, methodNode.Select(ResponsesXPath)); + } + + if(context.ApiDescription !=null) + // Special handling for parameters that are bound to model properties + ApplyPropertiesXmlToPropertyParameters(operation.Parameters, context.ApiDescription); + else + ApplyPropertiesXmlToPropertyParameters(operation.Parameters, context.ServiceEntry); + } + + private MethodInfo GetGenericTypeMethodOrNullFor(MethodInfo constructedTypeMethod) + { + var constructedType = constructedTypeMethod.DeclaringType; + var genericTypeDefinition = constructedType.GetGenericTypeDefinition(); + + // Retrieve list of candidate methods that match name and parameter count + var candidateMethods = genericTypeDefinition.GetMethods() + .Where(m => + { + return (m.Name == constructedTypeMethod.Name) + && (m.GetParameters().Length == constructedTypeMethod.GetParameters().Length); + }); + + + // If inconclusive, just return null + return (candidateMethods.Count() == 1) ? candidateMethods.First() : null; + } + + private void ApplyMethodXmlToOperation(Operation operation, XPathNavigator methodNode) + { + var summaryNode = methodNode.SelectSingleNode(SummaryXPath); + if (summaryNode != null) + operation.Summary = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml); + + var remarksNode = methodNode.SelectSingleNode(RemarksXPath); + if (remarksNode != null) + operation.Description = XmlCommentsTextHelper.Humanize(remarksNode.InnerXml); + } + + private void ApplyParamsXmlToActionParameters( + IList parameters, + XPathNavigator methodNode, + ApiDescription apiDescription) + { + if (parameters == null) return; + + foreach (var parameter in parameters) + { + // Check for a corresponding action parameter? + var actionParameter = apiDescription.ActionDescriptor.Parameters + .FirstOrDefault(p => parameter.Name.Equals( + (p.BindingInfo?.BinderModelName ?? p.Name), StringComparison.OrdinalIgnoreCase)); + if (actionParameter == null) continue; + + var paramNode = methodNode.SelectSingleNode(string.Format(ParamXPath, actionParameter.Name)); + if (paramNode != null) + parameter.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml); + } + } + + private void ApplyParamsXmlToActionParameters( + IList parameters, + XPathNavigator methodNode, + ServiceEntry serviceEntry) + { + if (parameters == null) return; + + foreach (var parameter in parameters) + { + // Check for a corresponding action parameter? + var methodInfo = serviceEntry.Type.GetTypeInfo().DeclaredMethods.Where(p => p.Name == serviceEntry.MethodName).FirstOrDefault(); + var actionParameter = methodInfo.GetParameters() + .FirstOrDefault(p => parameter.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase)); + if (actionParameter == null) continue; + + var paramNode = methodNode.SelectSingleNode(string.Format(ParamXPath, actionParameter.Name)); + if (paramNode != null) + parameter.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml); + } + } + + private void ApplyResponsesXmlToResponses(IDictionary responses, XPathNodeIterator responseNodes) + { + while (responseNodes.MoveNext()) + { + var code = responseNodes.Current.GetAttribute("code", ""); + var response = responses.ContainsKey(code) + ? responses[code] + : responses[code] = new Response(); + + response.Description = XmlCommentsTextHelper.Humanize(responseNodes.Current.InnerXml); + } + } + + private void ApplyPropertiesXmlToPropertyParameters( + IList parameters, + ApiDescription apiDescription) + { + if (parameters == null) return; + + foreach (var parameter in parameters) + { + // Check for a corresponding API parameter (from ApiExplorer) that's property-bound? + var propertyParam = apiDescription.ParameterDescriptions + .Where(p => p.ModelMetadata?.ContainerType != null && p.ModelMetadata?.PropertyName != null) + .FirstOrDefault(p => parameter.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase)); + if (propertyParam == null) continue; + + var metadata = propertyParam.ModelMetadata; + var memberInfo = metadata.ContainerType.GetMember(metadata.PropertyName).FirstOrDefault(); + if (memberInfo == null) continue; + + var memberName = XmlCommentsMemberNameHelper.GetMemberNameForMember(memberInfo); + var memberNode = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName)); + if (memberNode == null) continue; + + var summaryNode = memberNode.SelectSingleNode(SummaryXPath); + if (summaryNode != null) + parameter.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml); + } + } + + private void ApplyPropertiesXmlToPropertyParameters( + IList parameters, + ServiceEntry serviceEntry) + { + if (parameters == null) return; + + foreach (var parameter in parameters) + { + var methodInfo = serviceEntry.Type.GetTypeInfo().DeclaredMethods.Where(p => p.Name == serviceEntry.MethodName).FirstOrDefault(); + var propertyParam = methodInfo.GetParameters() + .FirstOrDefault(p => parameter.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase)); + if (propertyParam == null) continue; + var memberInfo = propertyParam.Member ; + if (memberInfo == null) continue; + + var memberName = XmlCommentsMemberNameHelper.GetMemberNameForMember(memberInfo); + var memberNode = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName)); + if (memberNode == null) continue; + + var summaryNode = memberNode.SelectSingleNode(SummaryXPath); + if (summaryNode != null) + parameter.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml); + } + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs new file mode 100644 index 000000000..d9b21b67f --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs @@ -0,0 +1,66 @@ +using System.Xml.XPath; +using System.Reflection; +using Newtonsoft.Json.Serialization; +using Surging.Core.Swagger; + +namespace Surging.Core.SwaggerGen +{ + public class XmlCommentsSchemaFilter : ISchemaFilter + { + private const string MemberXPath = "/doc/members/member[@name='{0}']"; + private const string SummaryTag = "summary"; + private const string ExampleXPath = "example"; + + private readonly XPathNavigator _xmlNavigator; + + public XmlCommentsSchemaFilter(XPathDocument xmlDoc) + { + _xmlNavigator = xmlDoc.CreateNavigator(); + } + + public void Apply(Schema schema, SchemaFilterContext context) + { + var jsonObjectContract = context.JsonContract as JsonObjectContract; + if (jsonObjectContract == null) return; + + var memberName = XmlCommentsMemberNameHelper.GetMemberNameForType(context.SystemType); + var typeNode = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName)); + + if (typeNode != null) + { + var summaryNode = typeNode.SelectSingleNode(SummaryTag); + if (summaryNode != null) + schema.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml); + } + + if (schema.Properties == null) return; + foreach (var entry in schema.Properties) + { + var jsonProperty = jsonObjectContract.Properties[entry.Key]; + if (jsonProperty == null) continue; + + if (jsonProperty.TryGetMemberInfo(out MemberInfo memberInfo)) + { + ApplyPropertyComments(entry.Value, memberInfo); + } + } + } + + private void ApplyPropertyComments(Schema propertySchema, MemberInfo memberInfo) + { + var memberName = XmlCommentsMemberNameHelper.GetMemberNameForMember(memberInfo); + var memberNode = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName)); + if (memberNode == null) return; + + var summaryNode = memberNode.SelectSingleNode(SummaryTag); + if (summaryNode != null) + { + propertySchema.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml); + } + + var exampleNode = memberNode.SelectSingleNode(ExampleXPath); + if (exampleNode != null) + propertySchema.Example = XmlCommentsTextHelper.Humanize(exampleNode.InnerXml); + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsTextHelper.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsTextHelper.cs new file mode 100644 index 000000000..c36cb773e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerGen/XmlComments/XmlCommentsTextHelper.cs @@ -0,0 +1,93 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Surging.Core.SwaggerGen +{ + public static class XmlCommentsTextHelper + { + private static Regex RefTagPattern = new Regex(@"<(see|paramref) (name|cref)=""([TPF]{1}:)?(?.+?)"" ?/>"); + private static Regex CodeTagPattern = new Regex(@"(?.+?)"); + + public static string Humanize(string text) + { + if (text == null) + throw new ArgumentNullException("text"); + + return text + .NormalizeIndentation() + .HumanizeRefTags() + .HumanizeCodeTags(); + } + + private static string NormalizeIndentation(this string text) + { + string[] lines = text.Split('\n'); + string padding = GetCommonLeadingWhitespace(lines); + + int padLen = padding == null ? 0 : padding.Length; + + // remove leading padding from each line + for (int i = 0, l = lines.Length; i < l; ++i) + { + string line = lines[i].TrimEnd('\r'); // remove trailing '\r' + + if (padLen != 0 && line.Length >= padLen && line.Substring(0, padLen) == padding) + line = line.Substring(padLen); + + lines[i] = line; + } + + // remove leading empty lines, but not all leading padding + // remove all trailing whitespace, regardless + return string.Join("\r\n", lines.SkipWhile(x => string.IsNullOrWhiteSpace(x))).TrimEnd(); + } + + private static string GetCommonLeadingWhitespace(string[] lines) + { + if (null == lines) + throw new ArgumentException("lines"); + + if (lines.Length == 0) + return null; + + string[] nonEmptyLines = lines + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToArray(); + + if (nonEmptyLines.Length < 1) + return null; + + int padLen = 0; + + // use the first line as a seed, and see what is shared over all nonEmptyLines + string seed = nonEmptyLines[0]; + for (int i = 0, l = seed.Length; i < l; ++i) + { + if (!char.IsWhiteSpace(seed, i)) + break; + + if (nonEmptyLines.Any(line => line[i] != seed[i])) + break; + + ++padLen; + } + + if (padLen > 0) + return seed.Substring(0, padLen); + + return null; + } + + private static string HumanizeRefTags(this string text) + { + return RefTagPattern.Replace(text, (match) => match.Groups["display"].Value); + } + + private static string HumanizeCodeTags(this string text) + { + return CodeTagPattern.Replace(text, (match) => "{" + match.Groups["display"].Value + "}"); + } + + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerModule.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerModule.cs new file mode 100644 index 000000000..209165d62 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerModule.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Surging.Core.CPlatform; +using Surging.Core.CPlatform.Module; +using Surging.Core.CPlatform.Runtime.Server; +using Surging.Core.KestrelHttpServer; +using Surging.Core.Swagger.Builder; +using Surging.Core.Swagger.Internal; +using Surging.Core.Swagger.Swagger.Filters; +using Surging.Core.Swagger.SwaggerUI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.Swagger +{ + public class SwaggerModule: KestrelHttpModule + { + private IServiceSchemaProvider _serviceSchemaProvider; + private IServiceEntryProvider _serviceEntryProvider; + + public override void Initialize(AppModuleContext context) + { + var serviceProvider = context.ServiceProvoider; + _serviceSchemaProvider = serviceProvider.GetInstances(); + _serviceEntryProvider = serviceProvider.GetInstances(); + } + + public override void Initialize(ApplicationInitializationContext context) + { + var info = AppConfig.SwaggerConfig.Info == null + ? AppConfig.SwaggerOptions : AppConfig.SwaggerConfig.Info; + if (info != null) + { + context.Builder.UseSwagger(); + context.Builder.UseSwaggerUI(c => + { + var areaName = AppConfig.SwaggerConfig.Options?.IngressName; + c.SwaggerEndpoint($"../swagger/{info.Version}/swagger.json", info.Title, areaName); + c.SwaggerEndpoint(_serviceEntryProvider.GetALLEntries(), areaName); + }); + } + } + + public override void RegisterBuilder(ConfigurationContext context) + { + var serviceCollection = context.Services; + var info = AppConfig.SwaggerConfig.Info == null + ? AppConfig.SwaggerOptions : AppConfig.SwaggerConfig.Info; + var swaggerOptions = AppConfig.SwaggerConfig.Options; + if (info != null) + { + serviceCollection.AddSwaggerGen(options => + { + options.OperationFilter(); + options.SwaggerDoc(info.Version, info); + if (swaggerOptions != null && swaggerOptions.IgnoreFullyQualified) + options.IgnoreFullyQualified(); + options.GenerateSwaggerDoc(_serviceEntryProvider.GetALLEntries()); + options.DocInclusionPredicateV2((docName, apiDesc) => + { + if (docName == info.Version) + return true; + var assembly = apiDesc.Type.Assembly; + + var title = assembly + .GetCustomAttributes(true) + .OfType(); + + return title.Any(v => v.Title == docName); + }); + var xmlPaths = _serviceSchemaProvider.GetSchemaFilesPath(); + foreach (var xmlPath in xmlPaths) + options.IncludeXmlComments(xmlPath); + }); + } + } + + /// + /// Inject dependent third-party components + /// + /// + protected override void RegisterBuilder(ContainerBuilderWrapper builder) + { + var section = CPlatform.AppConfig.GetSection("Swagger"); + if (section.Exists()) + { + AppConfig.SwaggerOptions = section.Get(); + AppConfig.SwaggerConfig = section.Get(); + } + builder.RegisterType(typeof(DefaultServiceSchemaProvider)).As(typeof(IServiceSchemaProvider)).SingleInstance(); + + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIBuilderExtensions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIBuilderExtensions.cs new file mode 100644 index 000000000..faab0af90 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIBuilderExtensions.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Builder; +using System; + +namespace Surging.Core.Swagger.SwaggerUI +{ + public static class SwaggerUIBuilderExtensions + { + public static IApplicationBuilder UseSwaggerUI( + this IApplicationBuilder app, + Action setupAction = null) + { + if (setupAction == null) + { + // Don't pass options so it can be configured/injected via DI container instead + app.UseMiddleware(); + } + else + { + // Configure an options instance here and pass directly to the middleware + var options = new SwaggerUIOptions(); + setupAction.Invoke(options); + + app.UseMiddleware(options); + } + + return app; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIMiddleware.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIMiddleware.cs new file mode 100644 index 000000000..61dcd456c --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIMiddleware.cs @@ -0,0 +1,135 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Surging.Core.Swagger.SwaggerUI +{ + public class SwaggerUIMiddleware + { + private const string EmbeddedFileNamespace = "Surging.Core.Swagger.SwaggerUI.node_modules.swagger_ui_dist"; + + private readonly SwaggerUIOptions _options; + private readonly StaticFileMiddleware _staticFileMiddleware; + + public SwaggerUIMiddleware( + RequestDelegate next, + IHostingEnvironment hostingEnv, + ILoggerFactory loggerFactory, + IOptions optionsAccessor) + : this(next, hostingEnv, loggerFactory, optionsAccessor.Value) + { } + + public SwaggerUIMiddleware( + RequestDelegate next, + IHostingEnvironment hostingEnv, + ILoggerFactory loggerFactory, + SwaggerUIOptions options) + { + _options = options ?? new SwaggerUIOptions(); + _staticFileMiddleware = CreateStaticFileMiddleware(next, hostingEnv, loggerFactory, options); + } + + public async Task Invoke(HttpContext httpContext) + { + var httpMethod = httpContext.Request.Method; + var path = httpContext.Request.Path.Value; + + // If the RoutePrefix is requested (with or without trailing slash), redirect to index URL + if (httpMethod == "GET" && Regex.IsMatch(path, $"^/{_options.RoutePrefix}/?$")) + { + // Use relative redirect to support proxy environments + var relativeRedirectPath = path.EndsWith("/") + ? "index.html" + : $"{path.Split('/').Last()}/index.html"; + + RespondWithRedirect(httpContext.Response, relativeRedirectPath); + return; + } + + if (httpMethod == "GET" && Regex.IsMatch(path, $"/{_options.RoutePrefix}/?index.html")) + { + await RespondWithIndexHtml(httpContext.Response); + return; + } + + await _staticFileMiddleware.Invoke(httpContext); + } + + private void RespondWithRedirect(HttpResponse response, string location) + { + response.StatusCode = 301; + response.Headers["Location"] = location; + } + + private async Task RespondWithIndexHtml(HttpResponse response) + { + response.StatusCode = 200; + response.ContentType = "text/html"; + + using (var stream = _options.IndexStream()) + { + // Inject arguments before writing to response + var htmlBuilder = new StringBuilder(new StreamReader(stream).ReadToEnd()); + foreach (var entry in GetIndexArguments()) + { + htmlBuilder.Replace(entry.Key, entry.Value); + } + + await response.WriteAsync(htmlBuilder.ToString(), Encoding.UTF8); + } + } + + private IDictionary GetIndexArguments() + { + return new Dictionary() + { + { "%(DocumentTitle)", _options.DocumentTitle }, + { "%(HeadContent)", _options.HeadContent }, + { "%(ConfigObject)", SerializeToJson(_options.ConfigObject) }, + { "%(OAuthConfigObject)", SerializeToJson(_options.OAuthConfigObject) } + }; + } + + private string SerializeToJson(object obj) + { + return JsonConvert.SerializeObject(obj, new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Converters = new[] { new StringEnumConverter(true) }, + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + StringEscapeHandling = StringEscapeHandling.EscapeHtml + }); + } + + private StaticFileMiddleware CreateStaticFileMiddleware( + RequestDelegate next, + IHostingEnvironment hostingEnv, + ILoggerFactory loggerFactory, + SwaggerUIOptions options) + { + var staticFileOptions = new StaticFileOptions + { + RequestPath = string.IsNullOrEmpty(options.RoutePrefix) ? string.Empty : $"/{options.RoutePrefix}", + FileProvider = new EmbeddedFileProvider(typeof(SwaggerUIMiddleware).GetTypeInfo().Assembly, EmbeddedFileNamespace), + }; + + return new StaticFileMiddleware(next, hostingEnv, Options.Create(staticFileOptions), loggerFactory); + } + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIOptions.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIOptions.cs new file mode 100644 index 000000000..19e89b383 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIOptions.cs @@ -0,0 +1,207 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.Swagger.SwaggerUI +{ + public class SwaggerUIOptions + { + /// + /// Gets or sets a route prefix for accessing the swagger-ui + /// + public string RoutePrefix { get; set; } = "swagger"; + + /// + /// Gets or sets a Stream function for retrieving the swagger-ui page + /// + public Func IndexStream { get; set; } = () => typeof(SwaggerUIOptions).GetTypeInfo().Assembly + .GetManifestResourceStream("Surging.Core.Swagger.SwaggerUI.index.html"); + + /// + /// Gets or sets a title for the swagger-ui page + /// + public string DocumentTitle { get; set; } = "Swagger UI"; + + /// + /// Gets or sets additional content to place in the head of the swagger-ui page + /// + public string HeadContent { get; set; } = ""; + + /// + /// Gets the JavaScript config object, represented as JSON, that will be passed to the SwaggerUI + /// + public ConfigObject ConfigObject { get; set; } = new ConfigObject(); + + /// + /// Gets the JavaScript config object, represented as JSON, that will be passed to the initOAuth method + /// + public OAuthConfigObject OAuthConfigObject { get; set; } = new OAuthConfigObject(); + } + + public class ConfigObject + { + /// + /// One or more Swagger JSON endpoints (url and name) to power the UI + /// + public IEnumerable Urls { get; set; } = null; + + /// + /// If set to true, enables deep linking for tags and operations + /// + public bool DeepLinking { get; set; } = false; + + /// + /// Controls the display of operationId in operations list + /// + public bool DisplayOperationId { get; set; } = false; + + /// + /// The default expansion depth for models (set to -1 completely hide the models) + /// + public int DefaultModelsExpandDepth { get; set; } = 1; + + /// + /// The default expansion depth for the model on the model-example section + /// + public int DefaultModelExpandDepth { get; set; } = 1; + + /// + /// Controls how the model is shown when the API is first rendered. + /// (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links) + /// + public ModelRendering DefaultModelRendering { get; set; } = ModelRendering.Example; + + /// + /// Controls the display of the request duration (in milliseconds) for Try-It-Out requests + /// + public bool DisplayRequestDuration { get; set; } = false; + + /// + /// Controls the default expansion setting for the operations and tags. + /// It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing) + /// + public DocExpansion DocExpansion { get; set; } = DocExpansion.List; + + /// + /// If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations + /// that are shown. Can be an empty string or specific value, in which case filtering will be enabled using that + /// value as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag + /// + public string Filter { get; set; } = null; + + /// + /// If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations + /// + public int? MaxDisplayedTags { get; set; } = null; + + /// + /// Controls the display of vendor extension (x-) fields and values for Operations, Parameters, and Schema + /// + public bool ShowExtensions { get; set; } = false; + + /// + /// Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields and values for Parameters + /// + public bool ShowCommonExtensions { get; set; } = false; + + /// + /// OAuth redirect URL + /// + [JsonProperty("oauth2RedirectUrl")] + public string OAuth2RedirectUrl { get; set; } = null; + + /// + /// List of HTTP methods that have the Try it out feature enabled. + /// An empty array disables Try it out for all operations. This does not filter the operations from the display + /// + [JsonProperty(NullValueHandling = NullValueHandling.Include)] + public IEnumerable SupportedSubmitMethods { get; set; } = Enum.GetValues(typeof(SubmitMethod)).Cast(); + + /// + /// By default, Swagger-UI attempts to validate specs against swagger.io's online validator. + /// You can use this parameter to set a different validator URL, for example for locally deployed validators (Validator Badge). + /// Setting it to null will disable validation + /// + [JsonProperty(NullValueHandling = NullValueHandling.Include)] + public string ValidatorUrl { get; set; } = null; + + [JsonExtensionData] + public Dictionary AdditionalItems = new Dictionary(); + } + + public class UrlDescriptor + { + public string Url { get; set; } + + public string Name { get; set; } + } + + public enum ModelRendering + { + Example, + Model + } + + public enum DocExpansion + { + List, + Full, + None + } + + public enum SubmitMethod + { + Get, + Put, + Post, + Delete, + Options, + Head, + Patch, + Trace + } + + public class OAuthConfigObject + { + /// + /// Default clientId + /// + public string ClientId { get; set; } = "clientId"; + + /// + /// Default clientSecret + /// + public string ClientSecret { get; set; } = "clientSecret"; + + /// + /// Realm query parameter (for oauth1) added to authorizationUrl and tokenUrl + /// + public string Realm { get; set; } = null; + + /// + /// Application name, displayed in authorization popup + /// + public string AppName { get; set; } = null; + + /// + /// Scope separator for passing scopes, encoded before calling, default value is a space (encoded value %20) + /// + public string ScopeSeperator { get; set; } = " "; + + /// + /// Additional query parameters added to authorizationUrl and tokenUrl + /// + public Dictionary AdditionalQueryStringParams { get; set; } = null; + + /// + /// Only activated for the accessCode flow. During the authorization_code request to the tokenUrl, + /// pass the Client Password using the HTTP Basic Authentication scheme + /// (Authorization header with Basic base64encode(client_id + client_secret)) + /// + public bool UseBasicAuthenticationWithAccessCodeGrant { get; set; } = false; + } +} \ No newline at end of file diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIOptionsExtensions.cs.cs b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIOptionsExtensions.cs.cs new file mode 100644 index 000000000..f11516687 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/SwaggerUIOptionsExtensions.cs.cs @@ -0,0 +1,295 @@ +using Surging.Core.CPlatform.Runtime.Server; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Surging.Core.Swagger.SwaggerUI +{ + public static class SwaggerUIOptionsExtensions + { + /// + /// Injects additional CSS stylesheets into the index.html page + /// + /// + /// A path to the stylesheet - i.e. the link "href" attribute + /// The target media - i.e. the link "media" attribute + public static void InjectStylesheet(this SwaggerUIOptions options, string path, string media = "screen") + { + var builder = new StringBuilder(options.HeadContent); + builder.AppendLine($""); + options.HeadContent = builder.ToString(); + } + + /// + /// Injects additional Javascript files into the index.html page + /// + /// + /// A path to the javascript - i.e. the script "src" attribute + /// The script type - i.e. the script "type" attribute + public static void InjectJavascript(this SwaggerUIOptions options, string path, string type = "text/javascript") + { + var builder = new StringBuilder(options.HeadContent); + builder.AppendLine($""); + options.HeadContent = builder.ToString(); + } + + /// + /// Adds Swagger JSON endpoints. Can be fully-qualified or relative to the UI page + /// + /// + /// Can be fully qualified or relative to the current host + /// The description that appears in the document selector drop-down + public static void SwaggerEndpoint(this SwaggerUIOptions options, string url, string name,string areaName) + { + var urls = new List(options.ConfigObject.Urls ?? Enumerable.Empty()); + urls.Add(new UrlDescriptor { Url = string.IsNullOrEmpty(areaName) ? url : $"{areaName}{url}", Name = name }); + options.ConfigObject.Urls = urls; + } + + public static void SwaggerEndpoint(this SwaggerUIOptions options, IEnumerable entries,string areaName) + { + + var list = new List(); + var assemblies = entries.Select(p => p.Type.Assembly).Distinct(); + foreach (var assembly in assemblies) + { + var version = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + var title = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + var des = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + if (version == null || title == null) + continue; + + var info = new Info() + { + Title = title.Title, + Version = version.Version, + Description = des?.Description, + + }; + options.SwaggerEndpoint($"../swagger/{info.Title}/swagger.json", info.Title,areaName); + } + } + + /// + /// Enables deep linking for tags and operations + /// + /// + public static void EnableDeepLinking(this SwaggerUIOptions options) + { + options.ConfigObject.DeepLinking = true; + } + + /// + /// Controls the display of operationId in operations list + /// + /// + public static void DisplayOperationId(this SwaggerUIOptions options) + { + options.ConfigObject.DisplayOperationId = true; + } + + /// + /// The default expansion depth for models (set to -1 completely hide the models) + /// + /// + /// + public static void DefaultModelsExpandDepth(this SwaggerUIOptions options, int depth) + { + options.ConfigObject.DefaultModelsExpandDepth = depth; + } + + /// + /// The default expansion depth for the model on the model-example section + /// + /// + /// + public static void DefaultModelExpandDepth(this SwaggerUIOptions options, int depth) + { + options.ConfigObject.DefaultModelExpandDepth = depth; + } + + /// + /// Controls how the model is shown when the API is first rendered. + /// (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) + /// + /// + /// + public static void DefaultModelRendering(this SwaggerUIOptions options, ModelRendering modelRendering) + { + options.ConfigObject.DefaultModelRendering = modelRendering; + } + + /// + /// Controls the display of the request duration (in milliseconds) for Try-It-Out requests + /// + /// + public static void DisplayRequestDuration(this SwaggerUIOptions options) + { + options.ConfigObject.DisplayRequestDuration = true; + } + + /// + /// Controls the default expansion setting for the operations and tags. + /// It can be 'List' (expands only the tags), 'Full' (expands the tags and operations) or 'None' (expands nothing) + /// + /// + /// + public static void DocExpansion(this SwaggerUIOptions options, DocExpansion docExpansion) + { + options.ConfigObject.DocExpansion = docExpansion; + } + + /// + /// Enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. + /// If an expression is provided it will be used and applied initially. + /// Filtering is case sensitive matching the filter expression anywhere inside the tag + /// + /// + /// + public static void EnableFilter(this SwaggerUIOptions options, string expression = null) + { + options.ConfigObject.Filter = expression ?? ""; + } + + /// + /// Limits the number of tagged operations displayed to at most this many. The default is to show all operations + /// + /// + /// + public static void MaxDisplayedTags(this SwaggerUIOptions options, int count) + { + options.ConfigObject.MaxDisplayedTags = count; + } + + /// + /// Controls the display of vendor extension (x-) fields and values for Operations, Parameters, and Schema + /// + /// + public static void ShowExtensions(this SwaggerUIOptions options) + { + options.ConfigObject.ShowExtensions = true; + } + + /// + /// List of HTTP methods that have the Try it out feature enabled. An empty array disables Try it out for all operations. + /// This does not filter the operations from the display + /// + /// + /// + public static void SupportedSubmitMethods(this SwaggerUIOptions options, params SubmitMethod[] submitMethods) + { + options.ConfigObject.SupportedSubmitMethods = submitMethods; + } + + /// + /// OAuth redirect URL + /// + /// + /// + public static void OAuth2RedirectUrl(this SwaggerUIOptions options, string url) + { + options.ConfigObject.OAuth2RedirectUrl = url; + } + + [Obsolete("The validator is disabled by default. Use EnableValidator to enable it")] + public static void ValidatorUrl(this SwaggerUIOptions options, string url) + { + options.ConfigObject.ValidatorUrl = url; + } + + /// + /// You can use this parameter to enable the swagger-ui's built-in validator (badge) functionality + /// Setting it to null will disable validation + /// + /// + /// + public static void EnableValidator(this SwaggerUIOptions options, string url = "https://online.swagger.io/validator") + { + options.ConfigObject.ValidatorUrl = url; + } + + /// + /// Default clientId + /// + /// + /// + public static void OAuthClientId(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.ClientId = value; + } + + /// + /// Default clientSecret + /// + /// + /// + public static void OAuthClientSecret(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.ClientSecret = value; + } + + /// + /// realm query parameter (for oauth1) added to authorizationUrl and tokenUrl + /// + /// + /// + public static void OAuthRealm(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.Realm = value; + } + + /// + /// Application name, displayed in authorization popup + /// + /// + /// + public static void OAuthAppName(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.AppName = value; + } + + /// + /// Scope separator for passing scopes, encoded before calling, default value is a space (encoded value %20) + /// + /// + /// + public static void OAuthScopeSeparator(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.ScopeSeperator = value; + } + + /// + /// Additional query parameters added to authorizationUrl and tokenUrl + /// + /// + /// + public static void OAuthAdditionalQueryStringParams( + this SwaggerUIOptions options, + Dictionary value) + { + options.OAuthConfigObject.AdditionalQueryStringParams = value; + } + + /// + /// Only activated for the accessCode flow. During the authorization_code request to the tokenUrl, + /// pass the Client Password using the HTTP Basic Authentication scheme (Authorization header with + /// Basic base64encoded[client_id:client_secret]). The default is false + /// + /// + public static void OAuthUseBasicAuthenticationWithAccessCodeGrant(this SwaggerUIOptions options) + { + options.OAuthConfigObject.UseBasicAuthenticationWithAccessCodeGrant = true; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/index.html b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/index.html new file mode 100644 index 000000000..359c8b81e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/index.html @@ -0,0 +1,104 @@ + + + + + + %(DocumentTitle) + + + + + + %(HeadContent) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/absolute-path.js b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/absolute-path.js new file mode 100644 index 000000000..af42bc8f1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/absolute-path.js @@ -0,0 +1,14 @@ +/* + * getAbsoluteFSPath + * @return {string} When run in NodeJS env, returns the absolute path to the current directory + * When run outside of NodeJS, will return an error message + */ +const getAbsoluteFSPath = function () { + // detect whether we are running in a browser or nodejs + if (typeof module !== "undefined" && module.exports) { + return require("path").resolve(__dirname) + } + throw new Error('getAbsoluteFSPath can only be called within a Nodejs environment'); +} + +module.exports = getAbsoluteFSPath diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/favicon-16x16.png b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/favicon-16x16.png new file mode 100644 index 000000000..0f7e13b0d Binary files /dev/null and b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/favicon-16x16.png differ diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/favicon-32x32.png b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/favicon-32x32.png new file mode 100644 index 000000000..b0a3352ff Binary files /dev/null and b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/favicon-32x32.png differ diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/index.html b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/index.html new file mode 100644 index 000000000..145b6e17b --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/index.html @@ -0,0 +1,60 @@ + + + + + + Swagger UI + + + + + + + +
+ + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/index.js b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/index.js new file mode 100644 index 000000000..c229ec43e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/index.js @@ -0,0 +1,17 @@ +try { + module.exports.SwaggerUIBundle = require("./swagger-ui-bundle.js") + module.exports.SwaggerUIStandalonePreset = require("./swagger-ui-standalone-preset.js") +} catch(e) { + // swallow the error if there's a problem loading the assets. + // allows this module to support providing the assets for browserish contexts, + // without exploding in a Node context. + // + // see https://github.com/swagger-api/swagger-ui/issues/3291#issuecomment-311195388 + // for more information. +} + +// `absolutePath` and `getAbsoluteFSPath` are both here because at one point, +// we documented having one and actually implemented the other. +// They were both retained so we don't break anyone's code. +module.exports.absolutePath = require("./absolute-path.js") +module.exports.getAbsoluteFSPath = require("./absolute-path.js") diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/oauth2-redirect.html b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/oauth2-redirect.html new file mode 100644 index 000000000..fb68399d2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/oauth2-redirect.html @@ -0,0 +1,67 @@ + + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/package.json b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/package.json new file mode 100644 index 000000000..5e26dcd08 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/package.json @@ -0,0 +1,109 @@ +{ + "_args": [ + [ + "swagger-ui-dist@3.18.0", + "C:\\Users\\VULCAN\\Downloads\\Swashbuckle.AspNetCore-master\\src\\Swashbuckle.AspNetCore.SwaggerUI" + ] + ], + "_from": "swagger-ui-dist@3.18.0", + "_hasShrinkwrap": false, + "_id": "swagger-ui-dist@3.18.0", + "_inCache": true, + "_location": "/swagger-ui-dist", + "_nodeVersion": "8.11.3", + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/swagger-ui-dist_3.18.0_1533374632544_0.913868410164947" + }, + "_npmUser": { + "email": "apiteam@swagger.io", + "name": "swagger-api" + }, + "_npmVersion": "5.6.0", + "_phantomChildren": {}, + "_requested": { + "name": "swagger-ui-dist", + "raw": "swagger-ui-dist@3.18.0", + "rawSpec": "3.18.0", + "scope": null, + "spec": "3.18.0", + "type": "version" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.18.0.tgz", + "_shasum": "d6f2ee0cd9da7be44729843f423cc70802cf83ce", + "_shrinkwrap": null, + "_spec": "swagger-ui-dist@3.18.0", + "_where": "C:\\Users\\VULCAN\\Downloads\\Swashbuckle.AspNetCore-master\\src\\Swashbuckle.AspNetCore.SwaggerUI", + "bugs": { + "url": "https://github.com/swagger-api/swagger-ui/issues" + }, + "contributors": [ + { + "url": "in alphabetical order" + }, + { + "name": "Anna Bodnia", + "email": "anna.bodnia@gmail.com" + }, + { + "name": "Buu Nguyen", + "email": "buunguyen@gmail.com" + }, + { + "name": "Josh Ponelat", + "email": "jponelat@gmail.com" + }, + { + "name": "Kyle Shockey", + "email": "kyleshockey1@gmail.com" + }, + { + "name": "Robert Barnwell", + "email": "robert@robertismy.name" + }, + { + "name": "Sahar Jafari", + "email": "shr.jafari@gmail.com" + } + ], + "dependencies": {}, + "description": "[![NPM version](https://badge.fury.io/js/swagger-ui-dist.svg)](http://badge.fury.io/js/swagger-ui-dist)", + "devDependencies": {}, + "directories": {}, + "dist": { + "fileCount": 17, + "integrity": "sha512-AwFwmd9pf4XJb/IwLvpZ6Bl6wDhjidwjgBiqGv3/kXHp1hbVWi5ZKGSwKjdJ9att6MDJFhgp0+Dvd/Zqb7uySA==", + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbZXCpCRA9TVsSAnZWagAAGMMP/15pvjo1OUrJ/mHIcbnO\notV51ySKMHCZNXMuDqmAQRUla7lzd/QY9h9iJIt3PS8GO91YYPmcXZ4C3a5a\nTViuvQMYPvGV900ybJ/IjNZ6nwglNMCh4nGOOx+NdbQP0bXOPrbZll/v0eQA\n3oQuKN/0mSlG5y7UZYU9NfOPPk2cbV+kym+YVKPHrVnzzEEFMp+phOsNFh6y\ncVqrnHLVRi19jmWJBqgtn8C2gjlaGlx7wLjnYvjlfSL3bV0axbNj53mCMEpV\nDE3dHjertx78xLAwLBA/b4wJ/43xkXRJLG+gJ9MDBNkuUUt3C7PEWGIftcNd\ng/HuTGujDaMonijcsiLemh6flJpzPo+Q/wNZ6FctNd2Ko1ivF3ou3Vzzpfbg\noMZU9xuLzgVx0G5kBEJ8YC5Z8o6M8SCcN4mDsAwNY24anei+14alv87IuJmZ\nHoHlH/KVuZ+vrTGjkw+XdcvKeIGtlufK4+70KnLutt+OSF0QkqzEpx67UDpM\npzjcUkVUXzur00wG10DIxHB5gddEMrKMSVOujBFSizlctiYuAT4hBZB3RVv/\nppuSIGx17ytEWR0wE6IEpQ0CtNAjNfOG21J4GZauZwjMftFzSoBBMNNMo139\nceVLFUcbT4jhsOh/nayJCIGVkteexs7GOhLh140GUwKgWzYZQu8VfMSsCOXK\nrlW/\r\n=5R+h\r\n-----END PGP SIGNATURE-----\r\n", + "shasum": "d6f2ee0cd9da7be44729843f423cc70802cf83ce", + "tarball": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.18.0.tgz", + "unpackedSize": 11310890 + }, + "homepage": "https://github.com/swagger-api/swagger-ui#readme", + "installable": true, + "license": "Apache-2.0", + "main": "index.js", + "maintainers": [ + { + "name": "kyleshockey", + "email": "kyle.shockey1@gmail.com" + }, + { + "name": "swagger", + "email": "apiteam@swagger.io" + }, + { + "name": "swagger-api", + "email": "apiteam@swagger.io" + } + ], + "name": "swagger-ui-dist", + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/swagger-api/swagger-ui.git" + }, + "version": "3.18.0" +} diff --git a/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/swagger-ui-bundle.js b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/swagger-ui-bundle.js new file mode 100644 index 000000000..a5e10a2b2 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger/SwaggerUI/node_modules/swagger-ui-dist/swagger-ui-bundle.js @@ -0,0 +1,93 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}("undefined"!=typeof self?self:this,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=446)}([function(e,t,n){"use strict";e.exports=n(74)},function(e,t,n){e.exports=n(855)()},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){"use strict";t.__esModule=!0;var r,o=n(262),i=(r=o)&&r.__esModule?r:{default:r};t.default=function(){function e(e,t){for(var n=0;n>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?C(e)+t:t}function A(){return!0}function O(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function P(e,t){return M(e,t,0)}function T(e,t){return M(e,t,t)}function M(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var I=0,j=1,N=2,R="function"==typeof Symbol&&Symbol.iterator,D="@@iterator",L=R||D;function U(e){this.next=e}function q(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function F(){return{value:void 0,done:!0}}function z(e){return!!H(e)}function B(e){return e&&"function"==typeof e.next}function V(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(R&&e[R]||e[D]);if("function"==typeof t)return t}function W(e){return e&&"number"==typeof e.length}function J(e){return null===e||void 0===e?ie():a(e)?e.toSeq():function(e){var t=se(e)||"object"==typeof e&&new te(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}(e)}function Y(e){return null===e||void 0===e?ie().toKeyedSeq():a(e)?u(e)?e.toSeq():e.fromEntrySeq():ae(e)}function K(e){return null===e||void 0===e?ie():a(e)?u(e)?e.entrySeq():e.toIndexedSeq():ue(e)}function G(e){return(null===e||void 0===e?ie():a(e)?u(e)?e.entrySeq():e:ue(e)).toSetSeq()}U.prototype.toString=function(){return"[Iterator]"},U.KEYS=I,U.VALUES=j,U.ENTRIES=N,U.prototype.inspect=U.prototype.toSource=function(){return this.toString()},U.prototype[L]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return le(this,e,t,!0)},J.prototype.__iterator=function(e,t){return ce(this,e,t,!0)},t(Y,J),Y.prototype.toKeyedSeq=function(){return this},t(K,J),K.of=function(){return K(arguments)},K.prototype.toIndexedSeq=function(){return this},K.prototype.toString=function(){return this.__toString("Seq [","]")},K.prototype.__iterate=function(e,t){return le(this,e,t,!1)},K.prototype.__iterator=function(e,t){return ce(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=oe,J.Keyed=Y,J.Set=G,J.Indexed=K;var $,Z,X,Q="@@__IMMUTABLE_SEQ__@@";function ee(e){this._array=e,this.size=e.length}function te(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function ne(e){this._iterable=e,this.size=e.length||e.size}function re(e){this._iterator=e,this._iteratorCache=[]}function oe(e){return!(!e||!e[Q])}function ie(){return $||($=new ee([]))}function ae(e){var t=Array.isArray(e)?new ee(e).fromEntrySeq():B(e)?new re(e).fromEntrySeq():z(e)?new ne(e).fromEntrySeq():"object"==typeof e?new te(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function ue(e){var t=se(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function se(e){return W(e)?new ee(e):B(e)?new re(e):z(e)?new ne(e):void 0}function le(e,t,n,r){var o=e._cache;if(o){for(var i=o.length-1,a=0;a<=i;a++){var u=o[n?i-a:a];if(!1===t(u[1],r?u[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function ce(e,t,n,r){var o=e._cache;if(o){var i=o.length-1,a=0;return new U(function(){var e=o[n?i-a:a];return a++>i?{value:void 0,done:!0}:q(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function fe(e,t){return t?function e(t,n,r,o){if(Array.isArray(n))return t.call(o,r,K(n).map(function(r,o){return e(t,r,o,n)}));if(de(n))return t.call(o,r,Y(n).map(function(r,o){return e(t,r,o,n)}));return n}(t,e,"",{"":e}):pe(e)}function pe(e){return Array.isArray(e)?K(e).map(pe).toList():de(e)?Y(e).map(pe).toMap():e}function de(e){return e&&(e.constructor===Object||void 0===e.constructor)}function he(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function ve(e,t){if(e===t)return!0;if(!a(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||u(e)!==u(t)||s(e)!==s(t)||c(e)!==c(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!l(e);if(c(e)){var r=e.entries();return t.every(function(e,t){var o=r.next().value;return o&&he(o[1],e)&&(n||he(o[0],t))})&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var i=e;e=t,t=i}var f=!0,p=t.__iterate(function(t,r){if(n?!e.has(t):o?!he(t,e.get(r,y)):!he(e.get(r,y),t))return f=!1,!1});return f&&e.size===p}function me(e,t){if(!(this instanceof me))return new me(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(Z)return Z;Z=this}}function ge(e,t){if(!e)throw new Error(t)}function ye(e,t,n){if(!(this instanceof ye))return new ye(e,t,n);if(ge(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?{value:void 0,done:!0}:q(e,o,n[t?r-o++:o++])})},t(te,Y),te.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},te.prototype.has=function(e){return this._object.hasOwnProperty(e)},te.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,i=0;i<=o;i++){var a=r[t?o-i:i];if(!1===e(n[a],a,this))return i+1}return i},te.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,i=0;return new U(function(){var a=r[t?o-i:i];return i++>o?{value:void 0,done:!0}:q(e,a,n[a])})},te.prototype[h]=!0,t(ne,K),ne.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=V(this._iterable),r=0;if(B(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},ne.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=V(this._iterable);if(!B(n))return new U(F);var r=0;return new U(function(){var t=n.next();return t.done?t:q(e,r++,t.value)})},t(re,K),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return q(e,o,r[o++])})},t(me,K),me.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},me.prototype.get=function(e,t){return this.has(e)?this._value:t},me.prototype.includes=function(e){return he(this._value,e)},me.prototype.slice=function(e,t){var n=this.size;return O(e,t,n)?this:new me(this._value,T(t,n)-P(e,n))},me.prototype.reverse=function(){return this},me.prototype.indexOf=function(e){return he(this._value,e)?0:-1},me.prototype.lastIndexOf=function(e){return he(this._value,e)?this.size:-1},me.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?{value:void 0,done:!0}:q(e,i++,a)})},ye.prototype.equals=function(e){return e instanceof ye?this._start===e._start&&this._end===e._end&&this._step===e._step:ve(this,e)},t(be,n),t(_e,be),t(we,be),t(Ee,be),be.Keyed=_e,be.Indexed=we,be.Set=Ee;var xe="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function Se(e){return e>>>1&1073741824|3221225471&e}function Ce(e){if(!1===e||null===e||void 0===e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return Se(n)}if("string"===t)return e.length>je?function(e){var t=De[e];void 0===t&&(t=ke(e),Re===Ne&&(Re=0,De={}),Re++,De[e]=t);return t}(e):ke(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return function(e){var t;if(Te&&void 0!==(t=Pe.get(e)))return t;if(void 0!==(t=e[Ie]))return t;if(!Oe){if(void 0!==(t=e.propertyIsEnumerable&&e.propertyIsEnumerable[Ie]))return t;if(void 0!==(t=function(e){if(e&&e.nodeType>0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}(e)))return t}t=++Me,1073741824&Me&&(Me=0);if(Te)Pe.set(e,t);else{if(void 0!==Ae&&!1===Ae(e))throw new Error("Non-extensible objects are not allowed as keys.");if(Oe)Object.defineProperty(e,Ie,{enumerable:!1,configurable:!1,writable:!1,value:t});else if(void 0!==e.propertyIsEnumerable&&e.propertyIsEnumerable===e.constructor.prototype.propertyIsEnumerable)e.propertyIsEnumerable=function(){return this.constructor.prototype.propertyIsEnumerable.apply(this,arguments)},e.propertyIsEnumerable[Ie]=t;else{if(void 0===e.nodeType)throw new Error("Unable to set a non-enumerable property on object.");e[Ie]=t}}return t}(e);if("function"==typeof e.toString)return ke(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ke(e){for(var t=0,n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}})},Ue.prototype.toString=function(){return this.__toString("Map {","}")},Ue.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},Ue.prototype.set=function(e,t){return Qe(this,e,t)},Ue.prototype.setIn=function(e,t){return this.updateIn(e,y,function(){return t})},Ue.prototype.remove=function(e){return Qe(this,e,y)},Ue.prototype.deleteIn=function(e){return this.updateIn(e,function(){return y})},Ue.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},Ue.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=function e(t,n,r,o){var i=t===y;var a=n.next();if(a.done){var u=i?r:t,s=o(u);return s===u?t:s}ge(i||t&&t.set,"invalid keyPath");var l=a.value;var c=i?y:t.get(l,y);var f=e(c,n,r,o);return f===c?t:f===y?t.remove(l):(i?Xe():t).set(l,f)}(this,nn(e),t,n);return r===y?void 0:r},Ue.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):Xe()},Ue.prototype.merge=function(){return rt(this,void 0,arguments)},Ue.prototype.mergeWith=function(t){return rt(this,t,e.call(arguments,1))},Ue.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]})},Ue.prototype.mergeDeep=function(){return rt(this,ot,arguments)},Ue.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return rt(this,it(t),n)},Ue.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]})},Ue.prototype.sort=function(e){return Pt(Wt(this,e))},Ue.prototype.sortBy=function(e,t){return Pt(Wt(this,t,e))},Ue.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},Ue.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new x)},Ue.prototype.asImmutable=function(){return this.__ensureOwner()},Ue.prototype.wasAltered=function(){return this.__altered},Ue.prototype.__iterator=function(e,t){return new Ke(this,e,t)},Ue.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},Ue.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Ze(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Ue.isMap=qe;var Fe,ze="@@__IMMUTABLE_MAP__@@",Be=Ue.prototype;function Ve(e,t){this.ownerID=e,this.entries=t}function He(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function We(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Je(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Ye(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function Ke(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&$e(e._root)}function Ge(e,t){return q(e,t[0],t[1])}function $e(e,t){return{node:e,index:0,__prev:t}}function Ze(e,t,n,r){var o=Object.create(Be);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Xe(){return Fe||(Fe=Ze(0))}function Qe(e,t,n){var r,o;if(e._root){var i=w(b),a=w(_);if(r=et(e._root,e.__ownerID,0,void 0,t,n,i,a),!a.value)return e;o=e.size+(i.value?n===y?-1:1:0)}else{if(n===y)return e;o=1,r=new Ve(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?Ze(o,r):Xe()}function et(e,t,n,r,o,i,a,u){return e?e.update(t,n,r,o,i,a,u):i===y?e:(E(u),E(a),new Ye(t,r,[o,i]))}function tt(e){return e.constructor===Ye||e.constructor===Je}function nt(e,t,n,r,o){if(e.keyHash===r)return new Je(t,r,[e.entry,o]);var i,a=(0===n?e.keyHash:e.keyHash>>>n)&g,u=(0===n?r:r>>>n)&g;return new He(t,1<>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function st(e,t,n,r){var o=r?e:S(e);return o[t]=n,o}Be[ze]=!0,Be.delete=Be.remove,Be.removeIn=Be.deleteIn,Ve.prototype.get=function(e,t,n,r){for(var o=this.entries,i=0,a=o.length;i=lt)return function(e,t,n,r){e||(e=new x);for(var o=new Ye(e,Ce(n),[n,r]),i=0;i>>e)&g),i=this.bitmap;return 0==(i&o)?r:this.nodes[ut(i&o-1)].get(e+v,t,n,r)},He.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var u=(0===t?n:n>>>t)&g,s=1<=ct)return function(e,t,n,r,o){for(var i=0,a=new Array(m),u=0;0!==n;u++,n>>>=1)a[u]=1&n?t[i++]:void 0;return a[r]=o,new We(e,i+1,a)}(e,p,l,u,h);if(c&&!h&&2===p.length&&tt(p[1^f]))return p[1^f];if(c&&h&&1===p.length&&tt(h))return h;var b=e&&e===this.ownerID,_=c?h?l:l^s:l|s,w=c?h?st(p,f,h,b):function(e,t,n){var r=e.length-1;if(n&&t===r)return e.pop(),e;for(var o=new Array(r),i=0,a=0;a>>e)&g,i=this.nodes[o];return i?i.get(e+v,t,n,r):r},We.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var u=(0===t?n:n>>>t)&g,s=o===y,l=this.nodes,c=l[u];if(s&&!c)return this;var f=et(c,e,t+v,n,r,o,i,a);if(f===c)return this;var p=this.count;if(c){if(!f&&--p0&&r=0&&e=e.size||t<0)return e.withMutations(function(e){t<0?kt(e,t).set(0,n):kt(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,o=e._root,i=w(_);t>=Ot(e._capacity)?r=xt(r,e.__ownerID,0,t,n,i):o=xt(o,e.__ownerID,e._level,t,n,i);if(!i.value)return e;if(e.__ownerID)return e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e;return wt(e._origin,e._capacity,e._level,o,r)}(this,e,t)},pt.prototype.remove=function(e){return this.has(e)?0===e?this.shift():e===this.size-1?this.pop():this.splice(e,1):this},pt.prototype.insert=function(e,t){return this.splice(e,0,t)},pt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=this._origin=this._capacity=0,this._level=v,this._root=this._tail=null,this.__hash=void 0,this.__altered=!0,this):Et()},pt.prototype.push=function(){var e=arguments,t=this.size;return this.withMutations(function(n){kt(n,0,t+e.length);for(var r=0;r>>t&g;if(r>=this.array.length)return new mt([],e);var o,i=0===r;if(t>0){var a=this.array[r];if((o=a&&a.removeBefore(e,t-v,n))===a&&i)return this}if(i&&!o)return this;var u=St(this,e);if(!i)for(var s=0;s>>t&g;if(o>=this.array.length)return this;if(t>0){var i=this.array[o];if((r=i&&i.removeAfter(e,t-v,n))===i&&o===this.array.length-1)return this}var a=St(this,e);return a.array.splice(o+1),r&&(a.array[o]=r),a};var gt,yt,bt={};function _t(e,t){var n=e._origin,r=e._capacity,o=Ot(r),i=e._tail;return a(e._root,e._level,0);function a(e,u,s){return 0===u?function(e,a){var u=a===o?i&&i.array:e&&e.array,s=a>n?0:n-a,l=r-a;l>m&&(l=m);return function(){if(s===l)return bt;var e=t?--l:s++;return u&&u[e]}}(e,s):function(e,o,i){var u,s=e&&e.array,l=i>n?0:n-i>>o,c=1+(r-i>>o);c>m&&(c=m);return function(){for(;;){if(u){var e=u();if(e!==bt)return e;u=null}if(l===c)return bt;var n=t?--c:l++;u=a(s&&s[n],o-v,i+(n<>>n&g,s=e&&u0){var l=e&&e.array[u],c=xt(l,t,n-v,r,o,i);return c===l?e:((a=St(e,t)).array[u]=c,a)}return s&&e.array[u]===o?e:(E(i),a=St(e,t),void 0===o&&u===a.array.length-1?a.array.pop():a.array[u]=o,a)}function St(e,t){return t&&e&&t===e.ownerID?e:new mt(e?e.array.slice():[],t)}function Ct(e,t){if(t>=Ot(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&g],r-=v;return n}}function kt(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new x,o=e._origin,i=e._capacity,a=o+t,u=void 0===n?i:n<0?i+n:o+n;if(a===o&&u===i)return e;if(a>=u)return e.clear();for(var s=e._level,l=e._root,c=0;a+c<0;)l=new mt(l&&l.array.length?[void 0,l]:[],r),c+=1<<(s+=v);c&&(a+=c,o+=c,u+=c,i+=c);for(var f=Ot(i),p=Ot(u);p>=1<f?new mt([],r):d;if(d&&p>f&&av;y-=v){var b=f>>>y&g;m=m.array[b]=St(m.array[b],r)}m.array[f>>>v&g]=d}if(u=p)a-=p,u-=p,s=v,l=null,h=h&&h.removeBefore(r,0,a);else if(a>o||p>>s&g;if(_!==p>>>s&g)break;_&&(c+=(1<o&&(l=l.removeBefore(r,s,a-c)),l&&pi&&(i=l.size),a(s)||(l=l.map(function(e){return fe(e)})),r.push(l)}return i>e.size&&(e=e.setSize(i)),at(e,t,r)}function Ot(e){return e>>v<=m&&a.size>=2*i.size?(r=(o=a.filter(function(e,t){return void 0!==e&&u!==t})).toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=i.remove(t),o=u===a.size-1?a.pop():a.set(u,void 0))}else if(s){if(n===a.get(u)[1])return e;r=i,o=a.set(u,[t,n])}else r=i.set(t,a.size),o=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Mt(r,o)}function Nt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Rt(e){this._iter=e,this.size=e.size}function Dt(e){this._iter=e,this.size=e.size}function Lt(e){this._iter=e,this.size=e.size}function Ut(e){var t=Qt(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=en,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===N){var r=e.__iterator(t,n);return new U(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===j?I:j,n)},t}function qt(e,t,n){var r=Qt(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var i=e.get(r,y);return i===y?o:t.call(n,i,r,e)},r.__iterateUncached=function(r,o){var i=this;return e.__iterate(function(e,o,a){return!1!==r(t.call(n,e,o,a),o,i)},o)},r.__iteratorUncached=function(r,o){var i=e.__iterator(N,o);return new U(function(){var o=i.next();if(o.done)return o;var a=o.value,u=a[0];return q(r,u,t.call(n,a[1],u,e),o)})},r}function Ft(e,t){var n=Qt(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Ut(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=en,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function zt(e,t,n,r){var o=Qt(e);return r&&(o.has=function(r){var o=e.get(r,y);return o!==y&&!!t.call(n,o,r,e)},o.get=function(r,o){var i=e.get(r,y);return i!==y&&t.call(n,i,r,e)?i:o}),o.__iterateUncached=function(o,i){var a=this,u=0;return e.__iterate(function(e,i,s){if(t.call(n,e,i,s))return u++,o(e,r?i:u-1,a)},i),u},o.__iteratorUncached=function(o,i){var a=e.__iterator(N,i),u=0;return new U(function(){for(;;){var i=a.next();if(i.done)return i;var s=i.value,l=s[0],c=s[1];if(t.call(n,c,l,e))return q(o,r?l:u++,c,i)}})},o}function Bt(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),O(t,n,o))return e;var i=P(t,o),a=T(n,o);if(i!=i||a!=a)return Bt(e.toSeq().cacheResult(),t,n,r);var u,s=a-i;s==s&&(u=s<0?0:s);var l=Qt(e);return l.size=0===u?u:e.size&&u||void 0,!r&&oe(e)&&u>=0&&(l.get=function(t,n){return(t=k(this,t))>=0&&tu)return{value:void 0,done:!0};var e=o.next();return r||t===j?e:q(t,s-1,t===I?void 0:e.value[1],e)})},l}function Vt(e,t,n,r){var o=Qt(e);return o.__iterateUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterate(o,i);var u=!0,s=0;return e.__iterate(function(e,i,l){if(!u||!(u=t.call(n,e,i,l)))return s++,o(e,r?i:s-1,a)}),s},o.__iteratorUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterator(o,i);var u=e.__iterator(N,i),s=!0,l=0;return new U(function(){var e,i,c;do{if((e=u.next()).done)return r||o===j?e:q(o,l++,o===I?void 0:e.value[1],e);var f=e.value;i=f[0],c=f[1],s&&(s=t.call(n,c,i,a))}while(s);return o===N?e:q(o,i,c,e)})},o}function Ht(e,t,n){var r=Qt(e);return r.__iterateUncached=function(r,o){var i=0,u=!1;return function e(s,l){var c=this;s.__iterate(function(o,s){return(!t||l0}function Kt(e,t,r){var o=Qt(e);return o.size=new ee(r).map(function(e){return e.size}).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(j,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var i=r.map(function(e){return e=n(e),V(o?e.reverse():e)}),a=0,u=!1;return new U(function(){var n;return u||(n=i.map(function(e){return e.next()}),u=n.some(function(e){return e.done})),u?{value:void 0,done:!0}:q(e,a++,t.apply(null,n.map(function(e){return e.value})))})},o}function Gt(e,t){return oe(e)?t:e.constructor(t)}function $t(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Zt(e){return Le(e.size),C(e)}function Xt(e){return u(e)?r:s(e)?o:i}function Qt(e){return Object.create((u(e)?Y:s(e)?K:G).prototype)}function en(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function tn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):An(e,t)},En.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Le(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):An(t,n)},En.prototype.pop=function(){return this.slice(1)},En.prototype.unshift=function(){return this.push.apply(this,arguments)},En.prototype.unshiftAll=function(e){return this.pushAll(e)},En.prototype.shift=function(){return this.pop.apply(this,arguments)},En.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):On()},En.prototype.slice=function(e,t){if(O(e,t,this.size))return this;var n=P(e,this.size);if(T(t,this.size)!==this.size)return we.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):An(r,o)},En.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?An(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},En.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},En.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new U(function(){if(r){var t=r.value;return r=r.next,q(e,n++,t)}return{value:void 0,done:!0}})},En.isStack=xn;var Sn,Cn="@@__IMMUTABLE_STACK__@@",kn=En.prototype;function An(e,t,n,r){var o=Object.create(kn);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function On(){return Sn||(Sn=An(0))}function Pn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}kn[Cn]=!0,kn.withMutations=Be.withMutations,kn.asMutable=Be.asMutable,kn.asImmutable=Be.asImmutable,kn.wasAltered=Be.wasAltered,n.Iterator=U,Pn(n,{toArray:function(){Le(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new Rt(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new Nt(this,!0)},toMap:function(){return Ue(this.toKeyedSeq())},toObject:function(){Le(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Pt(this.toKeyedSeq())},toOrderedSet:function(){return mn(u(this)?this.valueSeq():this)},toSet:function(){return sn(u(this)?this.valueSeq():this)},toSetSeq:function(){return new Dt(this)},toSeq:function(){return s(this)?this.toIndexedSeq():u(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return En(u(this)?this.valueSeq():this)},toList:function(){return pt(u(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return Gt(this,function(e,t){var n=u(e),o=[e].concat(t).map(function(e){return a(e)?n&&(e=r(e)):e=n?ae(e):ue(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===o.length)return e;if(1===o.length){var i=o[0];if(i===e||n&&u(i)||s(e)&&s(i))return i}var l=new ee(o);return n?l=l.toKeyedSeq():s(e)||(l=l.toSetSeq()),(l=l.flatten(!0)).size=o.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),l}(this,e.call(arguments,0)))},includes:function(e){return this.some(function(t){return he(t,e)})},entries:function(){return this.__iterator(N)},every:function(e,t){Le(this.size);var n=!0;return this.__iterate(function(r,o,i){if(!e.call(t,r,o,i))return n=!1,!1}),n},filter:function(e,t){return Gt(this,zt(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Le(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Le(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!==r&&void 0!==r?r.toString():""}),t},keys:function(){return this.__iterator(I)},map:function(e,t){return Gt(this,qt(this,e,t))},reduce:function(e,t,n){var r,o;return Le(this.size),arguments.length<2?o=!0:r=t,this.__iterate(function(t,i,a){o?(o=!1,r=t):r=e.call(n,r,t,i,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Gt(this,Ft(this,!0))},slice:function(e,t){return Gt(this,Bt(this,e,t,!0))},some:function(e,t){return!this.every(Nn(e),t)},sort:function(e){return Gt(this,Wt(this,e))},values:function(){return this.__iterator(j)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return C(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return function(e,t,n){var r=Ue().asMutable();return e.__iterate(function(o,i){r.update(t.call(n,o,i,e),0,function(e){return e+1})}),r.asImmutable()}(this,e,t)},equals:function(e){return ve(this,e)},entrySeq:function(){var e=this;if(e._cache)return new ee(e._cache);var t=e.toSeq().map(jn).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Nn(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,o,i){if(e.call(t,n,o,i))return r=[o,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(A)},flatMap:function(e,t){return Gt(this,function(e,t,n){var r=Xt(e);return e.toSeq().map(function(o,i){return r(t.call(n,o,i,e))}).flatten(!0)}(this,e,t))},flatten:function(e){return Gt(this,Ht(this,e,!0))},fromEntrySeq:function(){return new Lt(this)},get:function(e,t){return this.find(function(t,n){return he(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,o=nn(e);!(n=o.next()).done;){var i=n.value;if((r=r&&r.get?r.get(i,y):y)===y)return t}return r},groupBy:function(e,t){return function(e,t,n){var r=u(e),o=(c(e)?Pt():Ue()).asMutable();e.__iterate(function(i,a){o.update(t.call(n,i,a,e),function(e){return(e=e||[]).push(r?[a,i]:i),e})});var i=Xt(e);return o.map(function(t){return Gt(e,i(t))})}(this,e,t)},has:function(e){return this.get(e,y)!==y},hasIn:function(e){return this.getIn(e,y)!==y},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey(function(t){return he(t,e)})},keySeq:function(){return this.toSeq().map(In).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return Jt(this,e)},maxBy:function(e,t){return Jt(this,t,e)},min:function(e){return Jt(this,e?Rn(e):Un)},minBy:function(e,t){return Jt(this,t?Rn(t):Un,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Gt(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Gt(this,Vt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Nn(e),t)},sortBy:function(e,t){return Gt(this,Wt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Gt(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Gt(this,function(e,t,n){var r=Qt(e);return r.__iterateUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterate(r,o);var a=0;return e.__iterate(function(e,o,u){return t.call(n,e,o,u)&&++a&&r(e,o,i)}),a},r.__iteratorUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterator(r,o);var a=e.__iterator(N,o),u=!0;return new U(function(){if(!u)return{value:void 0,done:!0};var e=a.next();if(e.done)return e;var o=e.value,s=o[0],l=o[1];return t.call(n,l,s,i)?r===N?e:q(r,s,l,e):(u=!1,{value:void 0,done:!0})})},r}(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Nn(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=function(e){if(e.size===1/0)return 0;var t=c(e),n=u(e),r=t?1:0;return function(e,t){return t=xe(t,3432918353),t=xe(t<<15|t>>>-15,461845907),t=xe(t<<13|t>>>-13,5),t=xe((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=Se((t=xe(t^t>>>13,3266489909))^t>>>16)}(e.__iterate(n?t?function(e,t){r=31*r+qn(Ce(e),Ce(t))|0}:function(e,t){r=r+qn(Ce(e),Ce(t))|0}:t?function(e){r=31*r+Ce(e)|0}:function(e){r=r+Ce(e)|0}),r)}(this))}});var Tn=n.prototype;Tn[f]=!0,Tn[L]=Tn.values,Tn.__toJS=Tn.toArray,Tn.__toStringMapper=Dn,Tn.inspect=Tn.toSource=function(){return this.toString()},Tn.chain=Tn.flatMap,Tn.contains=Tn.includes,Pn(r,{flip:function(){return Gt(this,Ut(this))},mapEntries:function(e,t){var n=this,r=0;return Gt(this,this.toSeq().map(function(o,i){return e.call(t,[i,o],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Gt(this,this.toSeq().flip().map(function(r,o){return e.call(t,r,o,n)}).flip())}});var Mn=r.prototype;function In(e,t){return t}function jn(e,t){return[t,e]}function Nn(e){return function(){return!e.apply(this,arguments)}}function Rn(e){return function(){return-e.apply(this,arguments)}}function Dn(e){return"string"==typeof e?JSON.stringify(e):String(e)}function Ln(){return S(arguments)}function Un(e,t){return et?-1:0}function qn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return Mn[p]=!0,Mn[L]=Tn.entries,Mn.__toJS=Tn.toObject,Mn.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+Dn(e)},Pn(o,{toKeyedSeq:function(){return new Nt(this,!1)},filter:function(e,t){return Gt(this,zt(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Gt(this,Ft(this,!1))},slice:function(e,t){return Gt(this,Bt(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=P(e,e<0?this.count():this.size);var r=this.slice(0,e);return Gt(this,1===n?r:r.concat(S(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Gt(this,Ht(this,e,!1))},get:function(e,t){return(e=k(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=k(this,e))>=0&&(void 0!==this.size?this.size===1/0||e>",i={listOf:function(e){return l(e,"List",r.List.isList)},mapOf:function(e,t){return c(e,t,"Map",r.Map.isMap)},orderedMapOf:function(e,t){return c(e,t,"OrderedMap",r.OrderedMap.isOrderedMap)},setOf:function(e){return l(e,"Set",r.Set.isSet)},orderedSetOf:function(e){return l(e,"OrderedSet",r.OrderedSet.isOrderedSet)},stackOf:function(e){return l(e,"Stack",r.Stack.isStack)},iterableOf:function(e){return l(e,"Iterable",r.Iterable.isIterable)},recordOf:function(e){return u(function(t,n,o,i,u){for(var s=arguments.length,l=Array(s>5?s-5:0),c=5;c6?s-6:0),c=6;c5?l-5:0),f=5;f5?i-5:0),u=5;u key("+c[f]+")"].concat(a));if(d instanceof Error)return d}})).apply(void 0,i);var s})}function f(e){var t=void 0===arguments[1]?"Iterable":arguments[1],n=void 0===arguments[2]?r.Iterable.isIterable:arguments[2];return u(function(r,o,i,u,s){for(var l=arguments.length,c=Array(l>5?l-5:0),f=5;f5e3)return e.textContent;return function(e){for(var n,r,o,i,a,u=e.textContent,s=0,l=u[0],c=1,f=e.innerHTML="",p=0;r=n,n=p<7&&"\\"==n?1:c;){if(c=l,l=u[++s],i=f.length>1,!c||p>8&&"\n"==c||[/\S/.test(c),1,1,!/[$\w]/.test(c),("/"==n||"\n"==n)&&i,'"'==n&&i,"'"==n&&i,u[s-4]+r+n=="--\x3e",r+n=="*/"][p])for(f&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][p?p<3?2:p>6?4:p>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(f):0]),a.appendChild(t.createTextNode(f))),o=p&&p<7?p:o,f="",p=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(c),/[\])]/.test(c),/[$\w]/.test(c),"/"==c&&o<2&&"<"!=n,'"'==c,"'"==c,c+l+u[s+1]+u[s+2]=="\x3c!--",c+l=="/*",c+l=="//","#"==c][--p];);f+=c}}(e)},t.mapToList=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"key";var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:l.default.Map();if(!l.default.Map.isMap(t)||!t.size)return l.default.List();Array.isArray(n)||(n=[n]);if(n.length<1)return t.merge(r);var a=l.default.List();var u=n[0];var s=!0;var c=!1;var f=void 0;try{for(var p,d=(0,i.default)(t.entries());!(s=(p=d.next()).done);s=!0){var h=p.value,v=(0,o.default)(h,2),m=v[0],g=v[1],y=e(g,n.slice(1),r.set(u,m));a=l.default.List.isList(y)?a.concat(y):a.push(y)}}catch(e){c=!0,f=e}finally{try{!s&&d.return&&d.return()}finally{if(c)throw f}}return a},t.extractFileNameFromContentDispositionHeader=function(e){var t=/filename="([^;]*);?"/i.exec(e);null===t&&(t=/filename=([^;]*);?/i.exec(e));if(null!==t&&t.length>1)return t[1];return null},t.pascalCase=C,t.pascalCaseFilename=function(e){return C(e.replace(/\.[^./]*$/,""))},t.sanitizeUrl=function(e){if("string"!=typeof e||""===e)return"";return(0,c.sanitizeUrl)(e)},t.getAcceptControllingResponse=function(e){if(!l.default.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&(0,u.default)(e.get("content")||{}).length>0}),n=e.get("default")||l.default.OrderedMap(),r=(n.get("content")||l.default.OrderedMap()).keySeq().toJS().length?n:null;return t||r},t.deeplyStripKey=function e(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==(void 0===t?"undefined":(0,s.default)(t))||Array.isArray(t)||null===t||!n)return t;var o=(0,a.default)({},t);(0,u.default)(o).forEach(function(t){t===n&&r(o[t],t)?delete o[t]:o[t]=e(o[t],n,r)});return o},t.stringify=function(e){if("string"==typeof e)return e;e.toJS&&(e=e.toJS());if("object"===(void 0===e?"undefined":(0,s.default)(e))&&null!==e)try{return(0,r.default)(e,null,2)}catch(t){return String(e)}return e.toString()},t.numberToString=function(e){if("number"==typeof e)return e.toString();return e};var l=_(n(7)),c=n(573),f=_(n(574)),p=_(n(280)),d=_(n(285)),h=_(n(288)),v=_(n(651)),m=_(n(106)),g=n(193),y=_(n(33)),b=_(n(724));function _(e){return e&&e.__esModule?e:{default:e}}var w="default",E=t.isImmutable=function(e){return l.default.Iterable.isIterable(e)};function x(e){return Array.isArray(e)?e:[e]}function S(e){return!!e&&"object"===(void 0===e?"undefined":(0,s.default)(e))}t.memoize=d.default;function C(e){return(0,p.default)((0,f.default)(e))}t.propChecker=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];return(0,u.default)(e).length!==(0,u.default)(t).length||((0,v.default)(e,function(e,n){if(r.includes(n))return!1;var o=t[n];return l.default.Iterable.isIterable(e)?!l.default.is(e,o):("object"!==(void 0===e?"undefined":(0,s.default)(e))||"object"!==(void 0===o?"undefined":(0,s.default)(o)))&&e!==o})||n.some(function(n){return!(0,m.default)(e[n],t[n])}))};var k=t.validateMaximum=function(e,t){if(e>t)return"Value must be less than Maximum"},A=t.validateMinimum=function(e,t){if(et)return"Value must be less than MaxLength"},D=t.validateMinLength=function(e,t){if(e.length2&&void 0!==arguments[2]&&arguments[2],r=[],o=t&&"body"===e.get("in")?e.get("value_xml"):e.get("value"),i=e.get("required"),a=n?e.get("schema"):e;if(!a)return r;var u=a.get("maximum"),c=a.get("minimum"),f=a.get("type"),p=a.get("format"),d=a.get("maxLength"),h=a.get("minLength"),v=a.get("pattern");if(f&&(i||o)){var m="string"===f&&o,g="array"===f&&Array.isArray(o)&&o.length,b="array"===f&&l.default.List.isList(o)&&o.count(),_="file"===f&&o instanceof y.default.File,w="boolean"===f&&(o||!1===o),E="number"===f&&(o||0===o),x="integer"===f&&(o||0===o),S=!1;if(n&&"object"===f)if("object"===(void 0===o?"undefined":(0,s.default)(o)))S=!0;else if("string"==typeof o)try{JSON.parse(o),S=!0}catch(e){return r.push("Parameter string value must be valid JSON"),r}var C=[m,g,b,_,w,E,x,S].some(function(e){return!!e});if(i&&!C)return r.push("Required field is not provided"),r;if(v){var U=L(o,v);U&&r.push(U)}if(d||0===d){var q=R(o,d);q&&r.push(q)}if(h){var F=D(o,h);F&&r.push(F)}if(u||0===u){var z=k(o,u);z&&r.push(z)}if(c||0===c){var B=A(o,c);B&&r.push(B)}if("string"===f){var V=void 0;if(!(V="date-time"===p?j(o):"uuid"===p?N(o):I(o)))return r;r.push(V)}else if("boolean"===f){var H=M(o);if(!H)return r;r.push(H)}else if("number"===f){var W=O(o);if(!W)return r;r.push(W)}else if("integer"===f){var J=P(o);if(!J)return r;r.push(J)}else if("array"===f){var Y;if(!b||!o.count())return r;Y=a.getIn(["items","type"]),o.forEach(function(e,t){var n=void 0;"number"===Y?n=O(e):"integer"===Y?n=P(e):"string"===Y&&(n=I(e)),n&&r.push({index:t,error:n})})}else if("file"===f){var K=T(o);if(!K)return r;r.push(K)}}return r},t.getSampleSchema=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated --\x3e':null;var o=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=o[1]}return(0,g.memoizedCreateXMLExample)(e,n)}var i=(0,g.memoizedSampleFromSchema)(e,n);return"object"===(void 0===i?"undefined":(0,s.default)(i))?(0,r.default)(i,null,2):i},t.parseSearch=function(){var e={},t=y.default.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)n.hasOwnProperty(r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},t.serializeSearch=function(e){return(0,u.default)(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&")},t.btoa=function(t){return(t instanceof e?t:new e(t.toString(),"utf-8")).toString("base64")},t.sorters={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},t.buildFormData=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},t.shallowEqualKeys=function(e,t,n){return!!(0,h.default)(n,function(n){return(0,m.default)(e[n],t[n])})};var U=t.createDeepLinkPath=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"_"):""};t.escapeDeepLinkPath=function(e){return(0,b.default)(U(e))},t.getExtensions=function(e){return e.filter(function(e,t){return/^x-/.test(t)})},t.getCommonExtensions=function(e){return e.filter(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)})}}).call(t,n(55).Buffer)},function(e,t,n){"use strict"; +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/var r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,a,u=function(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s?@[\]^_`{|}~-])/g;function a(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function u(e){if(e>65535){var t=55296+((e-=65536)>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}var s=/&([a-z#][a-z0-9]{1,31});/gi,l=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,c=n(417);function f(e,t){var n=0;return o(c,t)?c[t]:35===t.charCodeAt(0)&&l.test(t)&&a(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?u(n):e}var p=/[&<>"]/,d=/[&<>"]/g,h={"&":"&","<":"<",">":">",'"':"""};function v(e){return h[e]}t.assign=function(e){return[].slice.call(arguments,1).forEach(function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e},t.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},t.has=o,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(i,"$1")},t.isValidEntityCode=a,t.fromCodePoint=u,t.replaceEntities=function(e){return e.indexOf("&")<0?e:e.replace(s,f)},t.escapeHtml=function(e){return p.test(e)?e.replace(d,v):e}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){var r=n(29),o=n(53),i=n(59),a=n(72),u=n(120),s=function(e,t,n){var l,c,f,p,d=e&s.F,h=e&s.G,v=e&s.S,m=e&s.P,g=e&s.B,y=h?r:v?r[t]||(r[t]={}):(r[t]||{}).prototype,b=h?o:o[t]||(o[t]={}),_=b.prototype||(b.prototype={});for(l in h&&(n=t),n)f=((c=!d&&y&&void 0!==y[l])?y:n)[l],p=g&&c?u(f,r):m&&"function"==typeof f?u(Function.call,f):f,y&&a(y,l,f,e&s.U),b[l]!=f&&i(b,l,p),m&&_[l]!=f&&(_[l]=f)};r.core=o,s.F=1,s.G=2,s.S=4,s.P=8,s.B=16,s.W=32,s.U=64,s.R=128,e.exports=s},function(e,t,n){var r=n(30),o=n(102),i=n(54),a=/"/g,u=function(e,t,n,r){var o=String(i(e)),u="<"+t;return""!==n&&(u+=" "+n+'="'+String(r).replace(a,""")+'"'),u+">"+o+""};e.exports=function(e,t){var n={};n[e]=t(u),r(r.P+r.F*o(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";var r,o=n(91),i=(r=o)&&r.__esModule?r:{default:r};e.exports=function(){var e={location:{},history:{},open:function(){},close:function(){},File:function(){}};if("undefined"==typeof window)return e;try{e=window;var t=!0,n=!1,r=void 0;try{for(var o,a=(0,i.default)(["File","Blob","FormData"]);!(t=(o=a.next()).done);t=!0){var u=o.value;u in window&&(e[u]=window[u])}}catch(e){n=!0,r=e}finally{try{!t&&a.return&&a.return()}finally{if(n)throw r}}}catch(e){console.error(e)}return e}()},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=i(n(25));t.isOAS3=a,t.isSwagger2=function(e){var t=e.get("swagger");if("string"!=typeof t)return!1;return t.startsWith("2.0")},t.OAS3ComponentWrapFactory=function(e){return function(t,n){return function(i){if(n&&n.specSelectors&&n.specSelectors.specJson){var u=n.specSelectors.specJson();return a(u)?o.default.createElement(e,(0,r.default)({},i,n,{Ori:t})):o.default.createElement(t,i)}return console.warn("OAS3 wrapper: couldn't get spec"),null}}};var o=i(n(0));function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=e.get("openapi");return"string"==typeof t&&(t.startsWith("3.0.")&&t.length>4)}},function(e,t,n){var r=n(28);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){var r=n(278),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();e.exports=i},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){"use strict";var r=null;e.exports={debugTool:r}},function(e,t,n){var r=n(35),o=n(239),i=n(157),a=Object.defineProperty;t.f=n(44)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),o)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){e.exports={default:n(518),__esModule:!0}},function(e,t,n){e.exports={default:n(519),__esModule:!0}},function(e,t,n){"use strict";function r(e){return function(){return e}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},e.exports=o},function(e,t,n){"use strict";var r=n(9),o=n(13),i=n(355),a=n(68),u=n(356),s=n(88),l=n(147),c=n(8),f=[],p=0,d=i.getPooled(),h=!1,v=null;function m(){E.ReactReconcileTransaction&&v||r("123")}var g=[{initialize:function(){this.dirtyComponentsLength=f.length},close:function(){this.dirtyComponentsLength!==f.length?(f.splice(0,this.dirtyComponentsLength),w()):f.length=0}},{initialize:function(){this.callbackQueue.reset()},close:function(){this.callbackQueue.notifyAll()}}];function y(){this.reinitializeTransaction(),this.dirtyComponentsLength=null,this.callbackQueue=i.getPooled(),this.reconcileTransaction=E.ReactReconcileTransaction.getPooled(!0)}function b(e,t){return e._mountOrder-t._mountOrder}function _(e){var t=e.dirtyComponentsLength;t!==f.length&&r("124",t,f.length),f.sort(b),p++;for(var n=0;n + * @license MIT + */ +var r=n(530),o=n(531),i=n(261);function a(){return s.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function u(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function h(e,t){if(s.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(r)return F(e).length;t=(""+t).toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function m(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=s.from(t,r)),s.isBuffer(t))return 0===t.length?-1:g(e,t,n,r,o);if("number"==typeof t)return t&=255,s.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):g(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function g(e,t,n,r,o){var i,a=1,u=e.length,s=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,u/=2,s/=2,n/=2}function l(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var c=-1;for(i=n;iu&&(n=u-s),i=n;i>=0;i--){for(var f=!0,p=0;po&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function S(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function C(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:l>223?3:l>191?2:1;if(o+f<=n)switch(f){case 1:l<128&&(c=l);break;case 2:128==(192&(i=e[o+1]))&&(s=(31&l)<<6|63&i)>127&&(c=s);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(s=(15&l)<<12|(63&i)<<6|63&a)>2047&&(s<55296||s>57343)&&(c=s);break;case 4:i=e[o+1],a=e[o+2],u=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&u)&&(s=(15&l)<<18|(63&i)<<12|(63&a)<<6|63&u)>65535&&s<1114112&&(c=s)}null===c?(c=65533,f=1):c>65535&&(c-=65536,r.push(c>>>10&1023|55296),c=56320|1023&c),r.push(c),o+=f}return function(e){var t=e.length;if(t<=k)return String.fromCharCode.apply(String,e);var n="",r=0;for(;rthis.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,n);case"utf8":case"utf-8":return C(this,t,n);case"ascii":return A(this,t,n);case"latin1":case"binary":return O(this,t,n);case"base64":return S(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return T(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}.apply(this,arguments)},s.prototype.equals=function(e){if(!s.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===s.compare(this,e)},s.prototype.inspect=function(){var e="",n=t.INSPECT_MAX_BYTES;return this.length>0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},s.prototype.compare=function(e,t,n,r,o){if(!s.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,o>>>=0,this===e)return 0;for(var i=o-r,a=n-t,u=Math.min(i,a),l=this.slice(r,o),c=e.slice(t,n),f=0;fo)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return y(this,e,t,n);case"utf8":case"utf-8":return b(this,e,t,n);case"ascii":return _(this,e,t,n);case"latin1":case"binary":return w(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return x(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},s.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var k=4096;function A(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function I(e,t,n,r,o,i){if(!s.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function j(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function N(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function R(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function D(e,t,n,r,i){return i||R(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function L(e,t,n,r,i){return i||R(e,0,n,8),o.write(e,t,n,r,52,8),n+8}s.prototype.slice=function(e,t){var n,r=this.length;if(e=~~e,t=void 0===t?r:~~t,e<0?(e+=r)<0&&(e=0):e>r&&(e=r),t<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},s.prototype.readUInt8=function(e,t){return t||M(e,1,this.length),this[e]},s.prototype.readUInt16LE=function(e,t){return t||M(e,2,this.length),this[e]|this[e+1]<<8},s.prototype.readUInt16BE=function(e,t){return t||M(e,2,this.length),this[e]<<8|this[e+1]},s.prototype.readUInt32LE=function(e,t){return t||M(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},s.prototype.readUInt32BE=function(e,t){return t||M(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},s.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||M(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},s.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||M(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},s.prototype.readInt8=function(e,t){return t||M(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},s.prototype.readInt16LE=function(e,t){t||M(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},s.prototype.readInt16BE=function(e,t){t||M(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},s.prototype.readInt32LE=function(e,t){return t||M(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},s.prototype.readInt32BE=function(e,t){return t||M(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},s.prototype.readFloatLE=function(e,t){return t||M(e,4,this.length),o.read(this,e,!0,23,4)},s.prototype.readFloatBE=function(e,t){return t||M(e,4,this.length),o.read(this,e,!1,23,4)},s.prototype.readDoubleLE=function(e,t){return t||M(e,8,this.length),o.read(this,e,!0,52,8)},s.prototype.readDoubleBE=function(e,t){return t||M(e,8,this.length),o.read(this,e,!1,52,8)},s.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||I(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},s.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,1,255,0),s.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},s.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,65535,0),s.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):j(this,e,t,!0),t+2},s.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,65535,0),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):j(this,e,t,!1),t+2},s.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,4294967295,0),s.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},s.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,4294967295,0),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},s.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);I(this,e,t,n,o-1,-o)}var i=0,a=1,u=0;for(this[t]=255&e;++i>0)-u&255;return t+n},s.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);I(this,e,t,n,o-1,-o)}var i=n-1,a=1,u=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===u&&0!==this[t+i+1]&&(u=1),this[t+i]=(e/a>>0)-u&255;return t+n},s.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,1,127,-128),s.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},s.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,32767,-32768),s.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):j(this,e,t,!0),t+2},s.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,32767,-32768),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):j(this,e,t,!1),t+2},s.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,2147483647,-2147483648),s.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},s.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},s.prototype.writeFloatLE=function(e,t,n){return D(this,e,t,!0,n)},s.prototype.writeFloatBE=function(e,t,n){return D(this,e,t,!1,n)},s.prototype.writeDoubleLE=function(e,t,n){return L(this,e,t,!0,n)},s.prototype.writeDoubleBE=function(e,t,n){return L(this,e,t,!1,n)},s.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!s.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function z(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(U,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function B(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(t,n(32))},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function u(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var s,l=[],c=!1,f=-1;function p(){c&&s&&(c=!1,s.length?l=s.concat(l):f=-1,l.length&&d())}function d(){if(!c){var e=u(p);c=!0;for(var t=l.length;t;){for(s=l,l=[];++f1)for(var n=1;n1?t-1:0),r=1;r2?n-2:0),o=2;o1){for(var h=Array(d),v=0;v1){for(var g=Array(m),y=0;y=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}},function(e,t,n){"use strict";function r(e){return void 0===e||null===e}e.exports.isNothing=r,e.exports.isObject=function(e){return"object"==typeof e&&null!==e},e.exports.toArray=function(e){return Array.isArray(e)?e:r(e)?[]:[e]},e.exports.repeat=function(e,t){var n,r="";for(n=0;n=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){e.exports=!n(102)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t){e.exports={}},function(e,t,n){var r=n(119),o=Math.min;e.exports=function(e){return e>0?o(r(e),9007199254740991):0}},function(e,t,n){"use strict";e.exports=function(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r0?o(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(60),o=n(460),i=n(461),a=Object.defineProperty;t.f=n(101)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),o)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(121);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,o){return e.call(t,n,r,o)}}return function(){return e.apply(t,arguments)}}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){var r=n(466),o=n(54);e.exports=function(e){return r(o(e))}},function(e,t,n){"use strict";var r=n(59),o=n(72),i=n(102),a=n(54),u=n(17);e.exports=function(e,t,n){var s=u(e),l=n(a,s,""[e]),c=l[0],f=l[1];i(function(){var t={};return t[s]=function(){return 7},7!=""[e](t)})&&(o(String.prototype,e,c),r(RegExp.prototype,s,2==t?function(e,t){return f.call(e,this,t)}:function(e){return f.call(e,this)}))}},function(e,t,n){var r=n(116)("meta"),o=n(28),i=n(52),a=n(39).f,u=0,s=Object.isExtensible||function(){return!0},l=!n(51)(function(){return s(Object.preventExtensions({}))}),c=function(e){a(e,r,{value:{i:"O"+ ++u,w:{}}})},f=e.exports={KEY:r,NEED:!1,fastKey:function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,r)){if(!s(e))return"F";if(!t)return"E";c(e)}return e[r].i},getWeak:function(e,t){if(!i(e,r)){if(!s(e))return!0;if(!t)return!1;c(e)}return e[r].w},onFreeze:function(e){return l&&f.NEED&&s(e)&&!i(e,r)&&c(e),e}}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){"use strict";var r={};e.exports=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CLEAR_BY=t.CLEAR=t.NEW_AUTH_ERR=t.NEW_SPEC_ERR_BATCH=t.NEW_SPEC_ERR=t.NEW_THROWN_ERR_BATCH=t.NEW_THROWN_ERR=void 0,t.newThrownErr=function(e){return{type:a,payload:(0,i.default)(e)}},t.newThrownErrBatch=function(e){return{type:u,payload:e}},t.newSpecErr=function(e){return{type:s,payload:e}},t.newSpecErrBatch=function(e){return{type:l,payload:e}},t.newAuthErr=function(e){return{type:c,payload:e}},t.clear=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:f,payload:e}},t.clearBy=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:p,payload:e}};var r,o=n(180),i=(r=o)&&r.__esModule?r:{default:r};var a=t.NEW_THROWN_ERR="err_new_thrown_err",u=t.NEW_THROWN_ERR_BATCH="err_new_thrown_err_batch",s=t.NEW_SPEC_ERR="err_new_spec_err",l=t.NEW_SPEC_ERR_BATCH="err_new_spec_err_batch",c=t.NEW_AUTH_ERR="err_new_auth_err",f=t.CLEAR="err_clear",p=t.CLEAR_BY="err_clear_by"},function(e,t,n){var r=n(61),o=n(47),i="[object Symbol]";e.exports=function(e){return"symbol"==typeof e||o(e)&&r(e)==i}},function(e,t,n){var r=n(62)(Object,"create");e.exports=r},function(e,t,n){var r=n(601),o=n(602),i=n(603),a=n(604),u=n(605);function s(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&eb;b++)if((m=t?y(a(h=e[b])[0],h[1]):y(e[b]))===l||m===c)return m}else for(v=g.call(e);!(h=v.next()).done;)if((m=o(v,y,h.value,t))===l||m===c)return m}).BREAK=l,t.RETURN=c},function(e,t,n){"use strict";var r=n(86);e.exports=r.DEFAULT=new r({include:[n(109)],explicit:[n(759),n(760),n(761)]})},function(e,t,n){var r=n(345),o=n(106),i=Object.prototype.hasOwnProperty;e.exports=function(e,t,n){var a=e[t];i.call(e,t)&&o(a,n)&&(void 0!==n||t in e)||r(e,t,n)}},function(e,t,n){"use strict";var r=n(9),o=(n(8),{}),i={reinitializeTransaction:function(){this.transactionWrappers=this.getTransactionWrappers(),this.wrapperInitData?this.wrapperInitData.length=0:this.wrapperInitData=[],this._isInTransaction=!1},_isInTransaction:!1,getTransactionWrappers:null,isInTransaction:function(){return!!this._isInTransaction},perform:function(e,t,n,o,i,a,u,s){var l,c;this.isInTransaction()&&r("27");try{this._isInTransaction=!0,l=!0,this.initializeAll(0),c=e.call(t,n,o,i,a,u,s),l=!1}finally{try{if(l)try{this.closeAll(0)}catch(e){}else this.closeAll(0)}finally{this._isInTransaction=!1}}return c},initializeAll:function(e){for(var t=this.transactionWrappers,n=e;n]/,s=n(219)(function(e,t){if(e.namespaceURI!==i.svg||"innerHTML"in e)e.innerHTML=t;else{(r=r||document.createElement("div")).innerHTML=""+t+"";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(o.canUseDOM){var l=document.createElement("div");l.innerHTML=" ",""===l.innerHTML&&(s=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&u.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),l=null}e.exports=s},function(e,t,n){"use strict";var r=/["'&<>]/;e.exports=function(e){return"boolean"==typeof e||"number"==typeof e?""+e:function(e){var t,n=""+e,o=r.exec(n);if(!o)return n;var i="",a=0,u=0;for(a=o.index;adocument.F=Object<\/script>"),e.close(),s=e.F;r--;)delete s.prototype[i[r]];return s()};e.exports=Object.create||function(e,t){var n;return null!==e?(u.prototype=r(e),n=new u,u.prototype=null,n[a]=e):n=s(),void 0===t?n:o(n,t)}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(162)("keys"),o=n(116);e.exports=function(e){return r[e]||(r[e]=o(e))}},function(e,t,n){var r=n(14),o=n(19),i=o["__core-js_shared__"]||(o["__core-js_shared__"]={});(e.exports=function(e,t){return i[e]||(i[e]=void 0!==t?t:{})})("versions",[]).push({version:r.version,mode:n(94)?"pure":"global",copyright:"© 2018 Denis Pushkarev (zloirock.ru)"})},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(165),o=n(20)("iterator"),i=n(69);e.exports=n(14).getIteratorMethod=function(e){if(void 0!=e)return e[o]||e["@@iterator"]||i[r(e)]}},function(e,t,n){var r=n(93),o=n(20)("toStringTag"),i="Arguments"==r(function(){return arguments}());e.exports=function(e){var t,n,a;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),o))?n:i?r(t):"Object"==(a=r(t))&&"function"==typeof t.callee?"Arguments":a}},function(e,t,n){var r=n(100),o=n(17)("toStringTag"),i="Arguments"==r(function(){return arguments}());e.exports=function(e){var t,n,a;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),o))?n:i?r(t):"Object"==(a=r(t))&&"function"==typeof t.callee?"Arguments":a}},function(e,t){e.exports=!1},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(73),o=n(29).document,i=r(o)&&r(o.createElement);e.exports=function(e){return i?o.createElement(e):{}}},function(e,t,n){var r=n(243)("keys"),o=n(168);e.exports=function(e){return r[e]||(r[e]=o(e))}},function(e,t,n){var r=n(117).f,o=n(118),i=n(17)("toStringTag");e.exports=function(e,t,n){e&&!o(e=n?e:e.prototype,i)&&r(e,i,{configurable:!0,value:t})}},function(e,t,n){"use strict";var r=n(121);e.exports.f=function(e){return new function(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=r(t),this.reject=r(n)}(e)}},function(e,t,n){var r=n(256),o=n(54);e.exports=function(e,t,n){if(r(t))throw TypeError("String#"+n+" doesn't accept regex!");return String(o(e))}},function(e,t,n){var r=n(17)("match");e.exports=function(e){var t=/./;try{"/./"[e](t)}catch(n){try{return t[r]=!1,!"/./"[e](t)}catch(e){}}return!0}},function(e,t,n){t.f=n(20)},function(e,t,n){var r=n(19),o=n(14),i=n(94),a=n(175),u=n(39).f;e.exports=function(e){var t=o.Symbol||(o.Symbol=i?{}:r.Symbol||{});"_"==e.charAt(0)||e in t||u(t,e,{value:a.f(e)})}},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t){},function(e,t,n){"use strict";(function(t){ +/*! + * @description Recursive object extending + * @author Viacheslav Lotsmanov + * @license MIT + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Viacheslav Lotsmanov + * + * 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. + */ +function n(e){return e instanceof t||e instanceof Date||e instanceof RegExp}function r(e){if(e instanceof t){var n=t.alloc?t.alloc(e.length):new t(e.length);return e.copy(n),n}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e);throw new Error("Unexpected situation")}function o(e,t){return"__proto__"===t?void 0:e[t]}var i=e.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var e,t,a=arguments[0];return Array.prototype.slice.call(arguments,1).forEach(function(u){"object"!=typeof u||null===u||Array.isArray(u)||Object.keys(u).forEach(function(s){return t=o(a,s),(e=o(u,s))===a?void 0:"object"!=typeof e||null===e?void(a[s]=e):Array.isArray(e)?void(a[s]=function e(t){var o=[];return t.forEach(function(t,a){"object"==typeof t&&null!==t?Array.isArray(t)?o[a]=e(t):n(t)?o[a]=r(t):o[a]=i({},t):o[a]=t}),o}(e)):n(e)?void(a[s]=r(e)):"object"!=typeof t||null===t||Array.isArray(t)?void(a[s]=i({},e)):void(a[s]=i(t,e))})}),a}}).call(t,n(55).Buffer)},function(e,t,n){"use strict";e.exports=function(e){return"object"==typeof e?function e(t,n){var r;r=Array.isArray(t)?[]:{};n.push(t);Object.keys(t).forEach(function(o){var i=t[o];"function"!=typeof i&&(i&&"object"==typeof i?-1!==n.indexOf(t[o])?r[o]="[Circular]":r[o]=e(t[o],n.slice(0)):r[o]=i)});"string"==typeof t.name&&(r.name=t.name);"string"==typeof t.message&&(r.message=t.message);"string"==typeof t.stack&&(r.stack=t.stack);return r}(e,[]):"function"==typeof e?"[Function: "+(e.name||"anonymous")+"]":e}},function(e,t,n){var r=n(590),o=n(606),i=n(608),a=n(609),u=n(610);function s(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e<=n}},function(e,t){e.exports=function(e){return function(t){return e(t)}}},function(e,t,n){(function(e){var r=n(278),o="object"==typeof t&&t&&!t.nodeType&&t,i=o&&"object"==typeof e&&e&&!e.nodeType&&e,a=i&&i.exports===o&&r.process,u=function(){try{var e=i&&i.require&&i.require("util").types;return e||a&&a.binding&&a.binding("util")}catch(e){}}();e.exports=u}).call(t,n(134)(e))},function(e,t,n){var r=n(24),o=n(128),i=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,a=/^\w*$/;e.exports=function(e,t){if(r(e))return!1;var n=typeof e;return!("number"!=n&&"symbol"!=n&&"boolean"!=n&&null!=e&&!o(e))||a.test(e)||!i.test(e)||null!=t&&e in Object(t)}},function(e,t){e.exports=function(e){return e}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.memoizedSampleFromSchema=t.memoizedCreateXMLExample=t.sampleXmlFromSchema=t.inferSchema=t.sampleFromSchema=void 0,t.createXMLExample=f;var r=n(12),o=a(n(657)),i=a(n(670));function a(e){return e&&e.__esModule?e:{default:e}}var u={string:function(){return"string"},string_email:function(){return"user@example.com"},"string_date-time":function(){return(new Date).toISOString()},number:function(){return 0},number_float:function(){return 0},integer:function(){return 0},boolean:function(e){return"boolean"!=typeof e.default||e.default}},s=function(e){var t=e=(0,r.objectify)(e),n=t.type,o=t.format,i=u[n+"_"+o]||u[n];return(0,r.isFunc)(i)?i(e):"Unknown Type: "+e.type},l=t.sampleFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=(0,r.objectify)(t),i=o.type,a=o.example,u=o.properties,l=o.additionalProperties,c=o.items,f=n.includeReadOnly,p=n.includeWriteOnly;if(void 0!==a)return(0,r.deeplyStripKey)(a,"$$ref",function(e){return"string"==typeof e&&e.indexOf("#")>-1});if(!i)if(u)i="object";else{if(!c)return;i="array"}if("object"===i){var d=(0,r.objectify)(u),h={};for(var v in d)d[v]&&d[v].readOnly&&!f||d[v]&&d[v].writeOnly&&!p||(h[v]=e(d[v],n));if(!0===l)h.additionalProp1={};else if(l)for(var m=(0,r.objectify)(l),g=e(m,n),y=1;y<4;y++)h["additionalProp"+y]=g;return h}return"array"===i?Array.isArray(c.anyOf)?c.anyOf.map(function(t){return e(t,n)}):Array.isArray(c.oneOf)?c.oneOf.map(function(t){return e(t,n)}):[e(c,n)]:t.enum?t.default?t.default:(0,r.normalizeArray)(t.enum)[0]:"file"!==i?s(t):void 0},c=(t.inferSchema=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},t.sampleXmlFromSchema=function e(t){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=(0,r.objectify)(t),a=i.type,u=i.properties,l=i.additionalProperties,c=i.items,f=i.example,p=o.includeReadOnly,d=o.includeWriteOnly,h=i.default,v={},m={},g=t.xml,y=g.name,b=g.prefix,_=g.namespace,w=i.enum,E=void 0;if(!a)if(u||l)a="object";else{if(!c)return;a="array"}(y=y||"notagname",n=(b?b+":":"")+y,_)&&(m[b?"xmlns:"+b:"xmlns"]=_);if("array"===a&&c){if(c.xml=c.xml||g||{},c.xml.name=c.xml.name||g.name,g.wrapped)return v[n]=[],Array.isArray(f)?f.forEach(function(t){c.example=t,v[n].push(e(c,o))}):Array.isArray(h)?h.forEach(function(t){c.default=t,v[n].push(e(c,o))}):v[n]=[e(c,o)],m&&v[n].push({_attr:m}),v;var x=[];return Array.isArray(f)?(f.forEach(function(t){c.example=t,x.push(e(c,o))}),x):Array.isArray(h)?(h.forEach(function(t){c.default=t,x.push(e(c,o))}),x):e(c,o)}if("object"===a){var S=(0,r.objectify)(u);for(var C in v[n]=[],f=f||{},S)if(S.hasOwnProperty(C)&&(!S[C].readOnly||p)&&(!S[C].writeOnly||d))if(S[C].xml=S[C].xml||{},S[C].xml.attribute){var k=Array.isArray(S[C].enum)&&S[C].enum[0],A=S[C].example,O=S[C].default;m[S[C].xml.name||C]=void 0!==A&&A||void 0!==f[C]&&f[C]||void 0!==O&&O||k||s(S[C])}else{S[C].xml.name=S[C].xml.name||C,void 0===S[C].example&&void 0!==f[C]&&(S[C].example=f[C]);var P=e(S[C]);Array.isArray(P)?v[n]=v[n].concat(P):v[n].push(P)}return!0===l?v[n].push({additionalProp:"Anything can be here"}):l&&v[n].push({additionalProp:s(l)}),m&&v[n].push({_attr:m}),v}return E=void 0!==f?f:void 0!==h?h:Array.isArray(w)?w[0]:s(t),v[n]=m?[{_attr:m},E]:E,v});function f(e,t){var n=c(e,t);if(n)return(0,o.default)(n,{declaration:!0,indent:"\t"})}t.memoizedCreateXMLExample=(0,i.default)(f),t.memoizedSampleFromSchema=(0,i.default)(l)},function(e,t){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function o(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,n,a,u,s,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var c=new Error('Uncaught, unspecified "error" event. ('+t+")");throw c.context=t,c}if(i(n=this._events[e]))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:u=Array.prototype.slice.call(arguments,1),n.apply(this,u)}else if(o(n))for(u=Array.prototype.slice.call(arguments,1),a=(l=n.slice()).length,s=0;s0&&this._events[e].length>a&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function o(){this.removeListener(e,o),n||(n=!0,t.apply(this,arguments))}return o.listener=t,this.on(e,o),this},n.prototype.removeListener=function(e,t){var n,i,a,u;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(a=(n=this._events[e]).length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(u=a;u-- >0;)if(n[u]===t||n[u].listener&&n[u].listener===t){i=u;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){(t=e.exports=n(306)).Stream=t,t.Readable=t,t.Writable=n(196),t.Duplex=n(64),t.Transform=n(311),t.PassThrough=n(665)},function(e,t,n){"use strict";(function(t,r,o){var i=n(140);function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,n){var r=e.entry;e.entry=null;for(;r;){var o=r.callback;t.pendingcb--,o(n),r=r.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=y;var u,s=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?r:i.nextTick;y.WritableState=g;var l=n(107);l.inherits=n(81);var c={deprecate:n(664)},f=n(307),p=n(141).Buffer,d=o.Uint8Array||function(){};var h,v=n(308);function m(){}function g(e,t){u=u||n(64),e=e||{};var r=t instanceof u;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var o=e.highWaterMark,l=e.writableHighWaterMark,c=this.objectMode?16:16384;this.highWaterMark=o||0===o?o:r&&(l||0===l)?l:c,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var n=e._writableState,r=n.sync,o=n.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(n),t)!function(e,t,n,r,o){--t.pendingcb,n?(i.nextTick(o,r),i.nextTick(S,e,t),e._writableState.errorEmitted=!0,e.emit("error",r)):(o(r),e._writableState.errorEmitted=!0,e.emit("error",r),S(e,t))}(e,n,r,t,o);else{var a=E(n);a||n.corked||n.bufferProcessing||!n.bufferedRequest||w(e,n),r?s(_,e,n,a,o):_(e,n,a,o)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function y(e){if(u=u||n(64),!(h.call(y,this)||this instanceof u))return new y(e);this._writableState=new g(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function b(e,t,n,r,o,i,a){t.writelen=r,t.writecb=a,t.writing=!0,t.sync=!0,n?e._writev(o,t.onwrite):e._write(o,i,t.onwrite),t.sync=!1}function _(e,t,n,r){n||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,r(),S(e,t)}function w(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=new Array(r),i=t.corkedRequestsFree;i.entry=n;for(var u=0,s=!0;n;)o[u]=n,n.isBuf||(s=!1),n=n.next,u+=1;o.allBuffers=s,b(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;n;){var l=n.chunk,c=n.encoding,f=n.callback;if(b(e,t,!1,t.objectMode?1:l.length,l,c,f),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function E(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function x(e,t){e._final(function(n){t.pendingcb--,n&&e.emit("error",n),t.prefinished=!0,e.emit("prefinish"),S(e,t)})}function S(e,t){var n=E(t);return n&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,i.nextTick(x,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),n}l.inherits(y,f),g.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(g.prototype,"buffer",{get:c.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(h=Function.prototype[Symbol.hasInstance],Object.defineProperty(y,Symbol.hasInstance,{value:function(e){return!!h.call(this,e)||this===y&&(e&&e._writableState instanceof g)}})):h=function(e){return e instanceof this},y.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},y.prototype.write=function(e,t,n){var r,o=this._writableState,a=!1,u=!o.objectMode&&(r=e,p.isBuffer(r)||r instanceof d);return u&&!p.isBuffer(e)&&(e=function(e){return p.from(e)}(e)),"function"==typeof t&&(n=t,t=null),u?t="buffer":t||(t=o.defaultEncoding),"function"!=typeof n&&(n=m),o.ended?function(e,t){var n=new Error("write after end");e.emit("error",n),i.nextTick(t,n)}(this,n):(u||function(e,t,n,r){var o=!0,a=!1;return null===n?a=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(a=new TypeError("Invalid non-string/buffer chunk")),a&&(e.emit("error",a),i.nextTick(r,a),o=!1),o}(this,o,e,n))&&(o.pendingcb++,a=function(e,t,n,r,o,i){if(!n){var a=function(e,t,n){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=p.from(t,n));return t}(t,r,o);r!==a&&(n=!0,o="buffer",r=a)}var u=t.objectMode?1:r.length;t.length+=u;var s=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(y.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),y.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},y.prototype._writev=null,y.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!==e&&void 0!==e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||function(e,t,n){t.ending=!0,S(e,t),n&&(t.finished?i.nextTick(n):e.once("finish",n));t.ended=!0,e.writable=!1}(this,r,n)},Object.defineProperty(y.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),y.prototype.destroy=v.destroy,y.prototype._undestroy=v.undestroy,y.prototype._destroy=function(e,t){this.end(),t(e)}}).call(t,n(56),n(309).setImmediate,n(32))},function(e,t,n){"use strict";e.exports=function(e){return"function"==typeof e}},function(e,t,n){"use strict";e.exports=n(691)()?Array.from:n(692)},function(e,t,n){"use strict";var r=n(705),o=n(66),i=n(82),a=Array.prototype.indexOf,u=Object.prototype.hasOwnProperty,s=Math.abs,l=Math.floor;e.exports=function(e){var t,n,c,f;if(!r(e))return a.apply(this,arguments);for(n=o(i(this).length),c=arguments[1],t=c=isNaN(c)?0:c>=0?l(c):o(this.length)-l(s(c));t1&&void 0!==arguments[1])||arguments[1];return e=(0,r.normalizeArray)(e),{type:u,payload:{thing:e,shown:t}}},t.changeMode=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=(0,r.normalizeArray)(e),{type:a,payload:{thing:e,mode:t}}};var r=n(12),o=t.UPDATE_LAYOUT="layout_update_layout",i=t.UPDATE_FILTER="layout_update_filter",a=t.UPDATE_MODE="layout_update_mode",u=t.SHOW="layout_show"},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.validateBeforeExecute=t.canExecuteScheme=t.operationScheme=t.hasHost=t.operationWithMeta=t.parameterWithMeta=t.parameterInclusionSettingFor=t.parameterWithMetaByIdentity=t.allowTryItOutFor=t.mutatedRequestFor=t.requestFor=t.responseFor=t.mutatedRequests=t.requests=t.responses=t.taggedOperations=t.operationsWithTags=t.tagDetails=t.tags=t.operationsWithRootInherited=t.schemes=t.host=t.basePath=t.definitions=t.findDefinition=t.securityDefinitions=t.security=t.produces=t.consumes=t.operations=t.paths=t.semver=t.version=t.externalDocs=t.info=t.isOAS3=t.spec=t.specJsonWithResolvedSubtrees=t.specResolvedSubtree=t.specResolved=t.specJson=t.specSource=t.specStr=t.url=t.lastError=void 0;var r,o=n(83),i=(r=o)&&r.__esModule?r:{default:r};t.getParameter=function(e,t,n,r){return t=t||[],e.getIn(["meta","paths"].concat((0,i.default)(t),["parameters"]),(0,s.fromJS)([])).find(function(e){return s.Map.isMap(e)&&e.get("name")===n&&e.get("in")===r})||(0,s.Map)()},t.parameterValues=function(e,t,n){return t=t||[],P.apply(void 0,[e].concat((0,i.default)(t))).get("parameters",(0,s.List)()).reduce(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(t.get("in")+"."+t.get("name"),r)},(0,s.fromJS)({}))},t.parametersIncludeIn=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(s.List.isList(e))return e.some(function(e){return s.Map.isMap(e)&&e.get("in")===t})},t.parametersIncludeType=T,t.contentTypeValues=function(e,t){t=t||[];var n=d(e).getIn(["paths"].concat((0,i.default)(t)),(0,s.fromJS)({})),r=e.getIn(["meta","paths"].concat((0,i.default)(t)),(0,s.fromJS)({})),o=M(e,t),a=n.get("parameters")||new s.List,u=r.get("consumes_value")?r.get("consumes_value"):T(a,"file")?"multipart/form-data":T(a,"formData")?"application/x-www-form-urlencoded":void 0;return(0,s.fromJS)({requestContentType:u,responseContentType:o})},t.operationConsumes=function(e,t){return t=t||[],d(e).getIn(["paths"].concat((0,i.default)(t),["consumes"]),(0,s.fromJS)({}))},t.currentProducesFor=M;var a=n(58),u=n(12),s=n(7);var l=["get","put","post","delete","options","head","patch","trace"],c=function(e){return e||(0,s.Map)()},f=(t.lastError=(0,a.createSelector)(c,function(e){return e.get("lastError")}),t.url=(0,a.createSelector)(c,function(e){return e.get("url")}),t.specStr=(0,a.createSelector)(c,function(e){return e.get("spec")||""}),t.specSource=(0,a.createSelector)(c,function(e){return e.get("specSource")||"not-editor"}),t.specJson=(0,a.createSelector)(c,function(e){return e.get("json",(0,s.Map)())})),p=(t.specResolved=(0,a.createSelector)(c,function(e){return e.get("resolved",(0,s.Map)())}),t.specResolvedSubtree=function(e,t){return e.getIn(["resolvedSubtrees"].concat((0,i.default)(t)),void 0)},function e(t,n){return s.Map.isMap(t)&&s.Map.isMap(n)?n.get("$$ref")?n:(0,s.OrderedMap)().mergeWith(e,t,n):n}),d=t.specJsonWithResolvedSubtrees=(0,a.createSelector)(c,function(e){return(0,s.OrderedMap)().mergeWith(p,e.get("json"),e.get("resolvedSubtrees"))}),h=t.spec=function(e){return f(e)},v=(t.isOAS3=(0,a.createSelector)(h,function(){return!1}),t.info=(0,a.createSelector)(h,function(e){return j(e&&e.get("info"))})),m=(t.externalDocs=(0,a.createSelector)(h,function(e){return j(e&&e.get("externalDocs"))}),t.version=(0,a.createSelector)(v,function(e){return e&&e.get("version")})),g=(t.semver=(0,a.createSelector)(m,function(e){return/v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(e).slice(1)}),t.paths=(0,a.createSelector)(d,function(e){return e.get("paths")})),y=t.operations=(0,a.createSelector)(g,function(e){if(!e||e.size<1)return(0,s.List)();var t=(0,s.List)();return e&&e.forEach?(e.forEach(function(e,n){if(!e||!e.forEach)return{};e.forEach(function(e,r){l.indexOf(r)<0||(t=t.push((0,s.fromJS)({path:n,method:r,operation:e,id:r+"-"+n})))})}),t):(0,s.List)()}),b=t.consumes=(0,a.createSelector)(h,function(e){return(0,s.Set)(e.get("consumes"))}),_=t.produces=(0,a.createSelector)(h,function(e){return(0,s.Set)(e.get("produces"))}),w=(t.security=(0,a.createSelector)(h,function(e){return e.get("security",(0,s.List)())}),t.securityDefinitions=(0,a.createSelector)(h,function(e){return e.get("securityDefinitions")}),t.findDefinition=function(e,t){var n=e.getIn(["resolvedSubtrees","definitions",t],null),r=e.getIn(["json","definitions",t],null);return n||r||null},t.definitions=(0,a.createSelector)(h,function(e){return e.get("definitions")||(0,s.Map)()}),t.basePath=(0,a.createSelector)(h,function(e){return e.get("basePath")}),t.host=(0,a.createSelector)(h,function(e){return e.get("host")}),t.schemes=(0,a.createSelector)(h,function(e){return e.get("schemes",(0,s.Map)())}),t.operationsWithRootInherited=(0,a.createSelector)(y,b,_,function(e,t,n){return e.map(function(e){return e.update("operation",function(e){if(e){if(!s.Map.isMap(e))return;return e.withMutations(function(e){return e.get("consumes")||e.update("consumes",function(e){return(0,s.Set)(e).merge(t)}),e.get("produces")||e.update("produces",function(e){return(0,s.Set)(e).merge(n)}),e})}return(0,s.Map)()})})})),E=t.tags=(0,a.createSelector)(h,function(e){return e.get("tags",(0,s.List)())}),x=t.tagDetails=function(e,t){return(E(e)||(0,s.List)()).filter(s.Map.isMap).find(function(e){return e.get("name")===t},(0,s.Map)())},S=t.operationsWithTags=(0,a.createSelector)(w,E,function(e,t){return e.reduce(function(e,t){var n=(0,s.Set)(t.getIn(["operation","tags"]));return n.count()<1?e.update("default",(0,s.List)(),function(e){return e.push(t)}):n.reduce(function(e,n){return e.update(n,(0,s.List)(),function(e){return e.push(t)})},e)},t.reduce(function(e,t){return e.set(t.get("name"),(0,s.List)())},(0,s.OrderedMap)()))}),C=(t.taggedOperations=function(e){return function(t){var n=(0,t.getConfigs)(),r=n.tagsSorter,o=n.operationsSorter;return S(e).sortBy(function(e,t){return t},function(e,t){var n="function"==typeof r?r:u.sorters.tagsSorter[r];return n?n(e,t):null}).map(function(t,n){var r="function"==typeof o?o:u.sorters.operationsSorter[o],i=r?t.sort(r):t;return(0,s.Map)({tagDetails:x(e,n),operations:i})})}},t.responses=(0,a.createSelector)(c,function(e){return e.get("responses",(0,s.Map)())})),k=t.requests=(0,a.createSelector)(c,function(e){return e.get("requests",(0,s.Map)())}),A=t.mutatedRequests=(0,a.createSelector)(c,function(e){return e.get("mutatedRequests",(0,s.Map)())}),O=(t.responseFor=function(e,t,n){return C(e).getIn([t,n],null)},t.requestFor=function(e,t,n){return k(e).getIn([t,n],null)},t.mutatedRequestFor=function(e,t,n){return A(e).getIn([t,n],null)},t.allowTryItOutFor=function(){return!0},t.parameterWithMetaByIdentity=function(e,t,n){var r=d(e).getIn(["paths"].concat((0,i.default)(t),["parameters"]),(0,s.OrderedMap)()),o=e.getIn(["meta","paths"].concat((0,i.default)(t),["parameters"]),(0,s.OrderedMap)());return r.map(function(e){var t=o.get(n.get("name")+"."+n.get("in")),r=o.get(n.get("name")+"."+n.get("in")+".hash-"+n.hashCode());return(0,s.OrderedMap)().merge(e,t,r)}).find(function(e){return e.get("in")===n.get("in")&&e.get("name")===n.get("name")},(0,s.OrderedMap)())}),P=(t.parameterInclusionSettingFor=function(e,t,n,r){var o=n+"."+r;return e.getIn(["meta","paths"].concat((0,i.default)(t),["parameter_inclusions",o]),!1)},t.parameterWithMeta=function(e,t,n,r){var o=d(e).getIn(["paths"].concat((0,i.default)(t),["parameters"]),(0,s.OrderedMap)()).find(function(e){return e.get("in")===r&&e.get("name")===n},(0,s.OrderedMap)());return O(e,t,o)},t.operationWithMeta=function(e,t,n){var r=d(e).getIn(["paths",t,n],(0,s.OrderedMap)()),o=e.getIn(["meta","paths",t,n],(0,s.OrderedMap)()),i=r.get("parameters",(0,s.List)()).map(function(r){return O(e,[t,n],r)});return(0,s.OrderedMap)().merge(r,o).set("parameters",i)});t.hasHost=(0,a.createSelector)(h,function(e){var t=e.get("host");return"string"==typeof t&&t.length>0&&"/"!==t[0]});function T(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(s.List.isList(e))return e.some(function(e){return s.Map.isMap(e)&&e.get("type")===t})}function M(e,t){t=t||[];var n=d(e).getIn(["paths"].concat((0,i.default)(t)),null);if(null!==n){var r=e.getIn(["meta","paths"].concat((0,i.default)(t),["produces_value"]),null),o=n.getIn(["produces",0],null);return r||o||"application/json"}}var I=t.operationScheme=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),o=Array.isArray(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||o||""};t.canExecuteScheme=function(e,t,n){return["http","https"].indexOf(I(e,t,n))>-1},t.validateBeforeExecute=function(e,t){t=t||[];var n=!0;return e.getIn(["meta","paths"].concat((0,i.default)(t),["parameters"]),(0,s.fromJS)([])).forEach(function(e){var t=e.get("errors");t&&t.count()&&(n=!1)}),n};function j(e){return s.Map.isMap(e)?e:new s.Map}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.execute=t.executeRequest=t.logRequest=t.setMutatedRequest=t.setRequest=t.setResponse=t.updateEmptyParamInclusion=t.validateParams=t.invalidateResolvedSubtreeCache=t.updateResolvedSubtree=t.requestResolvedSubtree=t.resolveSpec=t.parseToJson=t.SET_SCHEME=t.UPDATE_RESOLVED_SUBTREE=t.UPDATE_RESOLVED=t.UPDATE_OPERATION_META_VALUE=t.CLEAR_VALIDATE_PARAMS=t.CLEAR_REQUEST=t.CLEAR_RESPONSE=t.LOG_REQUEST=t.SET_MUTATED_REQUEST=t.SET_REQUEST=t.SET_RESPONSE=t.VALIDATE_PARAMS=t.UPDATE_EMPTY_PARAM_INCLUSION=t.UPDATE_PARAM=t.UPDATE_JSON=t.UPDATE_URL=t.UPDATE_SPEC=void 0;var r=b(n(25)),o=b(n(84)),i=b(n(23)),a=b(n(41)),u=b(n(204)),s=b(n(339)),l=b(n(340)),c=b(n(45));t.updateSpec=function(e){var t=L(e).replace(/\t/g," ");if("string"==typeof e)return{type:_,payload:t}},t.updateResolved=function(e){return{type:N,payload:e}},t.updateUrl=function(e){return{type:w,payload:e}},t.updateJsonSpec=function(e){return{type:E,payload:e}},t.changeParam=function(e,t,n,r,o){return{type:x,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}},t.changeParamByIdentity=function(e,t,n,r){return{type:x,payload:{path:e,param:t,value:n,isXml:r}}},t.clearValidateParams=function(e){return{type:I,payload:{pathMethod:e}}},t.changeConsumesValue=function(e,t){return{type:j,payload:{path:e,value:t,key:"consumes_value"}}},t.changeProducesValue=function(e,t){return{type:j,payload:{path:e,value:t,key:"produces_value"}}},t.clearResponse=function(e,t){return{type:T,payload:{path:e,method:t}}},t.clearRequest=function(e,t){return{type:M,payload:{path:e,method:t}}},t.setScheme=function(e,t,n){return{type:D,payload:{scheme:e,path:t,method:n}}};var f=b(n(208)),p=n(7),d=b(n(210)),h=b(n(180)),v=b(n(343)),m=b(n(765)),g=b(n(767)),y=n(12);function b(e){return e&&e.__esModule?e:{default:e}}var _=t.UPDATE_SPEC="spec_update_spec",w=t.UPDATE_URL="spec_update_url",E=t.UPDATE_JSON="spec_update_json",x=t.UPDATE_PARAM="spec_update_param",S=t.UPDATE_EMPTY_PARAM_INCLUSION="spec_update_empty_param_inclusion",C=t.VALIDATE_PARAMS="spec_validate_param",k=t.SET_RESPONSE="spec_set_response",A=t.SET_REQUEST="spec_set_request",O=t.SET_MUTATED_REQUEST="spec_set_mutated_request",P=t.LOG_REQUEST="spec_log_request",T=t.CLEAR_RESPONSE="spec_clear_response",M=t.CLEAR_REQUEST="spec_clear_request",I=t.CLEAR_VALIDATE_PARAMS="spec_clear_validate_param",j=t.UPDATE_OPERATION_META_VALUE="spec_update_operation_meta_value",N=t.UPDATE_RESOLVED="spec_update_resolved",R=t.UPDATE_RESOLVED_SUBTREE="spec_update_resolved_subtree",D=t.SET_SCHEME="set_scheme",L=function(e){return(0,v.default)(e)?e:""};t.parseToJson=function(e){return function(t){var n=t.specActions,r=t.specSelectors,o=t.errActions,i=r.specStr,a=null;try{e=e||i(),o.clear({source:"parser"}),a=f.default.safeLoad(e)}catch(e){return console.error(e),o.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return a&&"object"===(void 0===a?"undefined":(0,c.default)(a))?n.updateJsonSpec(a):{}}};var U=!1,q=(t.resolveSpec=function(e,t){return function(n){var r=n.specActions,o=n.specSelectors,i=n.errActions,a=n.fn,u=a.fetch,s=a.resolve,l=a.AST,c=void 0===l?{}:l,f=n.getConfigs;U||(console.warn("specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!"),U=!0);var p=f(),d=p.modelPropertyMacro,h=p.parameterMacro,v=p.requestInterceptor,m=p.responseInterceptor;void 0===e&&(e=o.specJson()),void 0===t&&(t=o.url());var g=c.getLineNumberForPath?c.getLineNumberForPath:function(){},y=o.specStr();return s({fetch:u,spec:e,baseDoc:t,modelPropertyMacro:d,parameterMacro:h,requestInterceptor:v,responseInterceptor:m}).then(function(e){var t=e.spec,n=e.errors;if(i.clear({type:"thrown"}),Array.isArray(n)&&n.length>0){var o=n.map(function(e){return console.error(e),e.line=e.fullPath?g(y,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e});i.newThrownErrBatch(o)}return r.updateResolved(t)})}},[]),F=(0,m.default)((0,l.default)(s.default.mark(function e(){var t,n,r,o,i,a,c,f,d,h,v,m,y,b,_,w,E;return s.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(t=q.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,i=o.resolveSubtree,a=o.AST,c=void 0===a?{}:a,f=t.specSelectors,d=t.specActions,i){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return h=c.getLineNumberForPath?c.getLineNumberForPath:function(){},v=f.specStr(),m=t.getConfigs(),y=m.modelPropertyMacro,b=m.parameterMacro,_=m.requestInterceptor,w=m.responseInterceptor,e.prev=11,e.next=14,q.reduce(function(){var e=(0,l.default)(s.default.mark(function e(t,o){var a,u,l,c,p,d,m;return s.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return a=e.sent,u=a.resultMap,l=a.specWithCurrentSubtrees,e.next=7,i(l,o,{baseDoc:f.url(),modelPropertyMacro:y,parameterMacro:b,requestInterceptor:_,responseInterceptor:w});case 7:return c=e.sent,p=c.errors,d=c.spec,r.allErrors().size&&n.clear({type:"thrown"}),Array.isArray(p)&&p.length>0&&(m=p.map(function(e){return e.line=e.fullPath?h(v,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e}),n.newThrownErrBatch(m)),(0,g.default)(u,o,d),(0,g.default)(l,o,d),e.abrupt("return",{resultMap:u,specWithCurrentSubtrees:l});case 15:case"end":return e.stop()}},e,void 0)}));return function(t,n){return e.apply(this,arguments)}}(),u.default.resolve({resultMap:(f.specResolvedSubtree([])||(0,p.Map)()).toJS(),specWithCurrentSubtrees:f.specJson().toJS()}));case 14:E=e.sent,delete q.system,q=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:d.updateResolvedSubtree([],E.resultMap);case 23:case"end":return e.stop()}},e,void 0,[[11,19]])})),35);t.requestResolvedSubtree=function(e){return function(t){q.push(e),q.system=t,F()}};t.updateResolvedSubtree=function(e,t){return{type:R,payload:{path:e,value:t}}},t.invalidateResolvedSubtreeCache=function(){return{type:R,payload:{path:[],value:(0,p.Map)()}}},t.validateParams=function(e,t){return{type:C,payload:{pathMethod:e,isOAS3:t}}},t.updateEmptyParamInclusion=function(e,t,n,r){return{type:S,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};t.setResponse=function(e,t,n){return{payload:{path:e,method:t,res:n},type:k}},t.setRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:A}},t.setMutatedRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:O}},t.logRequest=function(e){return{payload:e,type:P}},t.executeRequest=function(e){return function(t){var n=t.fn,r=t.specActions,o=t.specSelectors,u=t.getConfigs,s=t.oas3Selectors,l=e.pathName,c=e.method,f=e.operation,p=u(),v=p.requestInterceptor,m=p.responseInterceptor,g=f.toJS();if(g&&g.parameters&&g.parameters.length&&g.parameters.filter(function(e){return e&&!0===e.allowEmptyValue}).forEach(function(t){if(o.parameterInclusionSettingFor([l,c],t.name,t.in)){e.parameters=e.parameters||{};var n=e.parameters[t.name];(!n||n&&0===n.size)&&(e.parameters[t.name]="")}}),e.contextUrl=(0,d.default)(o.url()).toString(),g&&g.operationId?e.operationId=g.operationId:g&&l&&c&&(e.operationId=n.opId(g,l,c)),o.isOAS3()){var b=l+":"+c;e.server=s.selectedServer(b)||s.selectedServer();var _=s.serverVariables({server:e.server,namespace:b}).toJS(),w=s.serverVariables({server:e.server}).toJS();e.serverVariables=(0,a.default)(_).length?_:w,e.requestContentType=s.requestContentType(l,c),e.responseContentType=s.responseContentType(l,c)||"*/*";var E=s.requestBodyValue(l,c);(0,y.isJSONObject)(E)?e.requestBody=JSON.parse(E):E&&E.toJS?e.requestBody=E.toJS():e.requestBody=E}var x=(0,i.default)({},e);x=n.buildRequest(x),r.setRequest(e.pathName,e.method,x);e.requestInterceptor=function(t){var n=v.apply(this,[t]),o=(0,i.default)({},n);return r.setMutatedRequest(e.pathName,e.method,o),n},e.responseInterceptor=m;var S=Date.now();return n.execute(e).then(function(t){t.duration=Date.now()-S,r.setResponse(e.pathName,e.method,t)}).catch(function(t){return r.setResponse(e.pathName,e.method,{error:!0,err:(0,h.default)(t)})})}};t.execute=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,i=(0,o.default)(e,["path","method"]);return function(e){var o=e.fn.fetch,a=e.specSelectors,u=e.specActions,s=a.specJsonWithResolvedSubtrees().toJS(),l=a.operationScheme(t,n),c=a.contentTypeValues([t,n]).toJS(),f=c.requestContentType,p=c.responseContentType,d=/xml/i.test(f),h=a.parameterValues([t,n],d).toJS();return u.executeRequest((0,r.default)({},i,{fetch:o,spec:s,pathName:t,method:n,parameters:h,requestContentType:f,scheme:l,responseContentType:p}))}}},function(e,t,n){e.exports={default:n(733),__esModule:!0}},function(e,t){e.exports=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+": incorrect invocation!");return e}},function(e,t,n){"use strict";var r=n(95);e.exports.f=function(e){return new function(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=r(t),this.reject=r(n)}(e)}},function(e,t,n){var r=n(50);e.exports=function(e,t,n){for(var o in t)n&&e[o]?e[o]=t[o]:r(e,o,t[o]);return e}},function(e,t,n){"use strict";var r=n(743);e.exports=r},function(e,t,n){"use strict";var r=n(86);e.exports=new r({explicit:[n(746),n(747),n(748)]})},function(e,t,n){"use strict";(function(t){var r=n(763),o=n(764),i=/^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i,a=/^[A-Za-z][A-Za-z0-9+-.]*:\/\//,u=[["#","hash"],["?","query"],function(e){return e.replace("\\","/")},["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d+)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],s={hash:1,query:1};function l(e){var n,r=t&&t.location||{},o={},i=typeof(e=e||r);if("blob:"===e.protocol)o=new f(unescape(e.pathname),{});else if("string"===i)for(n in o=new f(e,{}),s)delete o[n];else if("object"===i){for(n in e)n in s||(o[n]=e[n]);void 0===o.slashes&&(o.slashes=a.test(e.href))}return o}function c(e){var t=i.exec(e);return{protocol:t[1]?t[1].toLowerCase():"",slashes:!!t[2],rest:t[3]}}function f(e,t,n){if(!(this instanceof f))return new f(e,t,n);var i,a,s,p,d,h,v=u.slice(),m=typeof t,g=this,y=0;for("object"!==m&&"string"!==m&&(n=t,t=null),n&&"function"!=typeof n&&(n=o.parse),t=l(t),i=!(a=c(e||"")).protocol&&!a.slashes,g.slashes=a.slashes||i&&t.slashes,g.protocol=a.protocol||t.protocol||"",e=a.rest,a.slashes||(v[3]=[/(.*)/,"pathname"]);y-1||r("96",e),!l.plugins[n]){t.extractEvents||r("97",e),l.plugins[n]=t;var a=t.eventTypes;for(var s in a)u(a[s],t,s)||r("98",s,e)}}}function u(e,t,n){l.eventNameDispatchConfigs.hasOwnProperty(n)&&r("99",n),l.eventNameDispatchConfigs[n]=e;var o=e.phasedRegistrationNames;if(o){for(var i in o){if(o.hasOwnProperty(i))s(o[i],t,n)}return!0}return!!e.registrationName&&(s(e.registrationName,t,n),!0)}function s(e,t,n){l.registrationNameModules[e]&&r("100",e),l.registrationNameModules[e]=t,l.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var l={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},possibleRegistrationNames:null,injectEventPluginOrder:function(e){o&&r("101"),o=Array.prototype.slice.call(e),a()},injectEventPluginsByName:function(e){var t=!1;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];i.hasOwnProperty(n)&&i[n]===o||(i[n]&&r("102",n),i[n]=o,t=!0)}t&&a()},getPluginModuleForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return l.registrationNameModules[t.registrationName]||null;if(void 0!==t.phasedRegistrationNames){var n=t.phasedRegistrationNames;for(var r in n)if(n.hasOwnProperty(r)){var o=l.registrationNameModules[n[r]];if(o)return o}}return null},_resetEventPlugins:function(){for(var e in o=null,i)i.hasOwnProperty(e)&&delete i[e];l.plugins.length=0;var t=l.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=l.registrationNameModules;for(var a in r)r.hasOwnProperty(a)&&delete r[a]}};e.exports=l},function(e,t,n){"use strict";var r,o,i=n(9),a=n(213);n(8),n(11);function u(e,t,n,r){var o=e.type||"unknown-event";e.currentTarget=s.getNodeFromInstance(r),t?a.invokeGuardedCallbackWithCatch(o,n,e):a.invokeGuardedCallback(o,n,e),e.currentTarget=null}var s={isEndish:function(e){return"topMouseUp"===e||"topTouchEnd"===e||"topTouchCancel"===e},isMoveish:function(e){return"topMouseMove"===e||"topTouchMove"===e},isStartish:function(e){return"topMouseDown"===e||"topTouchStart"===e},executeDirectDispatch:function(e){var t=e._dispatchListeners,n=e._dispatchInstances;Array.isArray(t)&&i("103"),e.currentTarget=t?s.getNodeFromInstance(n):null;var r=t?t(e):null;return e.currentTarget=null,e._dispatchListeners=null,e._dispatchInstances=null,r},executeDispatchesInOrder:function(e,t){var n=e._dispatchListeners,r=e._dispatchInstances;if(Array.isArray(n))for(var o=0;o0&&r.length<20?n+" (keys: "+r.join(", ")+")":n}function s(e,t){var n=o.get(e);return n||null}var l={isMounted:function(e){var t=o.get(e);return!!t&&!!t._renderedComponent},enqueueCallback:function(e,t,n){l.validateCallback(t,n);var r=s(e);if(!r)return null;r._pendingCallbacks?r._pendingCallbacks.push(t):r._pendingCallbacks=[t],a(r)},enqueueCallbackInternal:function(e,t){e._pendingCallbacks?e._pendingCallbacks.push(t):e._pendingCallbacks=[t],a(e)},enqueueForceUpdate:function(e){var t=s(e);t&&(t._pendingForceUpdate=!0,a(t))},enqueueReplaceState:function(e,t,n){var r=s(e);r&&(r._pendingStateQueue=[t],r._pendingReplaceState=!0,void 0!==n&&null!==n&&(l.validateCallback(n,"replaceState"),r._pendingCallbacks?r._pendingCallbacks.push(n):r._pendingCallbacks=[n]),a(r))},enqueueSetState:function(e,t){var n=s(e);n&&((n._pendingStateQueue||(n._pendingStateQueue=[])).push(t),a(n))},enqueueElementInternal:function(e,t,n){e._pendingElement=t,e._context=n,a(e)},validateCallback:function(e,t){e&&"function"!=typeof e&&r("122",t,u(e))}};e.exports=l},function(e,t,n){"use strict";n(13);var r=n(42),o=(n(11),r);e.exports=o},function(e,t,n){"use strict";e.exports=function(e){var t,n=e.keyCode;return"charCode"in e?0===(t=e.charCode)&&13===n&&(t=13):t=n,t>=32||13===t?t:0}},function(e,t,n){var r=n(61),o=n(229),i=n(47),a="[object Object]",u=Function.prototype,s=Object.prototype,l=u.toString,c=s.hasOwnProperty,f=l.call(Object);e.exports=function(e){if(!i(e)||r(e)!=a)return!1;var t=o(e);if(null===t)return!0;var n=c.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&l.call(n)==f}},function(e,t,n){var r=n(298)(Object.getPrototypeOf,Object);e.exports=r},function(e,t,n){var r=n(292);e.exports=function(e){var t=new e.constructor(e.byteLength);return new r(t).set(new r(e)),t}},function(e,t){var n=this&&this.__extends||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);function r(){this.constructor=e}e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)},r=Object.prototype.hasOwnProperty; +/*! + * https://github.com/Starcounter-Jack/JSON-Patch + * (c) 2017 Joachim Wester + * MIT license + */function o(e,t){return r.call(e,t)}function i(e){if(Array.isArray(e)){for(var t=new Array(e.length),n=0;n=48&&t<=57))return!1;n++}return!0},t.escapePathComponent=a,t.unescapePathComponent=function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")},t._getPathRecursive=u,t.getPath=function(e,t){if(e===t)return"/";var n=u(e,t);if(""===n)throw new Error("Object not found in root");return"/"+n},t.hasUndefined=function e(t){if(void 0===t)return!0;if(t)if(Array.isArray(t)){for(var n=0,r=t.length;nw;w++)if((p||w in y)&&(m=b(v=y[w],w,g),e))if(n)E[w]=m;else if(m)switch(e){case 3:return!0;case 5:return v;case 6:return w;case 2:E.push(v)}else if(c)return!1;return f?-1:l||c?c:E}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.authorizeRequest=t.authorizeAccessCodeWithBasicAuthentication=t.authorizeAccessCodeWithFormParams=t.authorizeApplication=t.authorizePassword=t.preAuthorizeImplicit=t.CONFIGURE_AUTH=t.VALIDATE=t.AUTHORIZE_OAUTH2=t.PRE_AUTHORIZE_OAUTH2=t.LOGOUT=t.AUTHORIZE=t.SHOW_AUTH_POPUP=void 0;var r=l(n(45)),o=l(n(23)),i=l(n(40));t.showDefinitions=function(e){return{type:c,payload:e}},t.authorize=function(e){return{type:f,payload:e}},t.logout=function(e){return{type:p,payload:e}},t.authorizeOauth2=function(e){return{type:d,payload:e}},t.configureAuth=function(e){return{type:h,payload:e}};var a=l(n(210)),u=l(n(33)),s=n(12);function l(e){return e&&e.__esModule?e:{default:e}}var c=t.SHOW_AUTH_POPUP="show_popup",f=t.AUTHORIZE="authorize",p=t.LOGOUT="logout",d=(t.PRE_AUTHORIZE_OAUTH2="pre_authorize_oauth2",t.AUTHORIZE_OAUTH2="authorize_oauth2"),h=(t.VALIDATE="validate",t.CONFIGURE_AUTH="configure_auth");t.preAuthorizeImplicit=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,a=e.token,s=e.isValid,l=o.schema,c=o.name,f=l.get("flow");delete u.default.swaggerUIRedirectOauth2,"accessCode"===f||s||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),a.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:(0,i.default)(a)}):n.authorizeOauth2({auth:o,token:a})}};t.authorizePassword=function(e){return function(t){var n=t.authActions,r=e.schema,i=e.name,a=e.username,u=e.password,l=e.passwordType,c=e.clientId,f=e.clientSecret,p={grant_type:"password",scope:e.scopes.join(" ")},d={},h={};return"basic"===l?h.Authorization="Basic "+(0,s.btoa)(a+":"+u):((0,o.default)(p,{username:a},{password:u}),"query"===l?(c&&(d.client_id=c),f&&(d.client_secret=f)):h.Authorization="Basic "+(0,s.btoa)(c+":"+f)),n.authorizeRequest({body:(0,s.buildFormData)(p),url:r.get("tokenUrl"),name:i,headers:h,query:d,auth:e})}},t.authorizeApplication=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,i=e.name,a=e.clientId,u=e.clientSecret,l={Authorization:"Basic "+(0,s.btoa)(a+":"+u)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:(0,s.buildFormData)(c),name:i,url:r.get("tokenUrl"),auth:e,headers:l})}},t.authorizeAccessCodeWithFormParams=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,u=t.clientSecret,l={grant_type:"authorization_code",code:t.code,client_id:a,client_secret:u,redirect_uri:n};return r.authorizeRequest({body:(0,s.buildFormData)(l),name:i,url:o.get("tokenUrl"),auth:t})}},t.authorizeAccessCodeWithBasicAuthentication=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,u=t.clientSecret,l={Authorization:"Basic "+(0,s.btoa)(a+":"+u)},c={grant_type:"authorization_code",code:t.code,client_id:a,redirect_uri:n};return r.authorizeRequest({body:(0,s.buildFormData)(c),name:i,url:o.get("tokenUrl"),auth:t,headers:l})}},t.authorizeRequest=function(e){return function(t){var n=t.fn,u=t.getConfigs,s=t.authActions,l=t.errActions,c=t.oas3Selectors,f=t.specSelectors,p=t.authSelectors,d=e.body,h=e.query,v=void 0===h?{}:h,m=e.headers,g=void 0===m?{}:m,y=e.name,b=e.url,_=e.auth,w=(p.getConfigs()||{}).additionalQueryStringParams,E=void 0;E=f.isOAS3()?(0,a.default)(b,c.selectedServer(),!0):(0,a.default)(b,f.url(),!0),"object"===(void 0===w?"undefined":(0,r.default)(w))&&(E.query=(0,o.default)({},E.query,w));var x=E.toString(),S=(0,o.default)({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded"},g);n.fetch({url:x,method:"post",headers:S,query:v,body:d,requestInterceptor:u().requestInterceptor,responseInterceptor:u().responseInterceptor}).then(function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?l.newAuthErr({authId:y,level:"error",source:"auth",message:(0,i.default)(t)}):s.authorizeOauth2({auth:_,token:t}):l.newAuthErr({authId:y,level:"error",source:"auth",message:e.statusText})}).catch(function(e){var t=new Error(e);l.newAuthErr({authId:y,level:"error",source:"auth",message:t.message})})}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parseYamlConfig=void 0;var r,o=n(208),i=(r=o)&&r.__esModule?r:{default:r};t.parseYamlConfig=function(e,t){try{return i.default.safeLoad(e)}catch(e){return t&&t.errActions.newThrownErr(new Error(e)),{}}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.loaded=t.TOGGLE_CONFIGS=t.UPDATE_CONFIGS=void 0;var r,o=n(22),i=(r=o)&&r.__esModule?r:{default:r};t.update=function(e,t){return{type:a,payload:(0,i.default)({},e,t)}},t.toggle=function(e){return{type:u,payload:e}};var a=t.UPDATE_CONFIGS="configs_update",u=t.TOGGLE_CONFIGS="configs_toggle";t.loaded=function(){return function(){}}},function(e,t,n){"use strict";function r(e,t,n,r,o){this.src=e,this.env=r,this.options=n,this.parser=t,this.tokens=o,this.pos=0,this.posMax=this.src.length,this.level=0,this.pending="",this.pendingLevel=0,this.cache=[],this.isInLabel=!1,this.linkLevel=0,this.linkContent="",this.labelUnmatchedScopes=0}r.prototype.pushPending=function(){this.tokens.push({type:"text",content:this.pending,level:this.pendingLevel}),this.pending=""},r.prototype.push=function(e){this.pending&&this.pushPending(),this.tokens.push(e),this.pendingLevel=this.level},r.prototype.cacheSet=function(e,t){for(var n=this.cache.length;n<=e;n++)this.cache.push(0);this.cache[e]=t},r.prototype.cacheGet=function(e){return es;)r(u,n=t[s++])&&(~i(l,n)||l.push(n));return l}},function(e,t,n){var r=n(19).document;e.exports=r&&r.documentElement},function(e,t,n){var r=n(52),o=n(71),i=n(161)("IE_PROTO"),a=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=o(e),r(e,i)?e[i]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?a:null}},function(e,t,n){var r=n(53),o=n(29),i=o["__core-js_shared__"]||(o["__core-js_shared__"]={});(e.exports=function(e,t){return i[e]||(i[e]=void 0!==t?t:{})})("versions",[]).push({version:r.version,mode:n(167)?"pure":"global",copyright:"© 2018 Denis Pushkarev (zloirock.ru)"})},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){"use strict";var r=n(246)(!0);n(247)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){var r=n(119),o=n(54);e.exports=function(e){return function(t,n){var i,a,u=String(o(t)),s=r(n),l=u.length;return s<0||s>=l?e?"":void 0:(i=u.charCodeAt(s))<55296||i>56319||s+1===l||(a=u.charCodeAt(s+1))<56320||a>57343?e?u.charAt(s):i:e?u.slice(s,s+2):a-56320+(i-55296<<10)+65536}}},function(e,t,n){"use strict";var r=n(167),o=n(30),i=n(72),a=n(59),u=n(103),s=n(462),l=n(171),c=n(468),f=n(17)("iterator"),p=!([].keys&&"next"in[].keys()),d=function(){return this};e.exports=function(e,t,n,h,v,m,g){s(n,t,h);var y,b,_,w=function(e){if(!p&&e in C)return C[e];switch(e){case"keys":case"values":return function(){return new n(this,e)}}return function(){return new n(this,e)}},E=t+" Iterator",x="values"==v,S=!1,C=e.prototype,k=C[f]||C["@@iterator"]||v&&C[v],A=k||w(v),O=v?x?w("entries"):A:void 0,P="Array"==t&&C.entries||k;if(P&&(_=c(P.call(new e)))!==Object.prototype&&_.next&&(l(_,E,!0),r||"function"==typeof _[f]||a(_,f,d)),x&&k&&"values"!==k.name&&(S=!0,A=function(){return k.call(this)}),r&&!g||!p&&!S&&C[f]||a(C,f,A),u[t]=A,u[E]=d,v)if(y={values:x?A:w("values"),keys:m?A:w("keys"),entries:O},g)for(b in y)b in C||i(C,b,y[b]);else o(o.P+o.F*(p||S),t,y);return y}},function(e,t,n){var r=n(465),o=n(250);e.exports=Object.keys||function(e){return r(e,o)}},function(e,t,n){var r=n(119),o=Math.max,i=Math.min;e.exports=function(e,t){return(e=r(e))<0?o(e+t,0):i(e,t)}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(29).document;e.exports=r&&r.documentElement},function(e,t,n){var r=n(60),o=n(121),i=n(17)("species");e.exports=function(e,t){var n,a=r(e).constructor;return void 0===a||void 0==(n=r(a)[i])?t:o(n)}},function(e,t,n){var r,o,i,a=n(120),u=n(480),s=n(251),l=n(169),c=n(29),f=c.process,p=c.setImmediate,d=c.clearImmediate,h=c.MessageChannel,v=c.Dispatch,m=0,g={},y=function(){var e=+this;if(g.hasOwnProperty(e)){var t=g[e];delete g[e],t()}},b=function(e){y.call(e.data)};p&&d||(p=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return g[++m]=function(){u("function"==typeof e?e:Function(e),t)},r(m),m},d=function(e){delete g[e]},"process"==n(100)(f)?r=function(e){f.nextTick(a(y,e,1))}:v&&v.now?r=function(e){v.now(a(y,e,1))}:h?(i=(o=new h).port2,o.port1.onmessage=b,r=a(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(r=function(e){c.postMessage(e+"","*")},c.addEventListener("message",b,!1)):r="onreadystatechange"in l("script")?function(e){s.appendChild(l("script")).onreadystatechange=function(){s.removeChild(this),y.call(e)}}:function(e){setTimeout(a(y,e,1),0)}),e.exports={set:p,clear:d}},function(e,t){e.exports=function(e){try{return{e:!1,v:e()}}catch(e){return{e:!0,v:e}}}},function(e,t,n){var r=n(60),o=n(73),i=n(172);e.exports=function(e,t){if(r(e),o(t)&&t.constructor===e)return t;var n=i.f(e);return(0,n.resolve)(t),n.promise}},function(e,t,n){var r=n(73),o=n(100),i=n(17)("match");e.exports=function(e){var t;return r(e)&&(void 0!==(t=e[i])?!!t:"RegExp"==o(e))}},function(e,t,n){var r=n(21),o=n(14),i=n(51);e.exports=function(e,t){var n=(o.Object||{})[e]||Object[e],a={};a[e]=t(n),r(r.S+r.F*i(function(){n(1)}),"Object",a)}},function(e,t,n){var r=n(93);e.exports=Array.isArray||function(e){return"Array"==r(e)}},function(e,t,n){var r=n(240),o=n(163).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return r(e,o)}},function(e,t,n){var r=n(125),o=n(96),i=n(70),a=n(157),u=n(52),s=n(239),l=Object.getOwnPropertyDescriptor;t.f=n(44)?l:function(e,t){if(e=i(e),t=a(t,!0),s)try{return l(e,t)}catch(e){}if(u(e,t))return o(!r.f.call(e,t),e[t])}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){e.exports={default:n(533),__esModule:!0}},function(e,t,n){"use strict";var r=n(97),o=n(177),i=n(125),a=n(71),u=n(154),s=Object.assign;e.exports=!s||n(51)(function(){var e={},t={},n=Symbol(),r="abcdefghijklmnopqrst";return e[n]=7,r.split("").forEach(function(e){t[e]=e}),7!=s({},e)[n]||Object.keys(s({},t)).join("")!=r})?function(e,t){for(var n=a(e),s=arguments.length,l=1,c=o.f,f=i.f;s>l;)for(var p,d=u(arguments[l++]),h=c?r(d).concat(c(d)):r(d),v=h.length,m=0;v>m;)f.call(d,p=h[m++])&&(n[p]=d[p]);return n}:s},function(e,t,n){"use strict";var r=n(105),o=n(13),i=n(265),a=(n(266),n(126));n(8),n(537);function u(e,t,n){this.props=e,this.context=t,this.refs=a,this.updater=n||i}function s(e,t,n){this.props=e,this.context=t,this.refs=a,this.updater=n||i}function l(){}u.prototype.isReactComponent={},u.prototype.setState=function(e,t){"object"!=typeof e&&"function"!=typeof e&&null!=e&&r("85"),this.updater.enqueueSetState(this,e),t&&this.updater.enqueueCallback(this,t,"setState")},u.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this),e&&this.updater.enqueueCallback(this,e,"forceUpdate")},l.prototype=u.prototype,s.prototype=new l,s.prototype.constructor=s,o(s.prototype,u.prototype),s.prototype.isPureReactComponent=!0,e.exports={Component:u,PureComponent:s}},function(e,t,n){"use strict";n(11);var r={isMounted:function(e){return!1},enqueueCallback:function(e,t){},enqueueForceUpdate:function(e){},enqueueReplaceState:function(e,t){},enqueueSetState:function(e,t){}};e.exports=r},function(e,t,n){"use strict";var r=!1;e.exports=r},function(e,t,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;e.exports=r},function(e,t,n){"use strict";var r=n(545);e.exports=function(e){return r(e,!1)}},function(e,t,n){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(271),o=n(562),i=n(563),a=n(564),u=n(275);n(274);n.d(t,"createStore",function(){return r.b}),n.d(t,"combineReducers",function(){return o.a}),n.d(t,"bindActionCreators",function(){return i.a}),n.d(t,"applyMiddleware",function(){return a.a}),n.d(t,"compose",function(){return u.a})},function(e,t,n){"use strict";n.d(t,"a",function(){return i}),t.b=function e(t,n,a){var u;"function"==typeof n&&void 0===a&&(a=n,n=void 0);if(void 0!==a){if("function"!=typeof a)throw new Error("Expected the enhancer to be a function.");return a(e)(t,n)}if("function"!=typeof t)throw new Error("Expected the reducer to be a function.");var s=t;var l=n;var c=[];var f=c;var p=!1;function d(){f===c&&(f=c.slice())}function h(){return l}function v(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var t=!0;return d(),f.push(e),function(){if(t){t=!1,d();var n=f.indexOf(e);f.splice(n,1)}}}function m(e){if(!Object(r.a)(e))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if(void 0===e.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(p)throw new Error("Reducers may not dispatch actions.");try{p=!0,l=s(l,e)}finally{p=!1}for(var t=c=f,n=0;no?0:o+t),(n=n>o?o:n)<0&&(n+=o),o=t>n?0:n-t>>>0,t>>>=0;for(var i=Array(o);++rp))return!1;var h=c.get(e);if(h&&c.get(t))return h==t;var v=-1,m=!0,g=n&u?new r:void 0;for(c.set(e,t),c.set(t,e);++v0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===l.prototype||(t=function(e){return l.from(e)}(t)),r?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):w(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||0!==t.length?w(e,a,t,!1):k(e,a)):w(e,a,t,!1))):r||(a.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=E?e=E:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function S(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(d("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?o.nextTick(C,e):C(e))}function C(e){d("emit readable"),e.emit("readable"),T(e)}function k(e,t){t.readingMore||(t.readingMore=!0,o.nextTick(A,e,t))}function A(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=function(e,t,n){var r;ei.length?i.length:e;if(a===i.length?o+=i:o+=i.slice(0,e),0===(e-=a)){a===i.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=i.slice(a));break}++r}return t.length-=r,o}(e,t):function(e,t){var n=l.allocUnsafe(e),r=t.head,o=1;r.data.copy(n),e-=r.data.length;for(;r=r.next;){var i=r.data,a=e>i.length?i.length:e;if(i.copy(n,n.length-e,0,a),0===(e-=a)){a===i.length?(++o,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=i.slice(a));break}++o}return t.length-=o,n}(e,t);return r}(e,t.buffer,t.decoder),n);var n}function I(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,o.nextTick(j,t,e))}function j(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function N(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return d("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?I(this):S(this),null;if(0===(e=x(e,t))&&t.ended)return 0===t.length&&I(this),null;var r,o=t.needReadable;return d("need readable",o),(0===t.length||t.length-e0?M(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&I(this)),null!==r&&this.emit("data",r),r},b.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},b.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,d("pipe count=%d opts=%j",i.pipesCount,t);var s=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr?c:b;function l(t,r){d("onunpipe"),t===n&&r&&!1===r.hasUnpiped&&(r.hasUnpiped=!0,d("cleanup"),e.removeListener("close",g),e.removeListener("finish",y),e.removeListener("drain",f),e.removeListener("error",m),e.removeListener("unpipe",l),n.removeListener("end",c),n.removeListener("end",b),n.removeListener("data",v),p=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function c(){d("onend"),e.end()}i.endEmitted?o.nextTick(s):n.once("end",s),e.on("unpipe",l);var f=function(e){return function(){var t=e._readableState;d("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&u(e,"data")&&(t.flowing=!0,T(e))}}(n);e.on("drain",f);var p=!1;var h=!1;function v(t){d("ondata"),h=!1,!1!==e.write(t)||h||((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==N(i.pipes,e))&&!p&&(d("false write response, pause",n._readableState.awaitDrain),n._readableState.awaitDrain++,h=!0),n.pause())}function m(t){d("onerror",t),b(),e.removeListener("error",m),0===u(e,"error")&&e.emit("error",t)}function g(){e.removeListener("finish",y),b()}function y(){d("onfinish"),e.removeListener("close",g),b()}function b(){d("unpipe"),n.unpipe(e)}return n.on("data",v),function(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?a(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}(e,"error",m),e.once("close",g),e.once("finish",y),e.emit("pipe",n),i.flowing||(d("pipe resume"),n.resume()),e},b.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,o=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(663),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(t,n(32))},function(e,t,n){"use strict";var r=n(141).Buffer,o=r.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function i(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(r.isEncoding===o||!o(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=s,this.end=l,t=4;break;case"utf8":this.fillLast=u,t=4;break;case"base64":this.text=c,this.end=f,t=3;break;default:return this.write=p,void(this.end=d)}this.lastNeed=0,this.lastTotal=0,this.lastChar=r.allocUnsafe(t)}function a(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function u(e){var t=this.lastTotal-this.lastNeed,n=function(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function s(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function l(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function c(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function p(e){return e.toString(this.encoding)}function d(e){return e&&e.length?this.write(e):""}t.StringDecoder=i,i.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n=0)return o>0&&(e.lastNeed=o-1),o;if(--r=0)return o>0&&(e.lastNeed=o-2),o;if(--r=0)return o>0&&(2===o?o=0:e.lastNeed=o-3),o;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},i.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,n){"use strict";e.exports=i;var r=n(64),o=n(107);function i(e){if(!(this instanceof i))return new i(e);r.call(this,e),this._transformState={afterTransform:function(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit("error",new Error("write callback called multiple times"));n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var o=this._readableState;o.reading=!1,(o.needReadable||o.length=0?n&&o?o-1:o:1:!1!==e&&r(e)}},function(e,t,n){"use strict";e.exports=n(679)()?Object.assign:n(680)},function(e,t,n){"use strict";var r,o,i,a,u,s=n(66),l=function(e,t){return t};try{Object.defineProperty(l,"length",{configurable:!0,writable:!1,enumerable:!1,value:1})}catch(e){}1===l.length?(r={configurable:!0,writable:!1,enumerable:!1},o=Object.defineProperty,e.exports=function(e,t){return t=s(t),e.length===t?e:(r.value=t,o(e,"length",r))}):(a=n(317),u=[],i=function(e){var t,n=0;if(u[e])return u[e];for(t=[];e--;)t.push("a"+(++n).toString(36));return new Function("fn","return function ("+t.join(", ")+") { return fn.apply(this, arguments); };")},e.exports=function(e,t){var n;if(t=s(t),e.length===t)return e;n=i(t)(e);try{a(n,e)}catch(e){}return n})},function(e,t,n){"use strict";var r=n(82),o=Object.defineProperty,i=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,u=Object.getOwnPropertySymbols;e.exports=function(e,t){var n,s=Object(r(t));if(e=Object(r(e)),a(s).forEach(function(r){try{o(e,r,i(t,r))}catch(e){n=e}}),"function"==typeof u&&u(s).forEach(function(r){try{o(e,r,i(t,r))}catch(e){n=e}}),void 0!==n)throw n;return e}},function(e,t,n){"use strict";var r=n(57),o=n(142),i=Function.prototype.call;e.exports=function(e,t){var n={},a=arguments[2];return r(t),o(e,function(e,r,o,u){n[r]=i.call(t,a,e,r,o,u)}),n}},function(e,t){e.exports=function(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return{statePlugins:{err:{reducers:(0,i.default)(e),actions:a,selectors:u}}}};var r,o=n(321),i=(r=o)&&r.__esModule?r:{default:r},a=s(n(127)),u=s(n(326));function s(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=s(n(22)),o=s(n(23));t.default=function(e){var t;return t={},(0,r.default)(t,i.NEW_THROWN_ERR,function(t,n){var r=n.payload,i=(0,o.default)(l,r,{type:"thrown"});return t.update("errors",function(e){return(e||(0,a.List)()).push((0,a.fromJS)(i))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_THROWN_ERR_BATCH,function(t,n){var r=n.payload;return r=r.map(function(e){return(0,a.fromJS)((0,o.default)(l,e,{type:"thrown"}))}),t.update("errors",function(e){return(e||(0,a.List)()).concat((0,a.fromJS)(r))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_SPEC_ERR,function(t,n){var r=n.payload,o=(0,a.fromJS)(r);return o=o.set("type","spec"),t.update("errors",function(e){return(e||(0,a.List)()).push((0,a.fromJS)(o)).sortBy(function(e){return e.get("line")})}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_SPEC_ERR_BATCH,function(t,n){var r=n.payload;return r=r.map(function(e){return(0,a.fromJS)((0,o.default)(l,e,{type:"spec"}))}),t.update("errors",function(e){return(e||(0,a.List)()).concat((0,a.fromJS)(r))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_AUTH_ERR,function(t,n){var r=n.payload,i=(0,a.fromJS)((0,o.default)({},r));return i=i.set("type","auth"),t.update("errors",function(e){return(e||(0,a.List)()).push((0,a.fromJS)(i))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.CLEAR,function(e,t){var n=t.payload;if(!n||!e.get("errors"))return e;var r=e.get("errors").filter(function(e){return e.keySeq().every(function(t){var r=e.get(t),o=n[t];return!o||r!==o})});return e.merge({errors:r})}),(0,r.default)(t,i.CLEAR_BY,function(e,t){var n=t.payload;if(!n||"function"!=typeof n)return e;var r=e.get("errors").filter(function(e){return n(e)});return e.merge({errors:r})}),t};var i=n(127),a=n(7),u=s(n(322));function s(e){return e&&e.__esModule?e:{default:e}}var l={line:0,level:"error",message:"Unknown error"}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){var n={jsSpec:t.specSelectors.specJson().toJS()};return(0,i.default)(u,function(e,t){try{var r=t.transform(e,n);return r.filter(function(e){return!!e})}catch(t){return console.error("Transformer error:",t),e}},e).filter(function(e){return!!e}).map(function(e){return!e.get("line")&&e.get("path"),e})};var r,o=n(727),i=(r=o)&&r.__esModule?r:{default:r};function a(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var u=[a(n(323)),a(n(324)),a(n(325))]},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transform=function(e){return e.map(function(e){var t=e.get("message").indexOf("is not of a type(s)");if(t>-1){var n=e.get("message").slice(t+"is not of a type(s)".length).split(",");return e.set("message",e.get("message").slice(0,t)+function(e){return e.reduce(function(e,t,n,r){return n===r.length-1&&r.length>1?e+"or "+t:r[n+1]&&r.length>2?e+t+", ":r[n+1]?e+t+" ":e+t},"should be a")}(n))}return e})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transform=function(e,t){t.jsSpec;return e};var r,o=n(138);(r=o)&&r.__esModule,n(7)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transform=function(e){return e.map(function(e){return e.set("message",(t=e.get("message"),n="instance.",t.replace(new RegExp(n,"g"),"")));var t,n})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.lastError=t.allErrors=void 0;var r=n(7),o=n(58),i=t.allErrors=(0,o.createSelector)(function(e){return e},function(e){return e.get("errors",(0,r.List)())});t.lastError=(0,o.createSelector)(i,function(e){return e.last()})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{statePlugins:{layout:{reducers:i.default,actions:a,selectors:u}}}};var r,o=n(328),i=(r=o)&&r.__esModule?r:{default:r},a=s(n(201)),u=s(n(329));function s(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,o,i=n(22),a=(r=i)&&r.__esModule?r:{default:r},u=n(7),s=n(201);t.default=(o={},(0,a.default)(o,s.UPDATE_LAYOUT,function(e,t){return e.set("layout",t.payload)}),(0,a.default)(o,s.UPDATE_FILTER,function(e,t){return e.set("filter",t.payload)}),(0,a.default)(o,s.SHOW,function(e,t){var n=t.payload.shown,r=(0,u.fromJS)(t.payload.thing);return e.update("shown",(0,u.fromJS)({}),function(e){return e.set(r,n)})}),(0,a.default)(o,s.UPDATE_MODE,function(e,t){var n=t.payload.thing,r=t.payload.mode;return e.setIn(["modes"].concat(n),(r||"")+"")}),o)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.showSummary=t.whatMode=t.isShown=t.currentFilter=t.current=void 0;var r,o=n(83),i=(r=o)&&r.__esModule?r:{default:r},a=n(58),u=n(12),s=n(7);t.current=function(e){return e.get("layout")},t.currentFilter=function(e){return e.get("filter")};var l=t.isShown=function(e,t,n){return t=(0,u.normalizeArray)(t),e.get("shown",(0,s.fromJS)({})).get((0,s.fromJS)(t),n)};t.whatMode=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return t=(0,u.normalizeArray)(t),e.getIn(["modes"].concat((0,i.default)(t)),n)},t.showSummary=(0,a.createSelector)(function(e){return e},function(e){return!l(e,"editor")})},function(e,t,n){var r=n(35);e.exports=function(e,t,n,o){try{return o?t(r(n)[0],n[1]):t(n)}catch(t){var i=e.return;throw void 0!==i&&r(i.call(e)),t}}},function(e,t,n){var r=n(69),o=n(20)("iterator"),i=Array.prototype;e.exports=function(e){return void 0!==e&&(r.Array===e||i[o]===e)}},function(e,t,n){var r=n(20)("iterator"),o=!1;try{var i=[7][r]();i.return=function(){o=!0},Array.from(i,function(){throw 2})}catch(e){}e.exports=function(e,t){if(!t&&!o)return!1;var n=!1;try{var i=[7],a=i[r]();a.next=function(){return{done:n=!0}},i[r]=function(){return a},e(i)}catch(e){}return n}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{statePlugins:{spec:{wrapActions:s,reducers:i.default,actions:a,selectors:u}}}};var r,o=n(334),i=(r=o)&&r.__esModule?r:{default:r},a=l(n(203)),u=l(n(202)),s=l(n(347));function l(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,o=p(n(22)),i=p(n(23)),a=p(n(83)),u=n(7),s=n(12),l=p(n(33)),c=n(202),f=n(203);function p(e){return e&&e.__esModule?e:{default:e}}t.default=(r={},(0,o.default)(r,f.UPDATE_SPEC,function(e,t){return"string"==typeof t.payload?e.set("spec",t.payload):e}),(0,o.default)(r,f.UPDATE_URL,function(e,t){return e.set("url",t.payload+"")}),(0,o.default)(r,f.UPDATE_JSON,function(e,t){return e.set("json",(0,s.fromJSOrdered)(t.payload))}),(0,o.default)(r,f.UPDATE_RESOLVED,function(e,t){return e.setIn(["resolved"],(0,s.fromJSOrdered)(t.payload))}),(0,o.default)(r,f.UPDATE_RESOLVED_SUBTREE,function(e,t){var n=t.payload,r=n.value,o=n.path;return e.setIn(["resolvedSubtrees"].concat((0,a.default)(o)),(0,s.fromJSOrdered)(r))}),(0,o.default)(r,f.UPDATE_PARAM,function(e,t){var n=t.payload,r=n.path,o=n.paramName,i=n.paramIn,u=n.param,s=n.value,l=n.isXml,c=void 0;c=u&&u.hashCode&&!i&&!o?u.get("name")+"."+u.get("in")+".hash-"+u.hashCode():o+"."+i;var f=l?"value_xml":"value";return e.setIn(["meta","paths"].concat((0,a.default)(r),["parameters",c,f]),s)}),(0,o.default)(r,f.UPDATE_EMPTY_PARAM_INCLUSION,function(e,t){var n=t.payload,r=n.pathMethod,o=n.paramName,i=n.paramIn,u=n.includeEmptyValue;if(!o||!i)return console.warn("Warning: UPDATE_EMPTY_PARAM_INCLUSION could not generate a paramKey."),e;var s=o+"."+i;return e.setIn(["meta","paths"].concat((0,a.default)(r),["parameter_inclusions",s]),u)}),(0,o.default)(r,f.VALIDATE_PARAMS,function(e,t){var n=t.payload,r=n.pathMethod,o=n.isOAS3,i=e.getIn(["meta","paths"].concat((0,a.default)(r)),(0,u.fromJS)({})),l=/xml/i.test(i.get("consumes_value")),f=c.operationWithMeta.apply(void 0,[e].concat((0,a.default)(r)));return e.updateIn(["meta","paths"].concat((0,a.default)(r),["parameters"]),(0,u.fromJS)({}),function(e){return f.get("parameters",(0,u.List)()).reduce(function(e,t){var n=(0,s.validateParam)(t,l,o);return e.setIn([t.get("name")+"."+t.get("in"),"errors"],(0,u.fromJS)(n))},e)})}),(0,o.default)(r,f.CLEAR_VALIDATE_PARAMS,function(e,t){var n=t.payload.pathMethod;return e.updateIn(["meta","paths"].concat((0,a.default)(n),["parameters"]),(0,u.fromJS)([]),function(e){return e.map(function(e){return e.set("errors",(0,u.fromJS)([]))})})}),(0,o.default)(r,f.SET_RESPONSE,function(e,t){var n=t.payload,r=n.res,o=n.path,a=n.method,u=void 0;(u=r.error?(0,i.default)({error:!0,name:r.err.name,message:r.err.message,statusCode:r.err.statusCode},r.err.response):r).headers=u.headers||{};var c=e.setIn(["responses",o,a],(0,s.fromJSOrdered)(u));return l.default.Blob&&r.data instanceof l.default.Blob&&(c=c.setIn(["responses",o,a,"text"],r.data)),c}),(0,o.default)(r,f.SET_REQUEST,function(e,t){var n=t.payload,r=n.req,o=n.path,i=n.method;return e.setIn(["requests",o,i],(0,s.fromJSOrdered)(r))}),(0,o.default)(r,f.SET_MUTATED_REQUEST,function(e,t){var n=t.payload,r=n.req,o=n.path,i=n.method;return e.setIn(["mutatedRequests",o,i],(0,s.fromJSOrdered)(r))}),(0,o.default)(r,f.UPDATE_OPERATION_META_VALUE,function(e,t){var n=t.payload,r=n.path,o=n.value,i=n.key,s=["paths"].concat((0,a.default)(r)),l=["meta","paths"].concat((0,a.default)(r));return e.getIn(["json"].concat((0,a.default)(s)))||e.getIn(["resolved"].concat((0,a.default)(s)))||e.getIn(["resolvedSubtrees"].concat((0,a.default)(s)))?e.setIn([].concat((0,a.default)(l),[i]),(0,u.fromJS)(o)):e}),(0,o.default)(r,f.CLEAR_RESPONSE,function(e,t){var n=t.payload,r=n.path,o=n.method;return e.deleteIn(["responses",r,o])}),(0,o.default)(r,f.CLEAR_REQUEST,function(e,t){var n=t.payload,r=n.path,o=n.method;return e.deleteIn(["requests",r,o])}),(0,o.default)(r,f.SET_SCHEME,function(e,t){var n=t.payload,r=n.scheme,o=n.path,i=n.method;return o&&i?e.setIn(["scheme",o,i],r):o||i?void 0:e.setIn(["scheme","_defaultScheme"],r)}),r)},function(e,t,n){var r=n(35),o=n(95),i=n(20)("species");e.exports=function(e,t){var n,a=r(e).constructor;return void 0===a||void 0==(n=r(a)[i])?t:o(n)}},function(e,t,n){var r,o,i,a=n(49),u=n(735),s=n(241),l=n(156),c=n(19),f=c.process,p=c.setImmediate,d=c.clearImmediate,h=c.MessageChannel,v=c.Dispatch,m=0,g={},y=function(){var e=+this;if(g.hasOwnProperty(e)){var t=g[e];delete g[e],t()}},b=function(e){y.call(e.data)};p&&d||(p=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return g[++m]=function(){u("function"==typeof e?e:Function(e),t)},r(m),m},d=function(e){delete g[e]},"process"==n(93)(f)?r=function(e){f.nextTick(a(y,e,1))}:v&&v.now?r=function(e){v.now(a(y,e,1))}:h?(i=(o=new h).port2,o.port1.onmessage=b,r=a(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(r=function(e){c.postMessage(e+"","*")},c.addEventListener("message",b,!1)):r="onreadystatechange"in l("script")?function(e){s.appendChild(l("script")).onreadystatechange=function(){s.removeChild(this),y.call(e)}}:function(e){setTimeout(a(y,e,1),0)}),e.exports={set:p,clear:d}},function(e,t){e.exports=function(e){try{return{e:!1,v:e()}}catch(e){return{e:!0,v:e}}}},function(e,t,n){var r=n(35),o=n(28),i=n(206);e.exports=function(e,t){if(r(e),o(t)&&t.constructor===e)return t;var n=i.f(e);return(0,n.resolve)(t),n.promise}},function(e,t,n){e.exports=n(741)},function(e,t,n){"use strict";t.__esModule=!0;var r,o=n(204),i=(r=o)&&r.__esModule?r:{default:r};t.default=function(e){return function(){var t=e.apply(this,arguments);return new i.default(function(e,n){return function r(o,a){try{var u=t[o](a),s=u.value}catch(e){return void n(e)}if(!u.done)return i.default.resolve(s).then(function(e){r("next",e)},function(e){r("throw",e)});e(s)}("next")})}}},function(e,t,n){"use strict";var r=n(86);e.exports=new r({include:[n(342)]})},function(e,t,n){"use strict";var r=n(86);e.exports=new r({include:[n(209)],implicit:[n(749),n(750),n(751),n(752)]})},function(e,t,n){var r=n(61),o=n(24),i=n(47),a="[object String]";e.exports=function(e){return"string"==typeof e||!o(e)&&i(e)&&r(e)==a}},function(e,t,n){var r=n(146),o=n(79),i=n(135),a=n(37),u=n(80);e.exports=function(e,t,n,s){if(!a(e))return e;for(var l=-1,c=(t=o(t,e)).length,f=c-1,p=e;null!=p&&++l.":"function"==typeof t?" Instead of passing a class like Foo, pass React.createElement(Foo) or .":null!=t&&void 0!==t.props?" This may be caused by unintentionally loading two independent copies of React.":"");var i,u=a.createElement(D,{child:t});if(e){var s=p.get(e);i=s._processChildContext(s._context)}else i=g;var l=N(n);if(l){var c=l._currentElement.props.child;if(_(c,t)){var f=l._renderedComponent.getPublicInstance(),d=o&&function(){o.call(f)};return L._updateRootComponent(l,u,i,n,d),f}L.unmountComponentAtNode(n)}var h=A(n),m=h&&!!O(h),y=I(n),b=m&&!l&&!y,w=L._renderNewRootComponent(u,n,b,i)._renderedComponent.getPublicInstance();return o&&o.call(w),w},render:function(e,t,n){return L._renderSubtreeIntoContainer(null,e,t,n)},unmountComponentAtNode:function(e){j(e)||r("40");var t=N(e);if(!t){I(e),1===e.nodeType&&e.hasAttribute(E);return!1}return delete k[t._instance.rootID],m.batchedUpdates(M,t,e,!1),!0},_mountImageIntoNode:function(e,t,n,i,a){if(j(t)||r("41"),i){var u=A(t);if(d.canReuseMarkup(e,u))return void s.precacheNode(n,u);var l=u.getAttribute(d.CHECKSUM_ATTR_NAME);u.removeAttribute(d.CHECKSUM_ATTR_NAME);var c=u.outerHTML;u.setAttribute(d.CHECKSUM_ATTR_NAME,l);var f=e,p=function(e,t){for(var n=Math.min(e.length,t.length),r=0;r1?r-1:0),a=1;a=o&&(t=console)[e].apply(t,i)}return i.warn=i.bind(null,"warn"),i.error=i.bind(null,"error"),i.info=i.bind(null,"info"),i.debug=i.bind(null,"debug"),{rootInjects:{log:i}}}},function(e,t,n){"use strict";var r,o=n(388),i=(r=o)&&r.__esModule?r:{default:r};e.exports=function(e){var t=e.configs;return{fn:{fetch:i.default.makeHttp(t.preFetch,t.postFetch),buildRequest:i.default.buildRequest,execute:i.default.execute,resolve:i.default.resolve,resolveSubtree:i.default.resolveSubtree,serializeRes:i.default.serializeRes,opId:i.default.helpers.opId}}}},function(e,t,n){e.exports=function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=23)}([function(e,t){e.exports=n(41)},function(e,t){e.exports=n(45)},function(e,t){e.exports=n(23)},function(e,t){e.exports=n(25)},function(e,t){e.exports=n(339)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=(arguments.length>3&&void 0!==arguments[3]?arguments[3]:{}).v2OperationIdCompatibilityMode;return e&&"object"===(void 0===e?"undefined":(0,c.default)(e))?(e.operationId||"").replace(/\s/g,"").length?h(e.operationId):i(t,n,{v2OperationIdCompatibilityMode:r}):null}function i(e,t){if((arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).v2OperationIdCompatibilityMode){var n=(t.toLowerCase()+"_"+e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|.\/?,\\'""-]/g,"_");return(n=n||e.substring(1)+"_"+t).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return""+d(t)+h(e)}function a(e,t){return d(t)+"-"+e}function u(e,t){return s(e,t,!0)||null}function s(e,t,n){if(!e||"object"!==(void 0===e?"undefined":(0,c.default)(e))||!e.paths||"object"!==(0,c.default)(e.paths))return null;var r=e.paths;for(var o in r)for(var i in r[o])if("PARAMETERS"!==i.toUpperCase()){var a=r[o][i];if(a&&"object"===(void 0===a?"undefined":(0,c.default)(a))){var u={spec:e,pathName:o,method:i.toUpperCase(),operation:a},s=t(u);if(n&&s)return u}}}Object.defineProperty(t,"__esModule",{value:!0});var l=r(n(18)),c=r(n(1));t.isOAS3=function(e){var t=e.openapi;return!!t&&(0,p.default)(t,"3")},t.isSwagger2=function(e){var t=e.swagger;return!!t&&(0,p.default)(t,"2")},t.opId=o,t.idFromPathMethod=i,t.legacyIdFromPathMethod=a,t.getOperationRaw=function(e,t){return e&&e.paths?u(e,function(e){var n=e.pathName,r=e.method,i=e.operation;if(!i||"object"!==(void 0===i?"undefined":(0,c.default)(i)))return!1;var u=i.operationId;return[o(i,n,r),a(n,r),u].some(function(e){return e&&e===t})}):null},t.findOperation=u,t.eachOperation=s,t.normalizeSwagger=function(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var i in n){var a=n[i];if((0,f.default)(a)){var u=a.parameters;for(var s in a)!function(e){var n=a[e];if(!(0,f.default)(n))return"continue";var s=o(n,i,e);if(s){r[s]?r[s].push(n):r[s]=[n];var c=r[s];if(c.length>1)c.forEach(function(e,t){e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId=""+s+(t+1)});else if(void 0!==n.operationId){var p=c[0];p.__originalOperationId=p.__originalOperationId||n.operationId,p.operationId=s}}if("parameters"!==e){var d=[],h={};for(var v in t)"produces"!==v&&"consumes"!==v&&"security"!==v||(h[v]=t[v],d.push(h));if(u&&(h.parameters=u,d.push(h)),d.length){var m=!0,g=!1,y=void 0;try{for(var b,_=(0,l.default)(d);!(m=(b=_.next()).done);m=!0){var w=b.value;for(var E in w)if(n[E]){if("parameters"===E){var x=!0,S=!1,C=void 0;try{for(var k,A=(0,l.default)(w[E]);!(x=(k=A.next()).done);x=!0)!function(){var e=k.value;n[E].some(function(t){return t.name&&t.name===e.name||t.$ref&&t.$ref===e.$ref||t.$$ref&&t.$$ref===e.$$ref||t===e})||n[E].push(e)}()}catch(e){S=!0,C=e}finally{try{!x&&A.return&&A.return()}finally{if(S)throw C}}}}else n[E]=w[E]}}catch(e){g=!0,y=e}finally{try{!m&&_.return&&_.return()}finally{if(g)throw y}}}}}(s)}}return t.$$normalized=!0,e};var f=r(n(47)),p=r(n(14)),d=function(e){return String.prototype.toLowerCase.call(e)},h=function(e){return e.replace(/[^\w]/gi,"_")}},function(e,t){e.exports=n(894)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).loadSpec,r=void 0!==n&&n,o={ok:e.ok,url:e.url||t,status:e.status,statusText:e.statusText,headers:i(e.headers)},a=o.headers["content-type"],u=r||_(a);return(u?e.text:e.blob||e.buffer).call(e).then(function(e){if(o.text=e,o.data=e,u)try{var t=function(e,t){return"application/json"===t?JSON.parse(e):g.default.safeLoad(e)}(e,a);o.body=t,o.obj=t}catch(e){o.parseError=e}return o})}function i(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t={};return"function"==typeof e.forEach?(e.forEach(function(e,n){void 0!==t[n]?(t[n]=Array.isArray(t[n])?t[n]:[t[n]],t[n].push(e)):t[n]=e}),t):t}function a(e){return"undefined"!=typeof File?e instanceof File:null!==e&&"object"===(void 0===e?"undefined":(0,h.default)(e))&&"function"==typeof e.pipe}function u(e,t){var n=e.collectionFormat,r=e.allowEmptyValue,o="object"===(void 0===e?"undefined":(0,h.default)(e))?e.value:e;if(void 0===o&&r)return"";if(a(o)||"boolean"==typeof o)return o;var i=encodeURIComponent;return t&&(i=(0,y.default)(o)?function(e){return e}:function(e){return(0,p.default)(e)}),"object"!==(void 0===o?"undefined":(0,h.default)(o))||Array.isArray(o)?Array.isArray(o)?Array.isArray(o)&&!n?o.map(i).join(","):"multi"===n?o.map(i):o.map(i).join({csv:",",ssv:"%20",tsv:"%09",pipes:"|"}[n]):i(o):""}function s(e){var t=(0,f.default)(e).reduce(function(t,n){var r=e[n],o=!!r.skipEncoding,i=o?n:encodeURIComponent(n),a=function(e){return e&&"object"===(void 0===e?"undefined":(0,h.default)(e))}(r)&&!Array.isArray(r);return t[i]=u(a?r:{value:r},o),t},{});return m.default.stringify(t,{encode:!1,indices:!1})||""}function l(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,r=void 0===t?"":t,o=e.query,i=e.form;if(i){var l=(0,f.default)(i).some(function(e){return a(i[e].value)}),p=e.headers["content-type"]||e.headers["Content-Type"];if(l||/multipart\/form-data/i.test(p)){var d=n(30);e.body=new d,(0,f.default)(i).forEach(function(t){e.body.append(t,u(i[t],!0))})}else e.body=s(i);delete e.form}if(o){var h=r.split("?"),v=(0,c.default)(h,2),g=v[0],y=v[1],b="";if(y){var _=m.default.parse(y);(0,f.default)(o).forEach(function(e){return delete _[e]}),b=m.default.stringify(_,{encode:!0})}var w=function(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:{};return d.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if("object"===(void 0===t?"undefined":(0,h.default)(t))&&(t=(a=t).url),a.headers=a.headers||{},b.mergeInQueryOrForm(a),!a.requestInterceptor){e.next=10;break}return e.next=6,a.requestInterceptor(a);case 6:if(e.t0=e.sent,e.t0){e.next=9;break}e.t0=a;case 9:a=e.t0;case 10:return n=a.headers["content-type"]||a.headers["Content-Type"],/multipart\/form-data/i.test(n)&&(delete a.headers["content-type"],delete a.headers["Content-Type"]),r=void 0,e.prev=13,e.next=16,(a.userFetch||fetch)(a.url,a);case 16:return r=e.sent,e.next=19,b.serializeRes(r,t,a);case 19:if(r=e.sent,!a.responseInterceptor){e.next=27;break}return e.next=23,a.responseInterceptor(r);case 23:if(e.t1=e.sent,e.t1){e.next=26;break}e.t1=r;case 26:r=e.t1;case 27:e.next=37;break;case 29:if(e.prev=29,e.t2=e.catch(13),r){e.next=33;break}throw e.t2;case 33:throw(o=new Error(r.statusText)).statusCode=o.status=r.status,o.responseError=e.t2,o;case 37:if(r.ok){e.next=42;break}throw(i=new Error(r.statusText)).statusCode=i.status=r.status,i.response=r,i;case 42:return e.abrupt("return",r);case 43:case"end":return e.stop()}},e,this,[[13,29]])}));return function(t){return e.apply(this,arguments)}}();var _=t.shouldDownloadAsText=function(){return/(json|xml|yaml|text)\b/.test(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"")}},function(e,t){e.exports=n(40)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){return Array.isArray(e)?e.length<1?"":"/"+e.map(function(e){return(e+"").replace(/~/g,"~0").replace(/\//g,"~1")}).join("/"):e}function i(e,t,n){return{op:"replace",path:e,value:t,meta:n}}function a(e,t,n){return f(c(e.filter(m).map(function(e){return t(e.value,n,e.path)})||[]))}function u(e,t,n){return n=n||[],Array.isArray(e)?e.map(function(e,r){return u(e,t,n.concat(r))}):p(e)?(0,w.default)(e).map(function(r){return u(e[r],t,n.concat(r))}):t(e,n[n.length-1],n)}function s(e,t,n){var r=[];if((n=n||[]).length>0){var o=t(e,n[n.length-1],n);o&&(r=r.concat(o))}if(Array.isArray(e)){var i=e.map(function(e,r){return s(e,t,n.concat(r))});i&&(r=r.concat(i))}else if(p(e)){var a=(0,w.default)(e).map(function(r){return s(e[r],t,n.concat(r))});a&&(r=r.concat(a))}return c(r)}function l(e){return Array.isArray(e)?e:[e]}function c(e){var t;return(t=[]).concat.apply(t,(0,_.default)(e.map(function(e){return Array.isArray(e)?c(e):e})))}function f(e){return e.filter(function(e){return void 0!==e})}function p(e){return e&&"object"===(void 0===e?"undefined":(0,b.default)(e))}function d(e){return e&&"function"==typeof e}function h(e){if(g(e)){var t=e.op;return"add"===t||"remove"===t||"replace"===t}return!1}function v(e){return h(e)||g(e)&&"mutation"===e.type}function m(e){return v(e)&&("add"===e.op||"replace"===e.op||"merge"===e.op||"mergeDeep"===e.op)}function g(e){return e&&"object"===(void 0===e?"undefined":(0,b.default)(e))}function y(e,t){try{return S.default.getValueByPointer(e,t)}catch(e){return console.error(e),{}}}Object.defineProperty(t,"__esModule",{value:!0});var b=r(n(1)),_=r(n(34)),w=r(n(0)),E=r(n(35)),x=r(n(2)),S=r(n(36)),C=r(n(4)),k=r(n(37)),A=r(n(38));t.default={add:function(e,t){return{op:"add",path:e,value:t}},replace:i,remove:function(e,t){return{op:"remove",path:e}},merge:function(e,t){return{type:"mutation",op:"merge",path:e,value:t}},mergeDeep:function(e,t){return{type:"mutation",op:"mergeDeep",path:e,value:t}},context:function(e,t){return{type:"context",path:e,value:t}},getIn:function(e,t){return t.reduce(function(e,t){return void 0!==t&&e?e[t]:e},e)},applyPatch:function(e,t,n){if(n=n||{},"merge"===(t=(0,x.default)({},t,{path:t.path&&o(t.path)})).op){var r=y(e,t.path);(0,x.default)(r,t.value),S.default.applyPatch(e,[i(t.path,r)])}else if("mergeDeep"===t.op){var a=y(e,t.path);for(var u in t.value){var s=t.value[u],l=Array.isArray(s);if(l){var c=a[u]||[];a[u]=c.concat(s)}else if(p(s)&&!l){var f=(0,x.default)({},a[u]);for(var d in s){if(Object.prototype.hasOwnProperty.call(f,d)){f=(0,k.default)((0,A.default)({},f),s);break}(0,x.default)(f,(0,E.default)({},d,s[d]))}a[u]=f}else a[u]=s}}else if("add"===t.op&&""===t.path&&p(t.value)){var h=(0,w.default)(t.value).reduce(function(e,n){return e.push({op:"add",path:"/"+o(n),value:t.value[n]}),e},[]);S.default.applyPatch(e,h)}else if("replace"===t.op&&""===t.path){var v=t.value;n.allowMetaPatches&&t.meta&&m(t)&&(Array.isArray(t.value)||p(t.value))&&(v=(0,x.default)({},v,t.meta)),e=v}else if(S.default.applyPatch(e,[t]),n.allowMetaPatches&&t.meta&&m(t)&&(Array.isArray(t.value)||p(t.value))){var g=y(e,t.path),b=(0,x.default)({},g,t.meta);S.default.applyPatch(e,[i(t.path,b)])}return e},parentPathMatch:function(e,t){if(!Array.isArray(t))return!1;for(var n=0,r=t.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.requestInterceptor,r=t.responseInterceptor,o=e.withCredentials?"include":"same-origin";return function(t){return e({url:t,loadSpec:!0,requestInterceptor:n,responseInterceptor:r,headers:{Accept:"application/json"},credentials:o}).then(function(e){return e.body})}}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(4)),a=r(n(11));t.makeFetchJSON=o,t.clearCache=function(){s.plugins.refs.clearCache()},t.default=function(e){function t(e){var t=this;E&&(s.plugins.refs.docCache[E]=e),s.plugins.refs.fetchJSON=o(w,{requestInterceptor:y,responseInterceptor:b});var n=[s.plugins.refs];return"function"==typeof g&&n.push(s.plugins.parameters),"function"==typeof m&&n.push(s.plugins.properties),"strict"!==p&&n.push(s.plugins.allOf),(0,l.default)({spec:e,context:{baseDoc:E},plugins:n,allowMetaPatches:h,pathDiscriminator:v,parameterMacro:g,modelPropertyMacro:m}).then(_?function(){var e=(0,a.default)(i.default.mark(function e(n){return i.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",n);case 1:case"end":return e.stop()}},e,t)}));return function(t){return e.apply(this,arguments)}}():c.normalizeSwagger)}var n=e.fetch,r=e.spec,f=e.url,p=e.mode,d=e.allowMetaPatches,h=void 0===d||d,v=e.pathDiscriminator,m=e.modelPropertyMacro,g=e.parameterMacro,y=e.requestInterceptor,b=e.responseInterceptor,_=e.skipNormalization,w=e.http,E=e.baseDoc;return E=E||f,w=n||w||u.default,r?t(r):o(w,{requestInterceptor:y,responseInterceptor:b})(E).then(t)};var u=r(n(7)),s=n(31),l=r(s),c=n(5)},function(e,t){e.exports=n(204)},function(e,t){e.exports=n(91)},function(e,t){e.exports=n(2)},function(e,t){e.exports=n(3)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){function n(){Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack;for(var e=arguments.length,n=Array(e),r=0;r-1||o.indexOf(n)>-1||i.some(function(e){return n.indexOf(e)>-1})};var r=["properties"],o=["definitions","parameters","responses","securityDefinitions","components/schemas","components/responses","components/parameters","components/securitySchemes"],i=["schema/example"]},function(e,t,n){e.exports=n(24)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("string"==typeof e?n.url=e:n=e,!(this instanceof o))return new o(n);(0,a.default)(this,n);var r=this.resolve().then(function(){return t.disableInterfaces||(0,a.default)(t,o.makeApisTagOperation(t)),t});return r.client=this,r}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(3)),a=r((r(n(25)),n(6))),u=r(n(14)),s=r(n(10)),l=n(7),c=r(l),f=n(16),p=r(f),d=r(n(48)),h=n(49),v=n(51),m=n(5);o.http=c.default,o.makeHttp=l.makeHttp.bind(null,o.http),o.resolve=p.default,o.resolveSubtree=d.default,o.execute=v.execute,o.serializeRes=l.serializeRes,o.serializeHeaders=l.serializeHeaders,o.clearCache=f.clearCache,o.parameterBuilders=v.PARAMETER_BUILDERS,o.makeApisTagOperation=h.makeApisTagOperation,o.buildRequest=v.buildRequest,o.helpers={opId:m.opId},o.prototype={http:c.default,execute:function(e){return this.applyDefaults(),o.execute((0,i.default)({spec:this.spec,http:this.http,securities:{authorized:this.authorizations},contextUrl:"string"==typeof this.url?this.url:void 0},e))},resolve:function(){var e=this;return o.resolve({spec:this.spec,url:this.url,allowMetaPatches:this.allowMetaPatches,requestInterceptor:this.requestInterceptor||null,responseInterceptor:this.responseInterceptor||null}).then(function(t){return e.originalSpec=e.spec,e.spec=t.spec,e.errors=t.errors,e})}},o.prototype.applyDefaults=function(){var e=this.spec,t=this.url;if(t&&(0,u.default)(t,"http")){var n=s.default.parse(t);e.host||(e.host=n.host),e.schemes||(e.schemes=[n.protocol.replace(":","")]),e.basePath||(e.basePath="/")}},t.default=o,e.exports=t.default},function(e,t){e.exports=n(906)},function(e,t){e.exports=n(18)},function(e,t){e.exports=n(907)},function(e,t){e.exports=n(908)},function(e,t){e.exports=n(343)},function(e,t){e.exports=n(911)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.plugins=t.SpecMap=void 0;var o=r(n(8)),i=r(n(1)),a=r(n(17)),u=r(n(4)),s=r(n(0)),l=r(n(18)),c=r(n(32)),f=r(n(2)),p=r(n(19)),d=r(n(20));t.default=function(e){return new w(e).dispatch()};var h=r(n(33)),v=r(n(9)),m=r(n(39)),g=r(n(43)),y=r(n(44)),b=r(n(45)),_=r(n(46)),w=function(){function e(t){(0,p.default)(this,e),(0,f.default)(this,{spec:"",debugLevel:"info",plugins:[],pluginHistory:{},errors:[],mutations:[],promisedPatches:[],state:{},patches:[],context:{},contextTree:new _.default,showDebug:!1,allPatches:[],pluginProp:"specMap",libMethods:(0,f.default)((0,c.default)(this),v.default),allowMetaPatches:!1},t),this.get=this._get.bind(this),this.getContext=this._getContext.bind(this),this.hasRun=this._hasRun.bind(this),this.wrappedPlugins=this.plugins.map(this.wrapPlugin.bind(this)).filter(v.default.isFunction),this.patches.push(v.default.add([],this.spec)),this.patches.push(v.default.context([],this.context)),this.updatePatches(this.patches)}return(0,d.default)(e,[{key:"debug",value:function(e){if(this.debugLevel===e){for(var t,n=arguments.length,r=Array(n>1?n-1:0),o=1;o1?n-1:0),o=1;o0})}},{key:"nextPromisedPatch",value:function(){if(this.promisedPatches.length>0)return a.default.race(this.promisedPatches.map(function(e){return e.value}))}},{key:"getPluginHistory",value:function(e){var t=this.getPluginName(e);return this.pluginHistory[t]||[]}},{key:"getPluginRunCount",value:function(e){return this.getPluginHistory(e).length}},{key:"getPluginHistoryTip",value:function(e){var t=this.getPluginHistory(e);return t&&t[t.length-1]||{}}},{key:"getPluginMutationIndex",value:function(e){var t=this.getPluginHistoryTip(e).mutationIndex;return"number"!=typeof t?-1:t}},{key:"getPluginName",value:function(e){return e.pluginName}},{key:"updatePluginHistory",value:function(e,t){var n=this.getPluginName(e);(this.pluginHistory[n]=this.pluginHistory[n]||[]).push(t)}},{key:"updatePatches",value:function(e,t){var n=this;v.default.normalizeArray(e).forEach(function(e){if(e instanceof Error)n.errors.push(e);else try{if(!v.default.isObject(e))return void n.debug("updatePatches","Got a non-object patch",e);if(n.showDebug&&n.allPatches.push(e),v.default.isPromise(e.value))return n.promisedPatches.push(e),void n.promisedPatchThen(e);if(v.default.isContextPatch(e))return void n.setContext(e.path,e.value);if(v.default.isMutation(e))return void n.updateMutations(e)}catch(e){console.error(e),n.errors.push(e)}})}},{key:"updateMutations",value:function(e){"object"===(0,i.default)(e.value)&&!Array.isArray(e.value)&&this.allowMetaPatches&&(e.value=(0,f.default)({},e.value));var t=v.default.applyPatch(this.state,e,{allowMetaPatches:this.allowMetaPatches});t&&(this.mutations.push(e),this.state=t)}},{key:"removePromisedPatch",value:function(e){var t=this.promisedPatches.indexOf(e);t<0?this.debug("Tried to remove a promisedPatch that isn't there!"):this.promisedPatches.splice(t,1)}},{key:"promisedPatchThen",value:function(e){var t=this;return e.value=e.value.then(function(n){var r=(0,f.default)({},e,{value:n});t.removePromisedPatch(e),t.updatePatches(r)}).catch(function(n){t.removePromisedPatch(e),t.updatePatches(n)})}},{key:"getMutations",value:function(e,t){return e=e||0,"number"!=typeof t&&(t=this.mutations.length),this.mutations.slice(e,t)}},{key:"getCurrentMutations",value:function(){return this.getMutationsForPlugin(this.getCurrentPlugin())}},{key:"getMutationsForPlugin",value:function(e){var t=this.getPluginMutationIndex(e);return this.getMutations(t+1)}},{key:"getCurrentPlugin",value:function(){return this.currentPlugin}},{key:"getPatchesOfType",value:function(e,t){return e.filter(t)}},{key:"getLib",value:function(){return this.libMethods}},{key:"_get",value:function(e){return v.default.getIn(this.state,e)}},{key:"_getContext",value:function(e){return this.contextTree.get(e)}},{key:"setContext",value:function(e,t){return this.contextTree.set(e,t)}},{key:"_hasRun",value:function(e){return this.getPluginRunCount(this.getCurrentPlugin())>(e||0)}},{key:"_clone",value:function(e){return JSON.parse((0,o.default)(e))}},{key:"dispatch",value:function(){function e(e){e&&(e=v.default.fullyNormalizeArray(e),n.updatePatches(e,r))}var t=this,n=this,r=this.nextPlugin();if(!r){var o=this.nextPromisedPatch();if(o)return o.then(function(){return t.dispatch()}).catch(function(){return t.dispatch()});var i={spec:this.state,errors:this.errors};return this.showDebug&&(i.patches=this.allPatches),a.default.resolve(i)}if(n.pluginCount=n.pluginCount||{},n.pluginCount[r]=(n.pluginCount[r]||0)+1,n.pluginCount[r]>100)return a.default.resolve({spec:n.state,errors:n.errors.concat(new Error("We've reached a hard limit of 100 plugin runs"))});if(r!==this.currentPlugin&&this.promisedPatches.length){var u=this.promisedPatches.map(function(e){return e.value});return a.default.all(u.map(function(e){return e.then(Function,Function)})).then(function(){return t.dispatch()})}return function(){n.currentPlugin=r;var t=n.getCurrentMutations(),o=n.mutations.length-1;try{if(r.isGenerator){var i=!0,a=!1,u=void 0;try{for(var s,p=(0,l.default)(r(t,n.getLib()));!(i=(s=p.next()).done);i=!0)e(s.value)}catch(e){a=!0,u=e}finally{try{!i&&p.return&&p.return()}finally{if(a)throw u}}}else e(r(t,n.getLib()))}catch(t){console.error(t),e([(0,f.default)((0,c.default)(t),{plugin:r})])}finally{n.updatePluginHistory(r,{mutationIndex:o})}return n.dispatch()}()}}]),e}(),E={refs:m.default,allOf:g.default,parameters:y.default,properties:b.default};t.SpecMap=w,t.plugins=E},function(e,t){e.exports=n(350)},function(e,t){e.exports=n(288)},function(e,t){e.exports=n(83)},function(e,t){e.exports=n(22)},function(e,t){e.exports=n(912)},function(e,t){e.exports=n(179)},function(e,t){e.exports=n(915)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!A.test(e)){if(!t)throw new O("Tried to resolve a relative URL, without having a basePath. path: '"+e+"' basePath: '"+t+"'");return x.default.resolve(t,e)}return e}function i(e,t){return new O("Could not resolve reference because of: "+e.message,t,e)}function a(e){return(e+"").split("#")}function u(e,t){var n=P[e];if(n&&!S.default.isPromise(n))try{var r=l(t,n);return(0,b.default)(g.default.resolve(r),{__value:r})}catch(e){return g.default.reject(e)}return s(e).then(function(e){return l(t,e)})}function s(e){var t=P[e];return t?S.default.isPromise(t)?t:g.default.resolve(t):(P[e]=I.fetchJSON(e).then(function(t){return P[e]=t,t}),P[e])}function l(e,t){var n=c(e);if(n.length<1)return t;var r=S.default.getIn(t,n);if(void 0===r)throw new O("Could not resolve pointer: "+e+" does not exist in document",{pointer:e});return r}function c(e){if("string"!=typeof e)throw new TypeError("Expected a string, got a "+(void 0===e?"undefined":(0,v.default)(e)));return"/"===e[0]&&(e=e.substr(1)),""===e?[]:e.split("/").map(f)}function f(e){return"string"!=typeof e?e:E.default.unescape(e.replace(/~1/g,"/").replace(/~0/g,"~"))}function p(e){return E.default.escape(e.replace(/~/g,"~0").replace(/\//g,"~1"))}function d(e,t){if(j(t))return!0;var n=e.charAt(t.length),r=t.slice(-1);return 0===e.indexOf(t)&&(!n||"/"===n||"#"===n)&&"#"!==r}function h(e,t,n,r){var o=T.get(r);o||(o={},T.set(r,o));var i=function(e){return 0===e.length?"":"/"+e.map(p).join("/")}(n),a=(t||"")+"#"+e;if(t==r.contextTree.get([]).baseDoc&&d(i,e))return!0;var u="";if(n.some(function(e){return u=u+"/"+p(e),o[u]&&o[u].some(function(e){return d(e,a)||d(a,e)})}))return!0;o[i]=(o[i]||[]).concat(a)}Object.defineProperty(t,"__esModule",{value:!0});var v=r(n(1)),m=r(n(0)),g=r(n(17)),y=r(n(40)),b=r(n(2)),_=n(41),w=r(n(15)),E=r(n(42)),x=r(n(10)),S=r(n(9)),C=r(n(21)),k=n(22),A=new RegExp("^([a-z]+://|//)","i"),O=(0,C.default)("JSONRefError",function(e,t,n){this.originalError=n,(0,b.default)(this,t||{})}),P={},T=new y.default,M={key:"$ref",plugin:function(e,t,n,r){var s=n.slice(0,-1);if(!(0,k.isFreelyNamed)(s)){var l=r.getContext(n).baseDoc;if("string"!=typeof e)return new O("$ref: must be a string (JSON-Ref)",{$ref:e,baseDoc:l,fullPath:n});var f=a(e),p=f[0],d=f[1]||"",v=void 0;try{v=l||p?o(p,l):null}catch(t){return i(t,{pointer:d,$ref:e,basePath:v,fullPath:n})}var g=void 0,y=void 0;if(!h(d,v,s,r)){if(null==v?(y=c(d),void 0===(g=r.get(y))&&(g=new O("Could not resolve reference: "+e,{pointer:d,$ref:e,baseDoc:l,fullPath:n}))):g=null!=(g=u(v,d)).__value?g.__value:g.catch(function(t){throw i(t,{pointer:d,$ref:e,baseDoc:l,fullPath:n})}),g instanceof Error)return[S.default.remove(n),g];var b=S.default.replace(s,g,{$$ref:e});return v&&v!==l?[b,S.default.context(s,{baseDoc:v})]:function(e,t){var n=[e];return t.path.reduce(function(e,t){return n.push(e[t]),e[t]},e),function e(t){return S.default.isObject(t)&&(n.indexOf(t)>=0||(0,m.default)(t).some(function(n){return e(t[n])}))}(t.value)}(r.state,b)?void 0:b}}}},I=(0,b.default)(M,{docCache:P,absoluteify:o,clearCache:function(e){void 0!==e?delete P[e]:(0,m.default)(P).forEach(function(e){delete P[e]})},JSONRefError:O,wrapError:i,getDoc:s,split:a,extractFromDoc:u,fetchJSON:function(e){return(0,_.fetch)(e,{headers:{Accept:"application/json, application/yaml"},loadSpec:!0}).then(function(e){return e.text()}).then(function(e){return w.default.safeLoad(e)})},extract:l,jsonPointerToArray:c,unescapeJsonPointerToken:f});t.default=I;var j=function(e){return!e||"/"===e||"#"===e};e.exports=t.default},function(e,t){e.exports=n(916)},function(e,t){e.exports=n(927)},function(e,t){e.exports=n(928)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(e){return e&&e.__esModule?e:{default:e}}(n(2)),o=n(22);t.default={key:"allOf",plugin:function(e,t,n,i,a){if(!a.meta||!a.meta.$$ref){var u=n.slice(0,-1);if(!(0,o.isFreelyNamed)(u)){if(!Array.isArray(e)){var s=new TypeError("allOf must be an array");return s.fullPath=n,s}var l=!1,c=a.value;u.forEach(function(e){c&&(c=c[e])}),delete(c=(0,r.default)({},c)).allOf;var f=[i.replace(u,{})].concat(e.map(function(e,t){if(!i.isObject(e)){if(l)return null;l=!0;var r=new TypeError("Elements in allOf must be objects");return r.fullPath=n,r}return i.mergeDeep(u,e)}));return f.push(i.mergeDeep(u,c)),c.$$ref||f.push(i.remove([].concat(u,"$$ref"))),f}}}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(2)),i=r(n(9));t.default={key:"parameters",plugin:function(e,t,n,r,a){if(Array.isArray(e)&&e.length){var u=(0,o.default)([],e),s=n.slice(0,-1),l=(0,o.default)({},i.default.getIn(r.spec,s));return e.forEach(function(e,t){try{u[t].default=r.parameterMacro(l,e)}catch(e){var o=new Error(e);return o.fullPath=n,o}}),i.default.replace(n,u)}return i.default.replace(n,e)}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(2)),i=r(n(9));t.default={key:"properties",plugin:function(e,t,n,r){var a=(0,o.default)({},e);for(var u in e)try{a[u].default=r.modelPropertyMacro(a[u])}catch(e){var s=new Error(e);return s.fullPath=n,s}return i.default.replace(n,a)}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){return i({children:{}},e,t)}function i(e,t,n){return e.value=t||{},e.protoValue=n?(0,u.default)({},n.protoValue,e.value):e.value,(0,a.default)(e.children).forEach(function(t){var n=e.children[t];e.children[t]=i(n,n.value,e)}),e}Object.defineProperty(t,"__esModule",{value:!0});var a=r(n(0)),u=r(n(3)),s=r(n(19)),l=r(n(20)),c=function(){function e(t){(0,s.default)(this,e),this.root=o(t||{})}return(0,l.default)(e,[{key:"set",value:function(e,t){var n=this.getParent(e,!0);if(n){var r=e[e.length-1],a=n.children;a[r]?i(a[r],t,n):a[r]=o(t,n)}else i(this.root,t,null)}},{key:"get",value:function(e){if((e=e||[]).length<1)return this.root.value;for(var t=this.root,n=void 0,r=void 0,o=0;o2&&void 0!==arguments[2]?arguments[2]:{};return o.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return r=y.returnEntireTree,a=y.baseDoc,c=y.requestInterceptor,f=y.responseInterceptor,p=y.parameterMacro,d=y.modelPropertyMacro,h={pathDiscriminator:n,baseDoc:a,requestInterceptor:c,responseInterceptor:f,parameterMacro:p,modelPropertyMacro:d},v=(0,l.normalizeSwagger)({spec:t}),m=v.spec,e.next=5,(0,s.default)((0,i.default)({},h,{spec:m,allowMetaPatches:!0,skipNormalization:!0}));case 5:return g=e.sent,!r&&Array.isArray(n)&&n.length&&(g.spec=(0,u.default)(g.spec,n)||null),e.abrupt("return",g);case 8:case"end":return e.stop()}},e,this)}));return function(t,n){return e.apply(this,arguments)}}(),e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=t.pathName,r=t.method,o=t.operationId;return function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.execute((0,a.default)({spec:e.spec},(0,u.default)(e,"requestInterceptor","responseInterceptor","userFetch"),{pathName:n,method:r,parameters:t,operationId:o},i))}}}function i(e){var t=e.spec,n=e.cb,r=void 0===n?l:n,o=e.defaultTag,i=void 0===o?"default":o,a=e.v2OperationIdCompatibilityMode,u={},f={};return(0,s.eachOperation)(t,function(e){var n=e.pathName,o=e.method,l=e.operation;(l.tags?c(l.tags):[i]).forEach(function(e){if("string"==typeof e){var i=f[e]=f[e]||{},c=(0,s.opId)(l,n,o,{v2OperationIdCompatibilityMode:a}),p=r({spec:t,pathName:n,method:o,operation:l,operationId:c});if(u[c])u[c]++,i[""+c+u[c]]=p;else if(void 0!==i[c]){var d=u[c]||1;u[c]=d+1,i[""+c+u[c]]=p;var h=i[c];delete i[c],i[""+c+d]=h}else i[c]=p}})}),f}Object.defineProperty(t,"__esModule",{value:!0}),t.self=void 0;var a=r(n(3));t.makeExecute=o,t.makeApisTagOperationsOperationExecute=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=f.makeExecute(e),n=f.mapTagOperations({v2OperationIdCompatibilityMode:e.v2OperationIdCompatibilityMode,spec:e.spec,cb:t}),r={};for(var o in n)for(var i in r[o]={operations:{}},n[o])r[o].operations[i]={execute:n[o][i]};return{apis:r}},t.makeApisTagOperation=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=f.makeExecute(e);return{apis:f.mapTagOperations({v2OperationIdCompatibilityMode:e.v2OperationIdCompatibilityMode,spec:e.spec,cb:t})}},t.mapTagOperations=i;var u=r(n(50)),s=n(5),l=function(){return null},c=function(e){return Array.isArray(e)?e:[e]},f=t.self={mapTagOperations:i,makeExecute:o}},function(e,t){e.exports=n(929)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.spec,n=e.operationId,r=(e.securities,e.requestContentType,e.responseContentType),o=e.scheme,a=e.requestInterceptor,s=e.responseInterceptor,c=e.contextUrl,f=e.userFetch,p=(e.requestBody,e.server),d=e.serverVariables,h=e.http,g=e.parameters,y=e.parameterBuilders,O=(0,x.isOAS3)(t);y||(y=O?_.default:b.default);var P={url:"",credentials:h&&h.withCredentials?"include":"same-origin",headers:{},cookies:{}};a&&(P.requestInterceptor=a),s&&(P.responseInterceptor=s),f&&(P.userFetch=f);var T=(0,x.getOperationRaw)(t,n);if(!T)throw new C("Operation "+n+" not found");var M=T.operation,I=void 0===M?{}:M,j=T.method,N=T.pathName;if(P.url+=i({spec:t,scheme:o,contextUrl:c,server:p,serverVariables:d,pathName:N,method:j}),!n)return delete P.cookies,P;P.url+=N,P.method=(""+j).toUpperCase(),g=g||{};var R=t.paths[N]||{};r&&(P.headers.accept=r);var D=A([].concat(S(I.parameters)).concat(S(R.parameters)));D.forEach(function(e){var n=y[e.in],r=void 0;if("body"===e.in&&e.schema&&e.schema.properties&&(r=g),void 0===(r=e&&e.name&&g[e.name])?r=e&&e.name&&g[e.in+"."+e.name]:k(e.name,D).length>1&&console.warn("Parameter '"+e.name+"' is ambiguous because the defined spec has more than one parameter with the name: '"+e.name+"' and the passed-in parameter values did not define an 'in' value."),null!==r){if(void 0!==e.default&&void 0===r&&(r=e.default),void 0===r&&e.required&&!e.allowEmptyValue)throw new Error("Required parameter "+e.name+" is not provided");if(O&&e.schema&&"object"===e.schema.type&&"string"==typeof r)try{r=JSON.parse(r)}catch(e){throw new Error("Could not parse object parameter value string as JSON")}n&&n({req:P,parameter:e,value:r,operation:I,spec:t})}});var L=(0,u.default)({},e,{operation:I});if((P=O?(0,w.default)(L,P):(0,E.default)(L,P)).cookies&&(0,l.default)(P.cookies).length){var U=(0,l.default)(P.cookies).reduce(function(e,t){var n=P.cookies[t];return e+(e?"&":"")+v.default.serialize(t,n)},"");P.headers.Cookie=U}return P.cookies&&delete P.cookies,(0,m.mergeInQueryOrForm)(P),P}function i(e){return(0,x.isOAS3)(e.spec)?function(e){var t=e.spec,n=e.pathName,r=e.method,o=e.server,i=e.contextUrl,a=e.serverVariables,u=void 0===a?{}:a,s=(0,f.default)(t,["paths",n,(r||"").toLowerCase(),"servers"])||(0,f.default)(t,["paths",n,"servers"])||(0,f.default)(t,["servers"]),l="",c=null;if(o&&s&&s.length){var p=s.map(function(e){return e.url});p.indexOf(o)>-1&&(l=o,c=s[p.indexOf(o)])}!l&&s&&s.length&&(l=s[0].url,c=s[0]),l.indexOf("{")>-1&&function(e){for(var t=[],n=/{([^}]+)}/g,r=void 0;r=n.exec(e);)t.push(r[1]);return t}(l).forEach(function(e){if(c.variables&&c.variables[e]){var t=c.variables[e],n=u[e]||t.default,r=new RegExp("{"+e+"}","g");l=l.replace(r,n)}});return function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=h.default.parse(e),r=h.default.parse(t),o=P(n.protocol)||P(r.protocol)||"",i=n.host||r.host,a=n.pathname||"",u=void 0;return"/"===(u=o&&i?o+"://"+(i+a):a)[u.length-1]?u.slice(0,-1):u}(l,i)}(e):function(e){var t=e.spec,n=e.scheme,r=e.contextUrl,o=void 0===r?"":r,i=h.default.parse(o),a=Array.isArray(t.schemes)?t.schemes[0]:null,u=n||a||P(i.protocol)||"http",s=t.host||i.host||"",l=t.basePath||"",c=void 0;return"/"===(c=u&&s?u+"://"+(s+l):l)[c.length-1]?c.slice(0,-1):c}(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.self=void 0;var a=r(n(8)),u=r(n(3)),s=r(n(52)),l=r(n(0)),c=r(n(2));t.execute=function(e){var t=e.http,n=e.fetch,r=e.spec,o=e.operationId,i=e.pathName,l=e.method,c=e.parameters,f=e.securities,h=(0,s.default)(e,["http","fetch","spec","operationId","pathName","method","parameters","securities"]),v=t||n||g.default;i&&l&&!o&&(o=(0,x.legacyIdFromPathMethod)(i,l));var m=O.buildRequest((0,u.default)({spec:r,operationId:o,parameters:c,securities:f,http:v},h));return m.body&&((0,p.default)(m.body)||(0,d.default)(m.body))&&(m.body=(0,a.default)(m.body)),v(m)},t.buildRequest=o,t.baseUrl=i;var f=r((r(n(6)),n(12))),p=r(n(53)),d=r(n(54)),h=r((r(n(13)),n(10))),v=r(n(55)),m=n(7),g=r(m),y=r(n(21)),b=r(n(56)),_=r(n(57)),w=r(n(62)),E=r(n(64)),x=n(5),S=function(e){return Array.isArray(e)?e:[]},C=(0,y.default)("OperationNotFoundError",function(e,t,n){this.originalError=n,(0,c.default)(this,t||{})}),k=function(e,t){return t.filter(function(t){return t.name===e})},A=function(e){var t={};e.forEach(function(e){t[e.in]||(t[e.in]={}),t[e.in][e.name]=e});var n=[];return(0,l.default)(t).forEach(function(e){(0,l.default)(t[e]).forEach(function(r){n.push(t[e][r])})}),n},O=t.self={buildRequest:o},P=function(e){return e?e.replace(/\W/g,""):null}},function(e,t){e.exports=n(84)},function(e,t){e.exports=n(228)},function(e,t){e.exports=n(24)},function(e,t){e.exports=n(932)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={body:function(e){var t=e.req,n=e.value;t.body=n},header:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{},void 0!==r&&(t.headers[n.name]=r)},query:function(e){var t=e.req,n=e.value,r=e.parameter;if(t.query=t.query||{},!1===n&&"boolean"===r.type&&(n="false"),0===n&&["number","integer"].indexOf(r.type)>-1&&(n="0"),n)t.query[r.name]={collectionFormat:r.collectionFormat,value:n};else if(r.allowEmptyValue&&void 0!==n){var o=r.name;t.query[o]=t.query[o]||{},t.query[o].allowEmptyValue=!0}},path:function(e){var t=e.req,n=e.value,r=e.parameter;t.url=t.url.replace("{"+r.name+"}",encodeURIComponent(n))},formData:function(e){var t=e.req,n=e.value,r=e.parameter;(n||r.allowEmptyValue)&&(t.form=t.form||{},t.form[r.name]={value:n,allowEmptyValue:r.allowEmptyValue,collectionFormat:r.collectionFormat})}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(0)),i=r(n(1)),a=r(n(58));t.default={path:function(e){var t=e.req,n=e.value,r=e.parameter,o=r.name,i=r.style,u=r.explode,s=(0,a.default)({key:r.name,value:n,style:i||"simple",explode:u||!1,escape:!1});t.url=t.url.replace("{"+o+"}",s)},query:function(e){var t=e.req,n=e.value,r=e.parameter;if(t.query=t.query||{},!1===n&&(n="false"),0===n&&(n="0"),n){var u=void 0===n?"undefined":(0,i.default)(n);"deepObject"===r.style?(0,o.default)(n).forEach(function(e){var o=n[e];t.query[r.name+"["+e+"]"]={value:(0,a.default)({key:e,value:o,style:"deepObject",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}}):"object"!==u||Array.isArray(n)||"form"!==r.style&&r.style||!r.explode&&void 0!==r.explode?t.query[r.name]={value:(0,a.default)({key:r.name,value:n,style:r.style||"form",explode:void 0===r.explode||r.explode,escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}:(0,o.default)(n).forEach(function(e){var o=n[e];t.query[e]={value:(0,a.default)({key:e,value:o,style:r.style||"form",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}})}else if(r.allowEmptyValue&&void 0!==n){var s=r.name;t.query[s]=t.query[s]||{},t.query[s].allowEmptyValue=!0}},header:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{},u.indexOf(n.name.toLowerCase())>-1||void 0!==r&&(t.headers[n.name]=(0,a.default)({key:n.name,value:r,style:n.style||"simple",explode:void 0!==n.explode&&n.explode,escape:!1}))},cookie:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{};var o=void 0===r?"undefined":(0,i.default)(r);if("undefined"!==o){var u="object"===o&&!Array.isArray(r)&&n.explode?"":n.name+"=";t.headers.Cookie=u+(0,a.default)({key:n.name,value:r,escape:!1,style:n.style||"form",explode:void 0!==n.explode&&n.explode})}}};var u=["accept","authorization","content-type"];e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).escape,n=arguments[2];return"number"==typeof e&&(e=e.toString()),"string"==typeof e&&e.length&&t?n?JSON.parse(e):(0,s.stringToCharArray)(e).map(function(e){return c(e)?e:l(e)&&"unsafe"===t?e:((0,u.default)(e)||[]).map(function(e){return e.toString(16).toUpperCase()}).map(function(e){return"%"+e}).join("")}).join(""):e}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(0)),a=r(n(1));t.encodeDisallowedCharacters=o,t.default=function(e){var t=e.value;return Array.isArray(t)?function(e){var t=e.key,n=e.value,r=e.style,i=e.explode,a=e.escape,u=function(e){return o(e,{escape:a})};if("simple"===r)return n.map(function(e){return u(e)}).join(",");if("label"===r)return"."+n.map(function(e){return u(e)}).join(".");if("matrix"===r)return n.map(function(e){return u(e)}).reduce(function(e,n){return!e||i?(e||"")+";"+t+"="+n:e+","+n},"");if("form"===r){var s=i?"&"+t+"=":",";return n.map(function(e){return u(e)}).join(s)}if("spaceDelimited"===r){var l=i?t+"=":"";return n.map(function(e){return u(e)}).join(" "+l)}if("pipeDelimited"===r){var c=i?t+"=":"";return n.map(function(e){return u(e)}).join("|"+c)}}(e):"object"===(void 0===t?"undefined":(0,a.default)(t))?function(e){var t=e.key,n=e.value,r=e.style,a=e.explode,u=e.escape,s=function(e){return o(e,{escape:u})},l=(0,i.default)(n);return"simple"===r?l.reduce(function(e,t){var r=s(n[t]);return(e?e+",":"")+t+(a?"=":",")+r},""):"label"===r?l.reduce(function(e,t){var r=s(n[t]);return(e?e+".":".")+t+(a?"=":".")+r},""):"matrix"===r&&a?l.reduce(function(e,t){var r=s(n[t]);return(e?e+";":";")+t+"="+r},""):"matrix"===r?l.reduce(function(e,r){var o=s(n[r]);return(e?e+",":";"+t+"=")+r+","+o},""):"form"===r?l.reduce(function(e,t){var r=s(n[t]);return(e?e+(a?"&":","):"")+t+(a?"=":",")+r},""):void 0}(e):function(e){var t=e.key,n=e.value,r=e.style,i=e.escape,a=function(e){return o(e,{escape:i})};return"simple"===r?a(n):"label"===r?"."+a(n):"matrix"===r?";"+t+"="+a(n):"form"===r?a(n):"deepObject"===r?a(n):void 0}(e)};var u=r((r(n(59)),n(60))),s=n(61),l=function(e){return":/?#[]@!$&'()*+,;=".indexOf(e)>-1},c=function(e){return/^[a-z0-9\-._~]+$/i.test(e)}},function(e,t){e.exports=n(933)},function(e,t){e.exports=n(934)},function(e,t){e.exports=n(935)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,i=void 0===o?{}:o,a=e.spec,f=(0,s.default)({},t),p=r.authorized,d=void 0===p?{}:p,h=i.security||a.security||[],v=d&&!!(0,u.default)(d).length,m=(0,l.default)(a,["components","securitySchemes"])||{};return f.headers=f.headers||{},f.query=f.query||{},(0,u.default)(r).length&&v&&h&&(!Array.isArray(i.security)||i.security.length)?(h.forEach(function(e,t){for(var n in e){var r=d[n],o=m[n];if(r){var i=r.value||r,a=o.type;if(r)if("apiKey"===a)"query"===o.in&&(f.query[o.name]=i),"header"===o.in&&(f.headers[o.name]=i),"cookie"===o.in&&(f.cookies[o.name]=i);else if("http"===a){if("basic"===o.scheme){var u=i.username,s=i.password,l=(0,c.default)(u+":"+s);f.headers.Authorization="Basic "+l}"bearer"===o.scheme&&(f.headers.Authorization="Bearer "+i)}else if("oauth2"===a){var p=r.token||{},h=p.access_token,v=p.token_type;v&&"bearer"!==v.toLowerCase()||(v="Bearer"),f.headers.Authorization=v+" "+h}}}}),f):t}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(8)),a=r(n(1)),u=r(n(0));t.default=function(e,t){var n=e.operation,r=e.requestBody,s=e.securities,l=e.spec,c=e.attachContentTypeForEmptyPayload,p=e.requestContentType;t=o({request:t,securities:s,operation:n,spec:l});var d=n.requestBody||{},h=(0,u.default)(d.content||{}),v=p&&h.indexOf(p)>-1;if(r||c){if(p&&v)t.headers["Content-Type"]=p;else if(!p){var m=h[0];m&&(t.headers["Content-Type"]=m,p=m)}}else p&&v&&(t.headers["Content-Type"]=p);return r&&(p?h.indexOf(p)>-1&&("application/x-www-form-urlencoded"===p||0===p.indexOf("multipart/")?"object"===(void 0===r?"undefined":(0,a.default)(r))?(t.form={},(0,u.default)(r).forEach(function(e){var n,o=r[e],u=void 0;"undefined"!=typeof File&&(u=o instanceof File),"undefined"!=typeof Blob&&(u=u||o instanceof Blob),void 0!==f.Buffer&&(u=u||f.Buffer.isBuffer(o)),n="object"!==(void 0===o?"undefined":(0,a.default)(o))||u?o:Array.isArray(o)?o.toString():(0,i.default)(o),t.form[e]={value:n}})):t.form=r:t.body=r):t.body=r),t},t.applySecurities=o;var s=r(n(6)),l=r(n(12)),c=r(n(13)),f=n(63)},function(e,t){e.exports=n(55)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,s=void 0===o?{}:o,l=e.spec,c=(0,u.default)({},t),f=r.authorized,p=void 0===f?{}:f,d=r.specSecurity,h=void 0===d?[]:d,v=s.security||h,m=p&&!!(0,i.default)(p).length,g=l.securityDefinitions;return c.headers=c.headers||{},c.query=c.query||{},(0,i.default)(r).length&&m&&v&&(!Array.isArray(s.security)||s.security.length)?(v.forEach(function(e,t){for(var n in e){var r=p[n];if(r){var o=r.token,i=r.value||r,u=g[n],s=u.type,l=o&&o.access_token,f=o&&o.token_type;if(r)if("apiKey"===s){var d="query"===u.in?"query":"headers";c[d]=c[d]||{},c[d][u.name]=i}else"basic"===s?i.header?c.headers.authorization=i.header:(i.base64=(0,a.default)(i.username+":"+i.password),c.headers.authorization="Basic "+i.base64):"oauth2"===s&&l&&(f=f&&"bearer"!==f.toLowerCase()?f:"Bearer",c.headers.authorization=f+" "+l)}}}),c):t}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(0));t.default=function(e,t){var n=e.spec,r=e.operation,i=e.securities,a=e.requestContentType,u=e.attachContentTypeForEmptyPayload;if((t=o({request:t,securities:i,operation:r,spec:n})).body||t.form||u)a?t.headers["Content-Type"]=a:Array.isArray(r.consumes)?t.headers["Content-Type"]=r.consumes[0]:Array.isArray(n.consumes)?t.headers["Content-Type"]=n.consumes[0]:r.parameters&&r.parameters.filter(function(e){return"file"===e.type}).length?t.headers["Content-Type"]="multipart/form-data":r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length&&(t.headers["Content-Type"]="application/x-www-form-urlencoded");else if(a){var s=r.parameters&&r.parameters.filter(function(e){return"body"===e.in}).length>0,l=r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length>0;(s||l)&&(t.headers["Content-Type"]=a)}return t},t.applySecurities=o;var a=r(n(13)),u=r(n(6));r(n(7))}])},function(e,t,n){"use strict";var r=Object.prototype.hasOwnProperty,o=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),i=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},r=0;r=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122?n+=t.charAt(r):i<128?n+=o[i]:i<2048?n+=o[192|i>>6]+o[128|63&i]:i<55296||i>=57344?n+=o[224|i>>12]+o[128|i>>6&63]+o[128|63&i]:(r+=1,i=65536+((1023&i)<<10|1023&t.charCodeAt(r)),n+=o[240|i>>18]+o[128|i>>12&63]+o[128|i>>6&63]+o[128|63&i])}return n},isBuffer:function(e){return null!==e&&void 0!==e&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},merge:function e(t,n,o){if(!n)return t;if("object"!=typeof n){if(Array.isArray(t))t.push(n);else{if("object"!=typeof t)return[t,n];(o.plainObjects||o.allowPrototypes||!r.call(Object.prototype,n))&&(t[n]=!0)}return t}if("object"!=typeof t)return[t].concat(n);var a=t;return Array.isArray(t)&&!Array.isArray(n)&&(a=i(t,o)),Array.isArray(t)&&Array.isArray(n)?(n.forEach(function(n,i){r.call(t,i)?t[i]&&"object"==typeof t[i]?t[i]=e(t[i],n,o):t.push(n):t[i]=n}),t):Object.keys(n).reduce(function(t,i){var a=n[i];return r.call(t,i)?t[i]=e(t[i],a,o):t[i]=a,t},a)}}},function(e,t,n){"use strict";var r=String.prototype.replace,o=/%20/g;e.exports={default:"RFC3986",formatters:{RFC1738:function(e){return r.call(e,o,"+")},RFC3986:function(e){return e}},RFC1738:"RFC1738",RFC3986:"RFC3986"}},function(e,t,n){var r=Array.prototype.slice,o=n(913),i=n(914),a=e.exports=function(e,t,n){return n||(n={}),e===t||(e instanceof Date&&t instanceof Date?e.getTime()===t.getTime():!e||!t||"object"!=typeof e&&"object"!=typeof t?n.strict?e===t:e==t:function(e,t,n){var l,c;if(u(e)||u(t))return!1;if(e.prototype!==t.prototype)return!1;if(i(e))return!!i(t)&&(e=r.call(e),t=r.call(t),a(e,t,n));if(s(e)){if(!s(t))return!1;if(e.length!==t.length)return!1;for(l=0;l=0;l--)if(f[l]!=p[l])return!1;for(l=f.length-1;l>=0;l--)if(c=f[l],!a(e[c],t[c],n))return!1;return typeof e==typeof t}(e,t,n))};function u(e){return null===e||void 0===e}function s(e){return!(!e||"object"!=typeof e||"number"!=typeof e.length)&&("function"==typeof e.copy&&"function"==typeof e.slice&&!(e.length>0&&"number"!=typeof e[0]))}},function(e,t,n){var r={strict:!0},o=n(391),i=function(e,t){return o(e,t,r)},a=n(231);t.JsonPatchError=a.PatchError,t.deepClone=a._deepClone;var u={add:function(e,t,n){return e[t]=this.value,{newDocument:n}},remove:function(e,t,n){var r=e[t];return delete e[t],{newDocument:n,removed:r}},replace:function(e,t,n){var r=e[t];return e[t]=this.value,{newDocument:n,removed:r}},move:function(e,t,n){var r=l(n,this.path);r&&(r=a._deepClone(r));var o=c(n,{op:"remove",path:this.from}).removed;return c(n,{op:"add",path:this.path,value:o}),{newDocument:n,removed:r}},copy:function(e,t,n){var r=l(n,this.from);return c(n,{op:"add",path:this.path,value:a._deepClone(r)}),{newDocument:n}},test:function(e,t,n){return{newDocument:n,test:i(e[t],this.value)}},_get:function(e,t,n){return this.value=e[t],{newDocument:n}}},s={add:function(e,t,n){return a.isInteger(t)?e.splice(t,0,this.value):e[t]=this.value,{newDocument:n,index:t}},remove:function(e,t,n){return{newDocument:n,removed:e.splice(t,1)[0]}},replace:function(e,t,n){var r=e[t];return e[t]=this.value,{newDocument:n,removed:r}},move:u.move,copy:u.copy,test:u.test,_get:u._get};function l(e,t){if(""==t)return e;var n={op:"_get",path:t};return c(e,n),n.value}function c(e,n,r,o){if(void 0===r&&(r=!1),void 0===o&&(o=!0),r&&("function"==typeof r?r(n,0,e,n.path):p(n,0)),""===n.path){var c={newDocument:e};if("add"===n.op)return c.newDocument=n.value,c;if("replace"===n.op)return c.newDocument=n.value,c.removed=e,c;if("move"===n.op||"copy"===n.op)return c.newDocument=l(e,n.from),"move"===n.op&&(c.removed=e),c;if("test"===n.op){if(c.test=i(e,n.value),!1===c.test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",0,n,e);return c.newDocument=e,c}if("remove"===n.op)return c.removed=e,c.newDocument=null,c;if("_get"===n.op)return n.value=e,c;if(r)throw new t.JsonPatchError("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",0,n,e);return c}o||(e=a._deepClone(e));var f=(n.path||"").split("/"),d=e,h=1,v=f.length,m=void 0,g=void 0,y=void 0;for(y="function"==typeof r?r:p;;){if(g=f[h],r&&void 0===m&&(void 0===d[g]?m=f.slice(0,h).join("/"):h==v-1&&(m=n.path),void 0!==m&&y(n,0,e,m)),h++,Array.isArray(d)){if("-"===g)g=d.length;else{if(r&&!a.isInteger(g))throw new t.JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index","OPERATION_PATH_ILLEGAL_ARRAY_INDEX",0,n.path,n);a.isInteger(g)&&(g=~~g)}if(h>=v){if(r&&"add"===n.op&&g>d.length)throw new t.JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",0,n.path,n);if(!1===(c=s[n.op].call(n,d,g,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",0,n,e);return c}}else if(g&&-1!=g.indexOf("~")&&(g=a.unescapePathComponent(g)),h>=v){if(!1===(c=u[n.op].call(n,d,g,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",0,n,e);return c}d=d[g]}}function f(e,n,r,o){if(void 0===o&&(o=!0),r&&!Array.isArray(n))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");o||(e=a._deepClone(e));for(var i=new Array(n.length),u=0,s=n.length;u0)throw new t.JsonPatchError('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",n,e,r);if(("move"===e.op||"copy"===e.op)&&"string"!=typeof e.from)throw new t.JsonPatchError("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",n,e,r);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&void 0===e.value)throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",n,e,r);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&a.hasUndefined(e.value))throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",n,e,r);if(r)if("add"==e.op){var i=e.path.split("/").length,s=o.split("/").length;if(i!==s+1&&i!==s)throw new t.JsonPatchError("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",n,e,r)}else if("replace"===e.op||"remove"===e.op||"_get"===e.op){if(e.path!==o)throw new t.JsonPatchError("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",n,e,r)}else if("move"===e.op||"copy"===e.op){var l=d([{op:"_get",path:e.from,value:void 0}],r);if(l&&"OPERATION_PATH_UNRESOLVABLE"===l.name)throw new t.JsonPatchError("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",n,e,r)}}function d(e,n,r){try{if(!Array.isArray(e))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(n)f(a._deepClone(n),a._deepClone(e),r||!0);else{r=r||p;for(var o=0;o1&&void 0!==arguments[1]?arguments[1]:(0,a.List)();return function(e){return(e.authSelectors.definitionsToAuthorize()||(0,a.List)()).filter(function(e){return t.some(function(t){return t.get(e.keySeq().first())})})}},t.authorized=(0,i.createSelector)(s,function(e){return e.get("authorized")||(0,a.Map)()}),t.isAuthorized=function(e,t){return function(e){var n=e.authSelectors.authorized();return a.List.isList(t)?!!t.toJS().filter(function(e){return-1===(0,r.default)(e).map(function(e){return!!n.get(e)}).indexOf(!1)}).length:null}},t.getConfigs=(0,i.createSelector)(s,function(e){return e.get("configs")})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.execute=void 0;var r,o=n(25),i=(r=o)&&r.__esModule?r:{default:r};t.execute=function(e,t){var n=t.authSelectors,r=t.specSelectors;return function(t){var o=t.path,a=t.method,u=t.operation,s=t.extras,l={authorized:n.authorized()&&n.authorized().toJS(),definitions:r.securityDefinitions()&&r.securityDefinitions().toJS(),specSecurity:r.security()&&r.security().toJS()};return e((0,i.default)({path:o,method:a,operation:u,securities:l},s))}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{fn:{shallowEqualKeys:r.shallowEqualKeys}}};var r=n(12)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=s(n(40)),o=s(n(23));t.default=function(e){var t=e.fn,n={download:function(e){return function(n){var r=n.errActions,i=n.specSelectors,a=n.specActions,s=n.getConfigs,l=t.fetch,c=s();function f(t){if(t instanceof Error||t.status>=400)return a.updateLoadingStatus("failed"),r.newThrownErr((0,o.default)(new Error((t.message||t.statusText)+" "+e),{source:"fetch"})),void(!t.status&&t instanceof Error&&function(){try{var t=void 0;if("URL"in u.default?t=new URL(e):(t=document.createElement("a")).href=e,"https:"!==t.protocol&&"https:"===u.default.location.protocol){var n=(0,o.default)(new Error("Possible mixed-content issue? The page was loaded over https:// but a "+t.protocol+"// URL was specified. Check that you are not attempting to load mixed content."),{source:"fetch"});return void r.newThrownErr(n)}if(t.origin!==u.default.location.origin){var i=(0,o.default)(new Error("Possible cross-origin (CORS) issue? The URL origin ("+t.origin+") does not match the page ("+u.default.location.origin+"). Check the server returns the correct 'Access-Control-Allow-*' headers."),{source:"fetch"});r.newThrownErr(i)}}catch(e){return}}());a.updateLoadingStatus("success"),a.updateSpec(t.text),i.url()!==e&&a.updateUrl(e)}e=e||i.url(),a.updateLoadingStatus("loading"),r.clear({source:"fetch"}),l({url:e,loadSpec:!0,requestInterceptor:c.requestInterceptor||function(e){return e},responseInterceptor:c.responseInterceptor||function(e){return e},credentials:"same-origin",headers:{Accept:"application/json,*/*"}}).then(f,f)}},updateLoadingStatus:function(e){var t=[null,"loading","failed","success","failedConfig"];return-1===t.indexOf(e)&&console.error("Error: "+e+" is not one of "+(0,r.default)(t)),{type:"spec_update_loading_status",payload:e}}},s={loadingStatus:(0,i.createSelector)(function(e){return e||(0,a.Map)()},function(e){return e.get("loadingStatus")||null})};return{statePlugins:{spec:{actions:n,reducers:{spec_update_loading_status:function(e,t){return"string"==typeof t.payload?e.set("loadingStatus",t.payload):e}},selectors:s}}}};var i=n(58),a=n(7),u=s(n(33));function s(e){return e&&e.__esModule?e:{default:e}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{statePlugins:{spec:{actions:a,selectors:f},configs:{reducers:s.default,actions:i,selectors:u}}}};var r=c(n(936)),o=n(234),i=l(n(235)),a=l(n(401)),u=l(n(402)),s=c(n(403));function l(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}function c(e){return e&&e.__esModule?e:{default:e}}var f={getLocalConfig:function(){return(0,o.parseYamlConfig)(r.default)}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getConfigByUrl=t.downloadConfig=void 0;var r=n(234);t.downloadConfig=function(e){return function(t){return(0,t.fn.fetch)(e)}},t.getConfigByUrl=function(e,t){return function(n){var o=n.specActions;if(e)return o.downloadConfig(e).then(i,i);function i(n){n instanceof Error||n.status>=400?(o.updateLoadingStatus("failedConfig"),o.updateLoadingStatus("failedConfig"),o.updateUrl(""),console.error(n.statusText+" "+e.url),t(null)):t((0,r.parseYamlConfig)(n.text))}}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.get=function(e,t){return e.getIn(Array.isArray(t)?t:[t])}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,o,i=n(22),a=(r=i)&&r.__esModule?r:{default:r},u=n(7),s=n(235);t.default=(o={},(0,a.default)(o,s.UPDATE_CONFIGS,function(e,t){return e.merge((0,u.fromJS)(t.payload))}),(0,a.default)(o,s.TOGGLE_CONFIGS,function(e,t){var n=t.payload,r=e.get(n);return e.set(n,!r)}),o)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return[r.default,{statePlugins:{configs:{wrapActions:{loaded:function(e,t){return function(){e.apply(void 0,arguments);var n=window.location.hash;t.layoutActions.parseDeepLinkHash(n)}}}}},wrapComponents:{operation:o.default,OperationTag:i.default}}]};var r=a(n(405)),o=a(n(407)),i=a(n(408));function a(e){return e&&e.__esModule?e:{default:e}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.clearScrollTo=t.scrollToElement=t.readyToScroll=t.parseDeepLinkHash=t.scrollTo=t.show=void 0;var r,o=c(n(22)),i=c(n(18)),a=n(406),u=c(n(937)),s=n(7),l=c(s);function c(e){return e&&e.__esModule?e:{default:e}}var f=t.show=function(e,t){var n=t.getConfigs,r=t.layoutSelectors;return function(){for(var t=arguments.length,o=Array(t),u=0;u",Gt:"≫",gt:">",gtcc:"⪧",gtcir:"⩺",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",hArr:"⇔",harr:"↔",harrcir:"⥈",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",Hfr:"ℌ",hfr:"𝔥",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",Hopf:"ℍ",hopf:"𝕙",horbar:"―",HorizontalLine:"─",Hscr:"ℋ",hscr:"𝒽",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",Ifr:"ℑ",ifr:"𝔦",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Im:"ℑ",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",imof:"⊷",imped:"Ƶ",Implies:"⇒",in:"∈",incare:"℅",infin:"∞",infintie:"⧝",inodot:"ı",Int:"∬",int:"∫",intcal:"⊺",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",Iscr:"ℐ",iscr:"𝒾",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",Lang:"⟪",lang:"⟨",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",Larr:"↞",lArr:"⇐",larr:"←",larrb:"⇤",larrbfs:"⤟",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",lat:"⪫",lAtail:"⤛",latail:"⤙",late:"⪭",lates:"⪭︀",lBarr:"⤎",lbarr:"⤌",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",lE:"≦",le:"≤",LeftAngleBracket:"⟨",LeftArrow:"←",Leftarrow:"⇐",leftarrow:"←",LeftArrowBar:"⇤",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVector:"⇃",LeftDownVectorBar:"⥙",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrow:"↔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTee:"⊣",LeftTeeArrow:"↤",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangle:"⊲",LeftTriangleBar:"⧏",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVector:"↿",LeftUpVectorBar:"⥘",LeftVector:"↼",LeftVectorBar:"⥒",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",les:"⩽",lescc:"⪨",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",Ll:"⋘",ll:"≪",llarr:"⇇",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoust:"⎰",lmoustache:"⎰",lnap:"⪉",lnapprox:"⪉",lnE:"≨",lne:"⪇",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftarrow:"⟵",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longleftrightarrow:"⟷",longmapsto:"⟼",LongRightArrow:"⟶",Longrightarrow:"⟹",longrightarrow:"⟶",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",Lscr:"ℒ",lscr:"𝓁",Lsh:"↰",lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",LT:"<",Lt:"≪",lt:"<",ltcc:"⪦",ltcir:"⩹",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",mid:"∣",midast:"*",midcir:"⫰",middot:"·",minus:"−",minusb:"⊟",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",Mscr:"ℳ",mscr:"𝓂",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natur:"♮",natural:"♮",naturals:"ℕ",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",ne:"≠",nearhk:"⤤",neArr:"⇗",nearr:"↗",nearrow:"↗",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nhArr:"⇎",nharr:"↮",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlArr:"⇍",nlarr:"↚",nldr:"‥",nlE:"≦̸",nle:"≰",nLeftarrow:"⇍",nleftarrow:"↚",nLeftrightarrow:"⇎",nleftrightarrow:"↮",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",Nopf:"ℕ",nopf:"𝕟",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangle:"⋪",NotLeftTriangleBar:"⧏̸",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangle:"⋫",NotRightTriangleBar:"⧐̸",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",npar:"∦",nparallel:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",npre:"⪯̸",nprec:"⊀",npreceq:"⪯̸",nrArr:"⇏",nrarr:"↛",nrarrc:"⤳̸",nrarrw:"↝̸",nRightarrow:"⇏",nrightarrow:"↛",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nVDash:"⊯",nVdash:"⊮",nvDash:"⊭",nvdash:"⊬",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwArr:"⇖",nwarr:"↖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",ocir:"⊚",Ocirc:"Ô",ocirc:"ô",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",Or:"⩔",or:"∨",orarr:"↻",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",Otimes:"⨷",otimes:"⊗",otimesas:"⨶",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",par:"∥",para:"¶",parallel:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plus:"+",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",Popf:"ℙ",popf:"𝕡",pound:"£",Pr:"⪻",pr:"≺",prap:"⪷",prcue:"≼",prE:"⪳",pre:"⪯",prec:"≺",precapprox:"⪷",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",precsim:"≾",Prime:"″",prime:"′",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportion:"∷",Proportional:"∝",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",Qopf:"ℚ",qopf:"𝕢",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",QUOT:'"',quot:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",Rang:"⟫",rang:"⟩",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",Rarr:"↠",rArr:"⇒",rarr:"→",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",rAtail:"⤜",ratail:"⤚",ratio:"∶",rationals:"ℚ",RBarr:"⤐",rBarr:"⤏",rbarr:"⤍",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",Re:"ℜ",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",rect:"▭",REG:"®",reg:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",Rfr:"ℜ",rfr:"𝔯",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrow:"→",Rightarrow:"⇒",rightarrow:"→",RightArrowBar:"⇥",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVector:"⇂",RightDownVectorBar:"⥕",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTee:"⊢",RightTeeArrow:"↦",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangle:"⊳",RightTriangleBar:"⧐",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVector:"↾",RightUpVectorBar:"⥔",RightVector:"⇀",RightVectorBar:"⥓",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoust:"⎱",rmoustache:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",Ropf:"ℝ",ropf:"𝕣",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",Rscr:"ℛ",rscr:"𝓇",Rsh:"↱",rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",Sc:"⪼",sc:"≻",scap:"⪸",Scaron:"Š",scaron:"š",sccue:"≽",scE:"⪴",sce:"⪰",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdot:"⋅",sdotb:"⊡",sdote:"⩦",searhk:"⤥",seArr:"⇘",searr:"↘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",sol:"/",solb:"⧄",solbar:"⌿",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",squ:"□",Square:"□",square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",Sub:"⋐",sub:"⊂",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",Subset:"⋐",subset:"⊂",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succ:"≻",succapprox:"⪸",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",Sum:"∑",sum:"∑",sung:"♪",Sup:"⋑",sup:"⊃",sup1:"¹",sup2:"²",sup3:"³",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",Supset:"⋑",supset:"⊃",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swArr:"⇙",swarr:"↙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",Therefore:"∴",therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",thinsp:" ",ThinSpace:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",Tilde:"∼",tilde:"˜",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",times:"×",timesb:"⊠",timesbar:"⨱",timesd:"⨰",tint:"∭",toea:"⤨",top:"⊤",topbot:"⌶",topcir:"⫱",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",TRADE:"™",trade:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",Uarr:"↟",uArr:"⇑",uarr:"↑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrow:"↑",Uparrow:"⇑",uparrow:"↑",UpArrowBar:"⤒",UpArrowDownArrow:"⇅",UpDownArrow:"↕",Updownarrow:"⇕",updownarrow:"↕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",Upsi:"ϒ",upsi:"υ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTee:"⊥",UpTeeArrow:"↥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",vArr:"⇕",varr:"↕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",Vbar:"⫫",vBar:"⫨",vBarv:"⫩",Vcy:"В",vcy:"в",VDash:"⊫",Vdash:"⊩",vDash:"⊨",vdash:"⊢",Vdashl:"⫦",Vee:"⋁",vee:"∨",veebar:"⊻",veeeq:"≚",vellip:"⋮",Verbar:"‖",verbar:"|",Vert:"‖",vert:"|",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",Wedge:"⋀",wedge:"∧",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xhArr:"⟺",xharr:"⟷",Xi:"Ξ",xi:"ξ",xlArr:"⟸",xlarr:"⟵",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrArr:"⟹",xrarr:"⟶",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",Yuml:"Ÿ",yuml:"ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",Zfr:"ℨ",zfr:"𝔷",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",Zopf:"ℤ",zopf:"𝕫",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"}},function(e,t,n){"use strict";var r=n(419),o=n(27).unescapeMd;e.exports=function(e,t){var n,i,a,u=t,s=e.posMax;if(60===e.src.charCodeAt(t)){for(t++;t8&&n<14);)if(92===n&&t+11)break;if(41===n&&--i<0)break;t++}return u!==t&&(a=o(e.src.slice(u,t)),!!e.parser.validateLink(a)&&(e.linkContent=a,e.pos=t,!0))}},function(e,t,n){"use strict";var r=n(27).replaceEntities;e.exports=function(e){var t=r(e);try{t=decodeURI(t)}catch(e){}return encodeURI(t)}},function(e,t,n){"use strict";var r=n(27).unescapeMd;e.exports=function(e,t){var n,o=t,i=e.posMax,a=e.src.charCodeAt(t);if(34!==a&&39!==a&&40!==a)return!1;for(t++,40===a&&(a=41);t1?r-1:0),i=1;i1?t-1:0),r=1;r0?Array(e+1).join(" ")+t:t}).join("\n")}(0,(0,r.default)(a,null,2))||"{}",c.default.createElement("br",null)))}}]),t}(l.Component);t.default=p},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=c(n(4)),o=c(n(2)),i=c(n(3)),a=c(n(5)),u=c(n(6)),s=c(n(0)),l=n(7);c(n(1)),c(n(10));function c(e){return e&&e.__esModule?e:{default:e}}var f=function(e){function t(){var e,n,i,u;(0,o.default)(this,t);for(var s=arguments.length,l=Array(s),c=0;c=e.length?(this._t=void 0,o(1)):o(0,"keys"==t?n:"values"==t?e[n]:[n,e[n]])},"values"),i.Arguments=i.Array,r("keys"),r("values"),r("entries")},function(e,t){e.exports=function(){}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t,n){"use strict";var r=n(159),o=n(96),i=n(98),a={};n(50)(a,n(20)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=r(a,{next:o(1,n)}),i(e,t+" Iterator")}},function(e,t,n){var r=n(39),o=n(35),i=n(97);e.exports=n(44)?Object.defineProperties:function(e,t){o(e);for(var n,a=i(t),u=a.length,s=0;u>s;)r.f(e,n=a[s++],t[n]);return e}},function(e,t,n){var r=n(70),o=n(115),i=n(455);e.exports=function(e){return function(t,n,a){var u,s=r(t),l=o(s.length),c=i(a,l);if(e&&n!=n){for(;l>c;)if((u=s[c++])!=u)return!0}else for(;l>c;c++)if((e||c in s)&&s[c]===n)return e||c||0;return!e&&-1}}},function(e,t,n){var r=n(160),o=Math.max,i=Math.min;e.exports=function(e,t){return(e=r(e))<0?o(e+t,0):i(e,t)}},function(e,t,n){var r=n(160),o=n(155);e.exports=function(e){return function(t,n){var i,a,u=String(o(t)),s=r(n),l=u.length;return s<0||s>=l?e?"":void 0:(i=u.charCodeAt(s))<55296||i>56319||s+1===l||(a=u.charCodeAt(s+1))<56320||a>57343?e?u.charAt(s):i:e?u.slice(s,s+2):a-56320+(i-55296<<10)+65536}}},function(e,t,n){var r=n(35),o=n(164);e.exports=n(14).getIterator=function(e){var t=o(e);if("function"!=typeof t)throw TypeError(e+" is not iterable!");return r(t.call(e))}},function(e,t,n){n(459),n(245),n(470),n(474),n(486),n(487),e.exports=n(53).Promise},function(e,t,n){"use strict";var r=n(166),o={};o[n(17)("toStringTag")]="z",o+""!="[object z]"&&n(72)(Object.prototype,"toString",function(){return"[object "+r(this)+"]"},!0)},function(e,t,n){e.exports=!n(101)&&!n(102)(function(){return 7!=Object.defineProperty(n(169)("div"),"a",{get:function(){return 7}}).a})},function(e,t,n){var r=n(73);e.exports=function(e,t){if(!r(e))return e;var n,o;if(t&&"function"==typeof(n=e.toString)&&!r(o=n.call(e)))return o;if("function"==typeof(n=e.valueOf)&&!r(o=n.call(e)))return o;if(!t&&"function"==typeof(n=e.toString)&&!r(o=n.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},function(e,t,n){"use strict";var r=n(463),o=n(244),i=n(171),a={};n(59)(a,n(17)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=r(a,{next:o(1,n)}),i(e,t+" Iterator")}},function(e,t,n){var r=n(60),o=n(464),i=n(250),a=n(170)("IE_PROTO"),u=function(){},s=function(){var e,t=n(169)("iframe"),r=i.length;for(t.style.display="none",n(251).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write(""); + options.HeadContent = builder.ToString(); + } + + /// + /// Adds Swagger JSON endpoints. Can be fully-qualified or relative to the UI page + /// + /// + /// Can be fully qualified or relative to the current host + /// The description that appears in the document selector drop-down + public static void SwaggerEndpoint(this SwaggerUIOptions options, string url, string name) + { + var urls = new List(options.ConfigObject.Urls ?? Enumerable.Empty()); + urls.Add(new UrlDescriptor { Url = url, Name = name} ); + options.ConfigObject.Urls = urls; + } + + public static void SwaggerEndpoint(this SwaggerUIOptions options, string url, string name, string areaName) + { + var urls = new List(options.ConfigObject.Urls ?? Enumerable.Empty()); + urls.Add(new UrlDescriptor { Url = string.IsNullOrEmpty(areaName) ? url : $"{areaName}{url}", Name = name }); + options.ConfigObject.Urls = urls; + } + + public static void SwaggerEndpoint(this SwaggerUIOptions options, IEnumerable entries, string areaName) + { + + var list = new List(); + var assemblies = entries.Select(p => p.Type.Assembly).Distinct(); + foreach (var assembly in assemblies) + { + var version = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + var title = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + var des = assembly + .GetCustomAttributes(true) + .OfType().FirstOrDefault(); + + if (version == null || title == null) + continue; + + var info = new Info() + { + Title = title.Title, + Version = version.Version, + Description = des?.Description, + + }; + options.SwaggerEndpoint($"../swagger/{info.Title}/swagger.json", info.Title, areaName); + } + } + + /// + /// Enables deep linking for tags and operations + /// + /// + public static void EnableDeepLinking(this SwaggerUIOptions options) + { + options.ConfigObject.DeepLinking = true; + } + /// + /// Enables persist authorization data + /// + /// + public static void EnablePersistAuthorization(this SwaggerUIOptions options) + { + options.ConfigObject.PersistAuthorization = true; + } + + /// + /// Controls the display of operationId in operations list + /// + /// + public static void DisplayOperationId(this SwaggerUIOptions options) + { + options.ConfigObject.DisplayOperationId = true; + } + + /// + /// The default expansion depth for models (set to -1 completely hide the models) + /// + /// + /// + public static void DefaultModelsExpandDepth(this SwaggerUIOptions options, int depth) + { + options.ConfigObject.DefaultModelsExpandDepth = depth; + } + + /// + /// The default expansion depth for the model on the model-example section + /// + /// + /// + public static void DefaultModelExpandDepth(this SwaggerUIOptions options, int depth) + { + options.ConfigObject.DefaultModelExpandDepth = depth; + } + + /// + /// Controls how the model is shown when the API is first rendered. + /// (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) + /// + /// + /// + public static void DefaultModelRendering(this SwaggerUIOptions options, ModelRendering modelRendering) + { + options.ConfigObject.DefaultModelRendering = modelRendering; + } + + /// + /// Controls the display of the request duration (in milliseconds) for Try-It-Out requests + /// + /// + public static void DisplayRequestDuration(this SwaggerUIOptions options) + { + options.ConfigObject.DisplayRequestDuration = true; + } + + /// + /// Controls the default expansion setting for the operations and tags. + /// It can be 'List' (expands only the tags), 'Full' (expands the tags and operations) or 'None' (expands nothing) + /// + /// + /// + public static void DocExpansion(this SwaggerUIOptions options, DocExpansion docExpansion) + { + options.ConfigObject.DocExpansion = docExpansion; + } + + /// + /// Enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. + /// If an expression is provided it will be used and applied initially. + /// Filtering is case sensitive matching the filter expression anywhere inside the tag + /// + /// + /// + public static void EnableFilter(this SwaggerUIOptions options, string expression = null) + { + options.ConfigObject.Filter = expression ?? ""; + } + + /// + /// Enables the "Try it out" section by default. + /// + /// + public static void EnableTryItOutByDefault(this SwaggerUIOptions options) + { + options.ConfigObject.TryItOutEnabled = true; + } + + /// + /// Limits the number of tagged operations displayed to at most this many. The default is to show all operations + /// + /// + /// + public static void MaxDisplayedTags(this SwaggerUIOptions options, int count) + { + options.ConfigObject.MaxDisplayedTags = count; + } + + /// + /// Controls the display of vendor extension (x-) fields and values for Operations, Parameters, and Schema + /// + /// + public static void ShowExtensions(this SwaggerUIOptions options) + { + options.ConfigObject.ShowExtensions = true; + } + + /// + /// Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields and values for Parameters + /// + /// + public static void ShowCommonExtensions(this SwaggerUIOptions options) + { + options.ConfigObject.ShowCommonExtensions = true; + } + + /// + /// List of HTTP methods that have the Try it out feature enabled. An empty array disables Try it out for all operations. + /// This does not filter the operations from the display + /// + /// + /// + public static void SupportedSubmitMethods(this SwaggerUIOptions options, params SubmitMethod[] submitMethods) + { + options.ConfigObject.SupportedSubmitMethods = submitMethods; + } + + /// + /// OAuth redirect URL + /// + /// + /// + public static void OAuth2RedirectUrl(this SwaggerUIOptions options, string url) + { + options.ConfigObject.OAuth2RedirectUrl = url; + } + + [Obsolete("The validator is disabled by default. Use EnableValidator to enable it")] + public static void ValidatorUrl(this SwaggerUIOptions options, string url) + { + options.ConfigObject.ValidatorUrl = url; + } + + /// + /// You can use this parameter to enable the swagger-ui's built-in validator (badge) functionality + /// Setting it to null will disable validation + /// + /// + /// + public static void EnableValidator(this SwaggerUIOptions options, string url = "https://online.swagger.io/validator") + { + options.ConfigObject.ValidatorUrl = url; + } + + /// + /// Default clientId + /// + /// + /// + public static void OAuthClientId(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.ClientId = value; + } + + /// + /// Default clientSecret + /// + /// + /// + public static void OAuthClientSecret(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.ClientSecret = value; + } + + /// + /// realm query parameter (for oauth1) added to authorizationUrl and tokenUrl + /// + /// + /// + public static void OAuthRealm(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.Realm = value; + } + + /// + /// Application name, displayed in authorization popup + /// + /// + /// + public static void OAuthAppName(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.AppName = value; + } + + /// + /// Scope separator for passing scopes, encoded before calling, default value is a space (encoded value %20) + /// + /// + /// + public static void OAuthScopeSeparator(this SwaggerUIOptions options, string value) + { + options.OAuthConfigObject.ScopeSeparator = value; + } + + /// + /// String array of initially selected oauth scopes, default is empty array + /// + public static void OAuthScopes(this SwaggerUIOptions options, params string[] scopes) + { + options.OAuthConfigObject.Scopes = scopes; + } + + /// + /// Additional query parameters added to authorizationUrl and tokenUrl + /// + /// + /// + public static void OAuthAdditionalQueryStringParams( + this SwaggerUIOptions options, + Dictionary value) + { + options.OAuthConfigObject.AdditionalQueryStringParams = value; + } + + /// + /// Only activated for the accessCode flow. During the authorization_code request to the tokenUrl, + /// pass the Client Password using the HTTP Basic Authentication scheme (Authorization header with + /// Basic base64encoded[client_id:client_secret]). The default is false + /// + /// + public static void OAuthUseBasicAuthenticationWithAccessCodeGrant(this SwaggerUIOptions options) + { + options.OAuthConfigObject.UseBasicAuthenticationWithAccessCodeGrant = true; + } + + /// + /// Only applies to authorizatonCode flows. Proof Key for Code Exchange brings enhanced security for OAuth public clients. + /// The default is false + /// + /// + public static void OAuthUsePkce(this SwaggerUIOptions options) + { + options.OAuthConfigObject.UsePkceWithAuthorizationCodeGrant = true; + } + + /// + /// Function to intercept remote definition, "Try it out", and OAuth 2.0 requests. + /// + /// + /// MUST be a valid Javascript function: (request: SwaggerRequest) => SwaggerRequest + public static void UseRequestInterceptor(this SwaggerUIOptions options, string value) + { + options.Interceptors.RequestInterceptorFunction = value; + } + + /// + /// Function to intercept remote definition, "Try it out", and OAuth 2.0 responses. + /// + /// + /// MUST be a valid Javascript function: (response: SwaggerResponse ) => SwaggerResponse + public static void UseResponseInterceptor(this SwaggerUIOptions options, string value) + { + options.Interceptors.ResponseInterceptorFunction = value; + } + } +} diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/index.html b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/index.html new file mode 100644 index 000000000..c5360b285 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/index.html @@ -0,0 +1,117 @@ + + + + + + %(DocumentTitle) + + + + + %(HeadContent) + + + +
+ + + + + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/LICENSE b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/NOTICE b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/NOTICE new file mode 100644 index 000000000..ab788a27d --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/NOTICE @@ -0,0 +1,2 @@ +swagger-ui +Copyright 2020-2021 SmartBear Software Inc. diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/README.md b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/README.md new file mode 100644 index 000000000..662842270 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/README.md @@ -0,0 +1,22 @@ +# Swagger UI Dist +[![NPM version](https://badge.fury.io/js/swagger-ui-dist.svg)](http://badge.fury.io/js/swagger-ui-dist) + +# API + +This module, `swagger-ui-dist`, exposes Swagger-UI's entire dist folder as a dependency-free npm module. +Use `swagger-ui` instead, if you'd like to have npm install dependencies for you. + +`SwaggerUIBundle` and `SwaggerUIStandalonePreset` can be imported: +```javascript + import { SwaggerUIBundle, SwaggerUIStandalonePreset } from "swagger-ui-dist" +``` + +To get an absolute path to this directory for static file serving, use the exported `getAbsoluteFSPath` method: + +```javascript +const swaggerUiAssetPath = require("swagger-ui-dist").getAbsoluteFSPath() + +// then instantiate server that serves files from the swaggerUiAssetPath +``` + +For anything else, check the [Swagger-UI](https://github.com/swagger-api/swagger-ui) repository. diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/absolute-path.js b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/absolute-path.js new file mode 100644 index 000000000..af42bc8f1 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/absolute-path.js @@ -0,0 +1,14 @@ +/* + * getAbsoluteFSPath + * @return {string} When run in NodeJS env, returns the absolute path to the current directory + * When run outside of NodeJS, will return an error message + */ +const getAbsoluteFSPath = function () { + // detect whether we are running in a browser or nodejs + if (typeof module !== "undefined" && module.exports) { + return require("path").resolve(__dirname) + } + throw new Error('getAbsoluteFSPath can only be called within a Nodejs environment'); +} + +module.exports = getAbsoluteFSPath diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/favicon-16x16.png b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/favicon-16x16.png new file mode 100644 index 000000000..8b194e617 Binary files /dev/null and b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/favicon-16x16.png differ diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/favicon-32x32.png b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/favicon-32x32.png new file mode 100644 index 000000000..249737fe4 Binary files /dev/null and b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/favicon-32x32.png differ diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/index.html b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/index.html new file mode 100644 index 000000000..2a9d4e272 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/index.html @@ -0,0 +1,60 @@ + + + + + + Swagger UI + + + + + + + +
+ + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/index.js b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/index.js new file mode 100644 index 000000000..c229ec43e --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/index.js @@ -0,0 +1,17 @@ +try { + module.exports.SwaggerUIBundle = require("./swagger-ui-bundle.js") + module.exports.SwaggerUIStandalonePreset = require("./swagger-ui-standalone-preset.js") +} catch(e) { + // swallow the error if there's a problem loading the assets. + // allows this module to support providing the assets for browserish contexts, + // without exploding in a Node context. + // + // see https://github.com/swagger-api/swagger-ui/issues/3291#issuecomment-311195388 + // for more information. +} + +// `absolutePath` and `getAbsoluteFSPath` are both here because at one point, +// we documented having one and actually implemented the other. +// They were both retained so we don't break anyone's code. +module.exports.absolutePath = require("./absolute-path.js") +module.exports.getAbsoluteFSPath = require("./absolute-path.js") diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/oauth2-redirect.html b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/oauth2-redirect.html new file mode 100644 index 000000000..64b171f7d --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/oauth2-redirect.html @@ -0,0 +1,75 @@ + + + + Swagger UI: OAuth2 Redirect + + + + + diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/package.json b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/package.json new file mode 100644 index 000000000..5850ba598 --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/package.json @@ -0,0 +1,18 @@ +{ + "name": "swagger-ui-dist", + "version": "4.1.3", + "main": "index.js", + "repository": "git@github.com:swagger-api/swagger-ui.git", + "contributors": [ + "(in alphabetical order)", + "Anna Bodnia ", + "Buu Nguyen ", + "Josh Ponelat ", + "Kyle Shockey ", + "Robert Barnwell ", + "Sahar Jafari " + ], + "license": "Apache-2.0", + "dependencies": {}, + "devDependencies": {} +} diff --git a/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/swagger-ui-bundle.js b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/swagger-ui-bundle.js new file mode 100644 index 000000000..2cbe107db --- /dev/null +++ b/src/Surging.Core/Surging.Core.Swagger_V5/SwaggerUI/node_modules/swagger-ui-dist/swagger-ui-bundle.js @@ -0,0 +1,3 @@ +/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=481)}([function(e,t,n){"use strict";e.exports=n(555)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return i(e)?e:J(e)}function r(e){return u(e)?e:K(e)}function o(e){return s(e)?e:Y(e)}function a(e){return i(e)&&!c(e)?e:G(e)}function i(e){return!(!e||!e[f])}function u(e){return!(!e||!e[p])}function s(e){return!(!e||!e[h])}function c(e){return u(e)||s(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(a,n),n.isIterable=i,n.isKeyed=u,n.isIndexed=s,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=a;var f="@@__IMMUTABLE_ITERABLE__@@",p="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m="delete",v=5,g=1<>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?A(e)+t:t}function C(){return!0}function j(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return N(e,t,0)}function I(e,t){return N(e,t,t)}function N(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var P=0,M=1,R=2,D="function"==typeof Symbol&&Symbol.iterator,L="@@iterator",B=D||L;function F(e){this.next=e}function z(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function q(){return{value:void 0,done:!0}}function U(e){return!!H(e)}function V(e){return e&&"function"==typeof e.next}function W(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(D&&e[D]||e[L]);if("function"==typeof t)return t}function $(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():i(e)?e.toSeq():ce(e)}function K(e){return null==e?ie().toKeyedSeq():i(e)?u(e)?e.toSeq():e.fromEntrySeq():ue(e)}function Y(e){return null==e?ie():i(e)?u(e)?e.entrySeq():e.toIndexedSeq():se(e)}function G(e){return(null==e?ie():i(e)?u(e)?e.entrySeq():e:se(e)).toSetSeq()}F.prototype.toString=function(){return"[Iterator]"},F.KEYS=P,F.VALUES=M,F.ENTRIES=R,F.prototype.inspect=F.prototype.toSource=function(){return this.toString()},F.prototype[B]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return fe(this,e,t,!0)},J.prototype.__iterator=function(e,t){return pe(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return fe(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return pe(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=ae,J.Keyed=K,J.Set=G,J.Indexed=Y;var Q,Z,X,ee="@@__IMMUTABLE_SEQ__@@";function te(e){this._array=e,this.size=e.length}function ne(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function re(e){this._iterable=e,this.size=e.length||e.size}function oe(e){this._iterator=e,this._iteratorCache=[]}function ae(e){return!(!e||!e[ee])}function ie(){return Q||(Q=new te([]))}function ue(e){var t=Array.isArray(e)?new te(e).fromEntrySeq():V(e)?new oe(e).fromEntrySeq():U(e)?new re(e).fromEntrySeq():"object"==typeof e?new ne(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function se(e){var t=le(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function ce(e){var t=le(e)||"object"==typeof e&&new ne(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}function le(e){return $(e)?new te(e):V(e)?new oe(e):U(e)?new re(e):void 0}function fe(e,t,n,r){var o=e._cache;if(o){for(var a=o.length-1,i=0;i<=a;i++){var u=o[n?a-i:i];if(!1===t(u[1],r?u[0]:i,e))return i+1}return i}return e.__iterateUncached(t,n)}function pe(e,t,n,r){var o=e._cache;if(o){var a=o.length-1,i=0;return new F((function(){var e=o[n?a-i:i];return i++>a?q():z(t,r?e[0]:i-1,e[1])}))}return e.__iteratorUncached(t,n)}function he(e,t){return t?de(t,e,"",{"":e}):me(e)}function de(e,t,n,r){return Array.isArray(t)?e.call(r,n,Y(t).map((function(n,r){return de(e,n,r,t)}))):ve(t)?e.call(r,n,K(t).map((function(n,r){return de(e,n,r,t)}))):t}function me(e){return Array.isArray(e)?Y(e).map(me).toList():ve(e)?K(e).map(me).toMap():e}function ve(e){return e&&(e.constructor===Object||void 0===e.constructor)}function ge(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function ye(e,t){if(e===t)return!0;if(!i(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||u(e)!==u(t)||s(e)!==s(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!c(e);if(l(e)){var r=e.entries();return t.every((function(e,t){var o=r.next().value;return o&&ge(o[1],e)&&(n||ge(o[0],t))}))&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var a=e;e=t,t=a}var f=!0,p=t.__iterate((function(t,r){if(n?!e.has(t):o?!ge(t,e.get(r,b)):!ge(e.get(r,b),t))return f=!1,!1}));return f&&e.size===p}function be(e,t){if(!(this instanceof be))return new be(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(Z)return Z;Z=this}}function we(e,t){if(!e)throw new Error(t)}function xe(e,t,n){if(!(this instanceof xe))return new xe(e,t,n);if(we(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?q():z(e,o,n[t?r-o++:o++])}))},t(ne,K),ne.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},ne.prototype.has=function(e){return this._object.hasOwnProperty(e)},ne.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,a=0;a<=o;a++){var i=r[t?o-a:a];if(!1===e(n[i],i,this))return a+1}return a},ne.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,a=0;return new F((function(){var i=r[t?o-a:a];return a++>o?q():z(e,i,n[i])}))},ne.prototype[d]=!0,t(re,Y),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=W(this._iterable),r=0;if(V(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},re.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=W(this._iterable);if(!V(n))return new F(q);var r=0;return new F((function(){var t=n.next();return t.done?t:z(e,r++,t.value)}))},t(oe,Y),oe.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,a=0;a=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return z(e,o,r[o++])}))},t(be,Y),be.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},be.prototype.get=function(e,t){return this.has(e)?this._value:t},be.prototype.includes=function(e){return ge(this._value,e)},be.prototype.slice=function(e,t){var n=this.size;return j(e,t,n)?this:new be(this._value,I(t,n)-T(e,n))},be.prototype.reverse=function(){return this},be.prototype.indexOf=function(e){return ge(this._value,e)?0:-1},be.prototype.lastIndexOf=function(e){return ge(this._value,e)?this.size:-1},be.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?q():z(e,a++,i)}))},xe.prototype.equals=function(e){return e instanceof xe?this._start===e._start&&this._end===e._end&&this._step===e._step:ye(this,e)},t(_e,n),t(Ee,_e),t(Se,_e),t(ke,_e),_e.Keyed=Ee,_e.Indexed=Se,_e.Set=ke;var Ae="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function Oe(e){return e>>>1&1073741824|3221225471&e}function Ce(e){if(!1===e||null==e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null==e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return Oe(n)}if("string"===t)return e.length>Fe?je(e):Te(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return Ie(e);if("function"==typeof e.toString)return Te(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function je(e){var t=Ue[e];return void 0===t&&(t=Te(e),qe===ze&&(qe=0,Ue={}),qe++,Ue[e]=t),t}function Te(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}var Re,De="function"==typeof WeakMap;De&&(Re=new WeakMap);var Le=0,Be="__immutablehash__";"function"==typeof Symbol&&(Be=Symbol(Be));var Fe=16,ze=255,qe=0,Ue={};function Ve(e){we(e!==1/0,"Cannot perform this action with an infinite size.")}function We(e){return null==e?ot():He(e)&&!l(e)?e:ot().withMutations((function(t){var n=r(e);Ve(n.size),n.forEach((function(e,n){return t.set(n,e)}))}))}function He(e){return!(!e||!e[Je])}t(We,Ee),We.of=function(){var t=e.call(arguments,0);return ot().withMutations((function(e){for(var n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}}))},We.prototype.toString=function(){return this.__toString("Map {","}")},We.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},We.prototype.set=function(e,t){return at(this,e,t)},We.prototype.setIn=function(e,t){return this.updateIn(e,b,(function(){return t}))},We.prototype.remove=function(e){return at(this,e,b)},We.prototype.deleteIn=function(e){return this.updateIn(e,(function(){return b}))},We.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},We.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=vt(this,_n(e),t,n);return r===b?void 0:r},We.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):ot()},We.prototype.merge=function(){return pt(this,void 0,arguments)},We.prototype.mergeWith=function(t){return pt(this,t,e.call(arguments,1))},We.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,ot(),(function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]}))},We.prototype.mergeDeep=function(){return pt(this,ht,arguments)},We.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return pt(this,dt(t),n)},We.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,ot(),(function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]}))},We.prototype.sort=function(e){return Ut(fn(this,e))},We.prototype.sortBy=function(e,t){return Ut(fn(this,t,e))},We.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},We.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new S)},We.prototype.asImmutable=function(){return this.__ensureOwner()},We.prototype.wasAltered=function(){return this.__altered},We.prototype.__iterator=function(e,t){return new et(this,e,t)},We.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate((function(t){return r++,e(t[1],t[0],n)}),t),r},We.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?rt(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},We.isMap=He;var $e,Je="@@__IMMUTABLE_MAP__@@",Ke=We.prototype;function Ye(e,t){this.ownerID=e,this.entries=t}function Ge(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function Qe(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Ze(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Xe(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function et(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&nt(e._root)}function tt(e,t){return z(e,t[0],t[1])}function nt(e,t){return{node:e,index:0,__prev:t}}function rt(e,t,n,r){var o=Object.create(Ke);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function ot(){return $e||($e=rt(0))}function at(e,t,n){var r,o;if(e._root){var a=_(w),i=_(x);if(r=it(e._root,e.__ownerID,0,void 0,t,n,a,i),!i.value)return e;o=e.size+(a.value?n===b?-1:1:0)}else{if(n===b)return e;o=1,r=new Ye(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?rt(o,r):ot()}function it(e,t,n,r,o,a,i,u){return e?e.update(t,n,r,o,a,i,u):a===b?e:(E(u),E(i),new Xe(t,r,[o,a]))}function ut(e){return e.constructor===Xe||e.constructor===Ze}function st(e,t,n,r,o){if(e.keyHash===r)return new Ze(t,r,[e.entry,o]);var a,i=(0===n?e.keyHash:e.keyHash>>>n)&y,u=(0===n?r:r>>>n)&y;return new Ge(t,1<>>=1)i[u]=1&n?t[a++]:void 0;return i[r]=o,new Qe(e,a+1,i)}function pt(e,t,n){for(var o=[],a=0;a>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function yt(e,t,n,r){var o=r?e:k(e);return o[t]=n,o}function bt(e,t,n,r){var o=e.length+1;if(r&&t+1===o)return e[t]=n,e;for(var a=new Array(o),i=0,u=0;u=xt)return ct(e,s,r,o);var p=e&&e===this.ownerID,h=p?s:k(s);return f?u?c===l-1?h.pop():h[c]=h.pop():h[c]=[r,o]:h.push([r,o]),p?(this.entries=h,this):new Ye(e,h)}},Ge.prototype.get=function(e,t,n,r){void 0===t&&(t=Ce(n));var o=1<<((0===e?t:t>>>e)&y),a=this.bitmap;return 0==(a&o)?r:this.nodes[gt(a&o-1)].get(e+v,t,n,r)},Ge.prototype.update=function(e,t,n,r,o,a,i){void 0===n&&(n=Ce(r));var u=(0===t?n:n>>>t)&y,s=1<=_t)return ft(e,p,c,u,d);if(l&&!d&&2===p.length&&ut(p[1^f]))return p[1^f];if(l&&d&&1===p.length&&ut(d))return d;var m=e&&e===this.ownerID,g=l?d?c:c^s:c|s,w=l?d?yt(p,f,d,m):wt(p,f,m):bt(p,f,d,m);return m?(this.bitmap=g,this.nodes=w,this):new Ge(e,g,w)},Qe.prototype.get=function(e,t,n,r){void 0===t&&(t=Ce(n));var o=(0===e?t:t>>>e)&y,a=this.nodes[o];return a?a.get(e+v,t,n,r):r},Qe.prototype.update=function(e,t,n,r,o,a,i){void 0===n&&(n=Ce(r));var u=(0===t?n:n>>>t)&y,s=o===b,c=this.nodes,l=c[u];if(s&&!l)return this;var f=it(l,e,t+v,n,r,o,a,i);if(f===l)return this;var p=this.count;if(l){if(!f&&--p0&&r=0&&e>>t&y;if(r>=this.array.length)return new Ct([],e);var o,a=0===r;if(t>0){var i=this.array[r];if((o=i&&i.removeBefore(e,t-v,n))===i&&a)return this}if(a&&!o)return this;var u=Lt(this,e);if(!a)for(var s=0;s>>t&y;if(o>=this.array.length)return this;if(t>0){var a=this.array[o];if((r=a&&a.removeAfter(e,t-v,n))===a&&o===this.array.length-1)return this}var i=Lt(this,e);return i.array.splice(o+1),r&&(i.array[o]=r),i};var jt,Tt,It={};function Nt(e,t){var n=e._origin,r=e._capacity,o=qt(r),a=e._tail;return i(e._root,e._level,0);function i(e,t,n){return 0===t?u(e,n):s(e,t,n)}function u(e,i){var u=i===o?a&&a.array:e&&e.array,s=i>n?0:n-i,c=r-i;return c>g&&(c=g),function(){if(s===c)return It;var e=t?--c:s++;return u&&u[e]}}function s(e,o,a){var u,s=e&&e.array,c=a>n?0:n-a>>o,l=1+(r-a>>o);return l>g&&(l=g),function(){for(;;){if(u){var e=u();if(e!==It)return e;u=null}if(c===l)return It;var n=t?--l:c++;u=i(s&&s[n],o-v,a+(n<=e.size||t<0)return e.withMutations((function(e){t<0?Ft(e,t).set(0,n):Ft(e,0,t+1).set(t,n)}));t+=e._origin;var r=e._tail,o=e._root,a=_(x);return t>=qt(e._capacity)?r=Dt(r,e.__ownerID,0,t,n,a):o=Dt(o,e.__ownerID,e._level,t,n,a),a.value?e.__ownerID?(e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e):Pt(e._origin,e._capacity,e._level,o,r):e}function Dt(e,t,n,r,o,a){var i,u=r>>>n&y,s=e&&u0){var c=e&&e.array[u],l=Dt(c,t,n-v,r,o,a);return l===c?e:((i=Lt(e,t)).array[u]=l,i)}return s&&e.array[u]===o?e:(E(a),i=Lt(e,t),void 0===o&&u===i.array.length-1?i.array.pop():i.array[u]=o,i)}function Lt(e,t){return t&&e&&t===e.ownerID?e:new Ct(e?e.array.slice():[],t)}function Bt(e,t){if(t>=qt(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&y],r-=v;return n}}function Ft(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new S,o=e._origin,a=e._capacity,i=o+t,u=void 0===n?a:n<0?a+n:o+n;if(i===o&&u===a)return e;if(i>=u)return e.clear();for(var s=e._level,c=e._root,l=0;i+l<0;)c=new Ct(c&&c.array.length?[void 0,c]:[],r),l+=1<<(s+=v);l&&(i+=l,o+=l,u+=l,a+=l);for(var f=qt(a),p=qt(u);p>=1<f?new Ct([],r):h;if(h&&p>f&&iv;g-=v){var b=f>>>g&y;m=m.array[b]=Lt(m.array[b],r)}m.array[f>>>v&y]=h}if(u=p)i-=p,u-=p,s=v,c=null,d=d&&d.removeBefore(r,0,i);else if(i>o||p>>s&y;if(w!==p>>>s&y)break;w&&(l+=(1<o&&(c=c.removeBefore(r,s,i-l)),c&&pa&&(a=c.size),i(s)||(c=c.map((function(e){return he(e)}))),r.push(c)}return a>e.size&&(e=e.setSize(a)),mt(e,t,r)}function qt(e){return e>>v<=g&&i.size>=2*a.size?(r=(o=i.filter((function(e,t){return void 0!==e&&u!==t}))).toKeyedSeq().map((function(e){return e[0]})).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=a.remove(t),o=u===i.size-1?i.pop():i.set(u,void 0))}else if(s){if(n===i.get(u)[1])return e;r=a,o=i.set(u,[t,n])}else r=a.set(t,i.size),o=i.set(i.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Wt(r,o)}function Jt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Kt(e){this._iter=e,this.size=e.size}function Yt(e){this._iter=e,this.size=e.size}function Gt(e){this._iter=e,this.size=e.size}function Qt(e){var t=bn(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=wn,t.__iterateUncached=function(t,n){var r=this;return e.__iterate((function(e,n){return!1!==t(n,e,r)}),n)},t.__iteratorUncached=function(t,n){if(t===R){var r=e.__iterator(t,n);return new F((function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e}))}return e.__iterator(t===M?P:M,n)},t}function Zt(e,t,n){var r=bn(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var a=e.get(r,b);return a===b?o:t.call(n,a,r,e)},r.__iterateUncached=function(r,o){var a=this;return e.__iterate((function(e,o,i){return!1!==r(t.call(n,e,o,i),o,a)}),o)},r.__iteratorUncached=function(r,o){var a=e.__iterator(R,o);return new F((function(){var o=a.next();if(o.done)return o;var i=o.value,u=i[0];return z(r,u,t.call(n,i[1],u,e),o)}))},r}function Xt(e,t){var n=bn(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Qt(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=wn,n.__iterate=function(t,n){var r=this;return e.__iterate((function(e,n){return t(e,n,r)}),!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function en(e,t,n,r){var o=bn(e);return r&&(o.has=function(r){var o=e.get(r,b);return o!==b&&!!t.call(n,o,r,e)},o.get=function(r,o){var a=e.get(r,b);return a!==b&&t.call(n,a,r,e)?a:o}),o.__iterateUncached=function(o,a){var i=this,u=0;return e.__iterate((function(e,a,s){if(t.call(n,e,a,s))return u++,o(e,r?a:u-1,i)}),a),u},o.__iteratorUncached=function(o,a){var i=e.__iterator(R,a),u=0;return new F((function(){for(;;){var a=i.next();if(a.done)return a;var s=a.value,c=s[0],l=s[1];if(t.call(n,l,c,e))return z(o,r?c:u++,l,a)}}))},o}function tn(e,t,n){var r=We().asMutable();return e.__iterate((function(o,a){r.update(t.call(n,o,a,e),0,(function(e){return e+1}))})),r.asImmutable()}function nn(e,t,n){var r=u(e),o=(l(e)?Ut():We()).asMutable();e.__iterate((function(a,i){o.update(t.call(n,a,i,e),(function(e){return(e=e||[]).push(r?[i,a]:a),e}))}));var a=yn(e);return o.map((function(t){return mn(e,a(t))}))}function rn(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),j(t,n,o))return e;var a=T(t,o),i=I(n,o);if(a!=a||i!=i)return rn(e.toSeq().cacheResult(),t,n,r);var u,s=i-a;s==s&&(u=s<0?0:s);var c=bn(e);return c.size=0===u?u:e.size&&u||void 0,!r&&ae(e)&&u>=0&&(c.get=function(t,n){return(t=O(this,t))>=0&&tu)return q();var e=o.next();return r||t===M?e:z(t,s-1,t===P?void 0:e.value[1],e)}))},c}function on(e,t,n){var r=bn(e);return r.__iterateUncached=function(r,o){var a=this;if(o)return this.cacheResult().__iterate(r,o);var i=0;return e.__iterate((function(e,o,u){return t.call(n,e,o,u)&&++i&&r(e,o,a)})),i},r.__iteratorUncached=function(r,o){var a=this;if(o)return this.cacheResult().__iterator(r,o);var i=e.__iterator(R,o),u=!0;return new F((function(){if(!u)return q();var e=i.next();if(e.done)return e;var o=e.value,s=o[0],c=o[1];return t.call(n,c,s,a)?r===R?e:z(r,s,c,e):(u=!1,q())}))},r}function an(e,t,n,r){var o=bn(e);return o.__iterateUncached=function(o,a){var i=this;if(a)return this.cacheResult().__iterate(o,a);var u=!0,s=0;return e.__iterate((function(e,a,c){if(!u||!(u=t.call(n,e,a,c)))return s++,o(e,r?a:s-1,i)})),s},o.__iteratorUncached=function(o,a){var i=this;if(a)return this.cacheResult().__iterator(o,a);var u=e.__iterator(R,a),s=!0,c=0;return new F((function(){var e,a,l;do{if((e=u.next()).done)return r||o===M?e:z(o,c++,o===P?void 0:e.value[1],e);var f=e.value;a=f[0],l=f[1],s&&(s=t.call(n,l,a,i))}while(s);return o===R?e:z(o,a,l,e)}))},o}function un(e,t){var n=u(e),o=[e].concat(t).map((function(e){return i(e)?n&&(e=r(e)):e=n?ue(e):se(Array.isArray(e)?e:[e]),e})).filter((function(e){return 0!==e.size}));if(0===o.length)return e;if(1===o.length){var a=o[0];if(a===e||n&&u(a)||s(e)&&s(a))return a}var c=new te(o);return n?c=c.toKeyedSeq():s(e)||(c=c.toSetSeq()),(c=c.flatten(!0)).size=o.reduce((function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}}),0),c}function sn(e,t,n){var r=bn(e);return r.__iterateUncached=function(r,o){var a=0,u=!1;function s(e,c){var l=this;e.__iterate((function(e,o){return(!t||c0}function dn(e,t,r){var o=bn(e);return o.size=new te(r).map((function(e){return e.size})).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(M,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var a=r.map((function(e){return e=n(e),W(o?e.reverse():e)})),i=0,u=!1;return new F((function(){var n;return u||(n=a.map((function(e){return e.next()})),u=n.some((function(e){return e.done}))),u?q():z(e,i++,t.apply(null,n.map((function(e){return e.value}))))}))},o}function mn(e,t){return ae(e)?t:e.constructor(t)}function vn(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function gn(e){return Ve(e.size),A(e)}function yn(e){return u(e)?r:s(e)?o:a}function bn(e){return Object.create((u(e)?K:s(e)?Y:G).prototype)}function wn(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function xn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):Kn(e,t)},Vn.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Ve(e.size);var t=this.size,n=this._head;return e.reverse().forEach((function(e){t++,n={value:e,next:n}})),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):Kn(t,n)},Vn.prototype.pop=function(){return this.slice(1)},Vn.prototype.unshift=function(){return this.push.apply(this,arguments)},Vn.prototype.unshiftAll=function(e){return this.pushAll(e)},Vn.prototype.shift=function(){return this.pop.apply(this,arguments)},Vn.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Yn()},Vn.prototype.slice=function(e,t){if(j(e,t,this.size))return this;var n=T(e,this.size);if(I(t,this.size)!==this.size)return Se.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):Kn(r,o)},Vn.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Kn(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Vn.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},Vn.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new F((function(){if(r){var t=r.value;return r=r.next,z(e,n++,t)}return q()}))},Vn.isStack=Wn;var Hn,$n="@@__IMMUTABLE_STACK__@@",Jn=Vn.prototype;function Kn(e,t,n,r){var o=Object.create(Jn);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Yn(){return Hn||(Hn=Kn(0))}function Gn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}Jn[$n]=!0,Jn.withMutations=Ke.withMutations,Jn.asMutable=Ke.asMutable,Jn.asImmutable=Ke.asImmutable,Jn.wasAltered=Ke.wasAltered,n.Iterator=F,Gn(n,{toArray:function(){Ve(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate((function(t,n){e[n]=t})),e},toIndexedSeq:function(){return new Kt(this)},toJS:function(){return this.toSeq().map((function(e){return e&&"function"==typeof e.toJS?e.toJS():e})).__toJS()},toJSON:function(){return this.toSeq().map((function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e})).__toJS()},toKeyedSeq:function(){return new Jt(this,!0)},toMap:function(){return We(this.toKeyedSeq())},toObject:function(){Ve(this.size);var e={};return this.__iterate((function(t,n){e[n]=t})),e},toOrderedMap:function(){return Ut(this.toKeyedSeq())},toOrderedSet:function(){return Ln(u(this)?this.valueSeq():this)},toSet:function(){return jn(u(this)?this.valueSeq():this)},toSetSeq:function(){return new Yt(this)},toSeq:function(){return s(this)?this.toIndexedSeq():u(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Vn(u(this)?this.valueSeq():this)},toList:function(){return St(u(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return mn(this,un(this,e.call(arguments,0)))},includes:function(e){return this.some((function(t){return ge(t,e)}))},entries:function(){return this.__iterator(R)},every:function(e,t){Ve(this.size);var n=!0;return this.__iterate((function(r,o,a){if(!e.call(t,r,o,a))return n=!1,!1})),n},filter:function(e,t){return mn(this,en(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Ve(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Ve(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate((function(r){n?n=!1:t+=e,t+=null!=r?r.toString():""})),t},keys:function(){return this.__iterator(P)},map:function(e,t){return mn(this,Zt(this,e,t))},reduce:function(e,t,n){var r,o;return Ve(this.size),arguments.length<2?o=!0:r=t,this.__iterate((function(t,a,i){o?(o=!1,r=t):r=e.call(n,r,t,a,i)})),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return mn(this,Xt(this,!0))},slice:function(e,t){return mn(this,rn(this,e,t,!0))},some:function(e,t){return!this.every(tr(e),t)},sort:function(e){return mn(this,fn(this,e))},values:function(){return this.__iterator(M)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some((function(){return!0}))},count:function(e,t){return A(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return tn(this,e,t)},equals:function(e){return ye(this,e)},entrySeq:function(){var e=this;if(e._cache)return new te(e._cache);var t=e.toSeq().map(er).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(tr(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate((function(n,o,a){if(e.call(t,n,o,a))return r=[o,n],!1})),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(C)},flatMap:function(e,t){return mn(this,cn(this,e,t))},flatten:function(e){return mn(this,sn(this,e,!0))},fromEntrySeq:function(){return new Gt(this)},get:function(e,t){return this.find((function(t,n){return ge(n,e)}),void 0,t)},getIn:function(e,t){for(var n,r=this,o=_n(e);!(n=o.next()).done;){var a=n.value;if((r=r&&r.get?r.get(a,b):b)===b)return t}return r},groupBy:function(e,t){return nn(this,e,t)},has:function(e){return this.get(e,b)!==b},hasIn:function(e){return this.getIn(e,b)!==b},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every((function(t){return e.includes(t)}))},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey((function(t){return ge(t,e)}))},keySeq:function(){return this.toSeq().map(Xn).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return pn(this,e)},maxBy:function(e,t){return pn(this,t,e)},min:function(e){return pn(this,e?nr(e):ar)},minBy:function(e,t){return pn(this,t?nr(t):ar,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return mn(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return mn(this,an(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(tr(e),t)},sortBy:function(e,t){return mn(this,fn(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return mn(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return mn(this,on(this,e,t))},takeUntil:function(e,t){return this.takeWhile(tr(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=ir(this))}});var Qn=n.prototype;Qn[f]=!0,Qn[B]=Qn.values,Qn.__toJS=Qn.toArray,Qn.__toStringMapper=rr,Qn.inspect=Qn.toSource=function(){return this.toString()},Qn.chain=Qn.flatMap,Qn.contains=Qn.includes,Gn(r,{flip:function(){return mn(this,Qt(this))},mapEntries:function(e,t){var n=this,r=0;return mn(this,this.toSeq().map((function(o,a){return e.call(t,[a,o],r++,n)})).fromEntrySeq())},mapKeys:function(e,t){var n=this;return mn(this,this.toSeq().flip().map((function(r,o){return e.call(t,r,o,n)})).flip())}});var Zn=r.prototype;function Xn(e,t){return t}function er(e,t){return[t,e]}function tr(e){return function(){return!e.apply(this,arguments)}}function nr(e){return function(){return-e.apply(this,arguments)}}function rr(e){return"string"==typeof e?JSON.stringify(e):String(e)}function or(){return k(arguments)}function ar(e,t){return et?-1:0}function ir(e){if(e.size===1/0)return 0;var t=l(e),n=u(e),r=t?1:0;return ur(e.__iterate(n?t?function(e,t){r=31*r+sr(Ce(e),Ce(t))|0}:function(e,t){r=r+sr(Ce(e),Ce(t))|0}:t?function(e){r=31*r+Ce(e)|0}:function(e){r=r+Ce(e)|0}),r)}function ur(e,t){return t=Ae(t,3432918353),t=Ae(t<<15|t>>>-15,461845907),t=Ae(t<<13|t>>>-13,5),t=Ae((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=Oe((t=Ae(t^t>>>13,3266489909))^t>>>16)}function sr(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return Zn[p]=!0,Zn[B]=Qn.entries,Zn.__toJS=Qn.toObject,Zn.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+rr(e)},Gn(o,{toKeyedSeq:function(){return new Jt(this,!1)},filter:function(e,t){return mn(this,en(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return mn(this,Xt(this,!1))},slice:function(e,t){return mn(this,rn(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=T(e,e<0?this.count():this.size);var r=this.slice(0,e);return mn(this,1===n?r:r.concat(k(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return mn(this,sn(this,e,!1))},get:function(e,t){return(e=O(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find((function(t,n){return n===e}),void 0,t)},has:function(e){return(e=O(this,e))>=0&&(void 0!==this.size?this.size===1/0||e1)try{return decodeURIComponent(t[1])}catch(e){console.error(e)}return null}function Ne(e){return t=e.replace(/\.[^./]*$/,""),Y()(J()(t));var t}function Pe(e,t,n,r,a){if(!t)return[];var u=[],s=t.get("nullable"),c=t.get("required"),f=t.get("maximum"),h=t.get("minimum"),d=t.get("type"),m=t.get("format"),g=t.get("maxLength"),b=t.get("minLength"),x=t.get("uniqueItems"),_=t.get("maxItems"),E=t.get("minItems"),S=t.get("pattern"),k=n||!0===c,A=null!=e;if(s&&null===e||!d||!(k||A&&"array"===d||!(!k&&!A)))return[];var O="string"===d&&e,C="array"===d&&l()(e)&&e.length,j="array"===d&&W.a.List.isList(e)&&e.count(),T=[O,C,j,"array"===d&&"string"==typeof e&&e,"file"===d&&e instanceof ue.a.File,"boolean"===d&&(e||!1===e),"number"===d&&(e||0===e),"integer"===d&&(e||0===e),"object"===d&&"object"===i()(e)&&null!==e,"object"===d&&"string"==typeof e&&e],I=N()(T).call(T,(function(e){return!!e}));if(k&&!I&&!r)return u.push("Required field is not provided"),u;if("object"===d&&(null===a||"application/json"===a)){var P,M=e;if("string"==typeof e)try{M=JSON.parse(e)}catch(e){return u.push("Parameter string value must be valid JSON"),u}if(t&&t.has("required")&&Ee(c.isList)&&c.isList()&&y()(c).call(c,(function(e){void 0===M[e]&&u.push({propKey:e,error:"Required property not found"})})),t&&t.has("properties"))y()(P=t.get("properties")).call(P,(function(e,t){var n=Pe(M[t],e,!1,r,a);u.push.apply(u,o()(p()(n).call(n,(function(e){return{propKey:t,error:e}}))))}))}if(S){var R=function(e,t){if(!new RegExp(t).test(e))return"Value must follow pattern "+t}(e,S);R&&u.push(R)}if(E&&"array"===d){var D=function(e,t){var n;if(!e&&t>=1||e&&e.lengtht)return v()(n="Array must not contain more then ".concat(t," item")).call(n,1===t?"":"s")}(e,_);L&&u.push({needRemove:!0,error:L})}if(x&&"array"===d){var B=function(e,t){if(e&&("true"===t||!0===t)){var n=Object(V.fromJS)(e),r=n.toSet();if(e.length>r.size){var o=Object(V.Set)();if(y()(n).call(n,(function(e,t){w()(n).call(n,(function(t){return Ee(t.equals)?t.equals(e):t===e})).size>1&&(o=o.add(t))})),0!==o.size)return p()(o).call(o,(function(e){return{index:e,error:"No duplicates allowed."}})).toArray()}}}(e,x);B&&u.push.apply(u,o()(B))}if(g||0===g){var F=function(e,t){var n;if(e.length>t)return v()(n="Value must be no longer than ".concat(t," character")).call(n,1!==t?"s":"")}(e,g);F&&u.push(F)}if(b){var z=function(e,t){var n;if(e.lengtht)return"Value must be less than ".concat(t)}(e,f);q&&u.push(q)}if(h||0===h){var U=function(e,t){if(e2&&void 0!==arguments[2]?arguments[2]:{},r=n.isOAS3,o=void 0!==r&&r,a=n.bypassRequiredCheck,i=void 0!==a&&a,u=e.get("required"),s=Object(le.a)(e,{isOAS3:o}),c=s.schema,l=s.parameterContentMediaType;return Pe(t,c,u,i,l)},Re=function(e,t,n){if(e&&(!e.xml||!e.xml.name)){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return Object(ie.memoizedCreateXMLExample)(e,t,n)},De=[{when:/json/,shouldStringifyTypes:["string"]}],Le=["object"],Be=function(e,t,n,r){var a=Object(ie.memoizedSampleFromSchema)(e,t,r),u=i()(a),s=S()(De).call(De,(function(e,t){var r;return t.when.test(n)?v()(r=[]).call(r,o()(e),o()(t.shouldStringifyTypes)):e}),Le);return te()(s,(function(e){return e===u}))?M()(a,null,2):a},Fe=function(e,t,n,r){var o,a=Be(e,t,n,r);try{"\n"===(o=me.a.dump(me.a.load(a),{lineWidth:-1}))[o.length-1]&&(o=T()(o).call(o,0,o.length-1))}catch(e){return console.error(e),"error: could not generate yaml example"}return o.replace(/\t/g," ")},ze=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:void 0;return e&&Ee(e.toJS)&&(e=e.toJS()),r&&Ee(r.toJS)&&(r=r.toJS()),/xml/.test(t)?Re(e,n,r):/(yaml|yml)/.test(t)?Fe(e,n,t,r):Be(e,n,t,r)},qe=function(){var e={},t=ue.a.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},Ue=function(t){return(t instanceof e?t:e.from(t.toString(),"utf-8")).toString("base64")},Ve={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},We=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},He=function(e,t,n){return!!X()(n,(function(n){return re()(e[n],t[n])}))};function $e(e){return"string"!=typeof e||""===e?"":Object(H.sanitizeUrl)(e)}function Je(e){return!(!e||D()(e).call(e,"localhost")>=0||D()(e).call(e,"127.0.0.1")>=0||"none"===e)}function Ke(e){if(!W.a.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=B()(e).call(e,(function(e,t){return z()(t).call(t,"2")&&_()(e.get("content")||{}).length>0})),n=e.get("default")||W.a.OrderedMap(),r=(n.get("content")||W.a.OrderedMap()).keySeq().toJS().length?n:null;return t||r}var Ye=function(e){return"string"==typeof e||e instanceof String?U()(e).call(e).replace(/\s/g,"%20"):""},Ge=function(e){return ce()(Ye(e).replace(/%20/g,"_"))},Qe=function(e){return w()(e).call(e,(function(e,t){return/^x-/.test(t)}))},Ze=function(e){return w()(e).call(e,(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)}))};function Xe(e,t){var n,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==i()(e)||l()(e)||null===e||!t)return e;var o=A()({},e);return y()(n=_()(o)).call(n,(function(e){e===t&&r(o[e],e)?delete o[e]:o[e]=Xe(o[e],t,r)})),o}function et(e){if("string"==typeof e)return e;if(e&&e.toJS&&(e=e.toJS()),"object"===i()(e)&&null!==e)try{return M()(e,null,2)}catch(t){return String(e)}return null==e?"":e.toString()}function tt(e){return"number"==typeof e?e.toString():e}function nt(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.returnAll,r=void 0!==n&&n,o=t.allowHashes,a=void 0===o||o;if(!W.a.Map.isMap(e))throw new Error("paramToIdentifier: received a non-Im.Map parameter as input");var i,u,s,c=e.get("name"),l=e.get("in"),f=[];e&&e.hashCode&&l&&c&&a&&f.push(v()(i=v()(u="".concat(l,".")).call(u,c,".hash-")).call(i,e.hashCode()));l&&c&&f.push(v()(s="".concat(l,".")).call(s,c));return f.push(c),r?f:f[0]||""}function rt(e,t){var n,r=nt(e,{returnAll:!0});return w()(n=p()(r).call(r,(function(e){return t[e]}))).call(n,(function(e){return void 0!==e}))[0]}function ot(){return it(pe()(32).toString("base64"))}function at(e){return it(de()("sha256").update(e).digest("base64"))}function it(e){return e.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}var ut=function(e){return!e||!(!ge(e)||!e.isEmpty())}}).call(this,n(132).Buffer)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){var r=n(226);function o(e,t){for(var n=0;n1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:r,n=null,a=null;return function(){return o(t,n,arguments)||(a=e.apply(null,arguments)),n=arguments,a}}))},function(e,t,n){(function(t){var n=function(e){return e&&e.Math==Math&&e};e.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof t&&t)||function(){return this}()||Function("return this")()}).call(this,n(57))},function(e,t,n){e.exports=n(385)},function(e,t,n){var r=n(166),o=n(515);function a(t){return"function"==typeof r&&"symbol"==typeof o?(e.exports=a=function(e){return typeof e},e.exports.default=e.exports,e.exports.__esModule=!0):(e.exports=a=function(e){return e&&"function"==typeof r&&e.constructor===r&&e!==r.prototype?"symbol":typeof e},e.exports.default=e.exports,e.exports.__esModule=!0),a(t)}e.exports=a,e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){e.exports=n(351)},function(e,t,n){e.exports=n(349)},function(e,t,n){"use strict";var r=n(17),o=n(93),a=n(27),i=n(41),u=n(111).f,s=n(331),c=n(34),l=n(84),f=n(85),p=n(44),h=function(e){var t=function(n,r,a){if(this instanceof t){switch(arguments.length){case 0:return new e;case 1:return new e(n);case 2:return new e(n,r)}return new e(n,r,a)}return o(e,this,arguments)};return t.prototype=e.prototype,t};e.exports=function(e,t){var n,o,d,m,v,g,y,b,w=e.target,x=e.global,_=e.stat,E=e.proto,S=x?r:_?r[w]:(r[w]||{}).prototype,k=x?c:c[w]||f(c,w,{})[w],A=k.prototype;for(d in t)n=!s(x?d:w+(_?".":"#")+d,e.forced)&&S&&p(S,d),v=k[d],n&&(g=e.noTargetGet?(b=u(S,d))&&b.value:S[d]),m=n&&g?g:t[d],n&&typeof v==typeof m||(y=e.bind&&n?l(m,r):e.wrap&&n?h(m):E&&i(m)?a(m):m,(e.sham||m&&m.sham||v&&v.sham)&&f(y,"sham",!0),f(k,d,y),E&&(p(c,o=w+"Prototype")||f(c,o,{}),f(c[o],d,m),e.real&&A&&!A[d]&&f(A,d,m)))}},function(e,t,n){e.exports=n(381)},function(e,t,n){e.exports=n(352)},function(e,t,n){var r=n(420),o=n(421),a=n(800),i=n(802),u=n(807),s=n(809),c=n(814),l=n(226),f=n(3);function p(e,t){var n=r(e);if(o){var u=o(e);t&&(u=a(u).call(u,(function(t){return i(e,t).enumerable}))),n.push.apply(n,u)}return n}e.exports=function(e){for(var t=1;t>",i=function(){invariant(!1,"ImmutablePropTypes type checking code is stripped in production.")};i.isRequired=i;var u=function(){return i};function s(e){var t=typeof e;return Array.isArray(e)?"array":e instanceof RegExp?"object":e instanceof o.Iterable?"Immutable."+e.toSource().split(" ")[0]:t}function c(e){function t(t,n,r,o,i,u){for(var s=arguments.length,c=Array(s>6?s-6:0),l=6;l4)}function l(e){var t=e.get("swagger");return"string"==typeof t&&i()(t).call(t,"2.0")}function f(e){return function(t,n){return function(r){return n&&n.specSelectors&&n.specSelectors.specJson?c(n.specSelectors.specJson())?s.a.createElement(e,o()({},r,n,{Ori:t})):s.a.createElement(t,r):(console.warn("OAS3 wrapper: couldn't get spec"),null)}}}},function(e,t,n){e.exports=n(535)},function(e,t,n){var r=n(17),o=n(212),a=n(44),i=n(171),u=n(210),s=n(329),c=o("wks"),l=r.Symbol,f=l&&l.for,p=s?l:l&&l.withoutSetter||i;e.exports=function(e){if(!a(c,e)||!u&&"string"!=typeof c[e]){var t="Symbol."+e;u&&a(l,e)?c[e]=l[e]:c[e]=s&&f?f(t):p(t)}return c[e]}},function(e,t,n){var r=n(242);e.exports=function(e,t,n){var o=null==e?void 0:r(e,t);return void 0===o?n:o}},function(e,t,n){e.exports=n(840)},function(e,t){e.exports=function(e){return"function"==typeof e}},function(e,t,n){var r=n(34);e.exports=function(e){return r[e+"Prototype"]}},function(e,t,n){var r=n(41);e.exports=function(e){return"object"==typeof e?null!==e:r(e)}},function(e,t,n){var r=n(27),o=n(62),a=r({}.hasOwnProperty);e.exports=Object.hasOwn||function(e,t){return a(o(e),t)}},function(e,t,n){var r=n(34),o=n(44),a=n(223),i=n(63).f;e.exports=function(e){var t=r.Symbol||(r.Symbol={});o(t,e)||i(t,e,{value:a.f(e)})}},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_SPEC",(function(){return ee})),n.d(t,"UPDATE_URL",(function(){return te})),n.d(t,"UPDATE_JSON",(function(){return ne})),n.d(t,"UPDATE_PARAM",(function(){return re})),n.d(t,"UPDATE_EMPTY_PARAM_INCLUSION",(function(){return oe})),n.d(t,"VALIDATE_PARAMS",(function(){return ae})),n.d(t,"SET_RESPONSE",(function(){return ie})),n.d(t,"SET_REQUEST",(function(){return ue})),n.d(t,"SET_MUTATED_REQUEST",(function(){return se})),n.d(t,"LOG_REQUEST",(function(){return ce})),n.d(t,"CLEAR_RESPONSE",(function(){return le})),n.d(t,"CLEAR_REQUEST",(function(){return fe})),n.d(t,"CLEAR_VALIDATE_PARAMS",(function(){return pe})),n.d(t,"UPDATE_OPERATION_META_VALUE",(function(){return he})),n.d(t,"UPDATE_RESOLVED",(function(){return de})),n.d(t,"UPDATE_RESOLVED_SUBTREE",(function(){return me})),n.d(t,"SET_SCHEME",(function(){return ve})),n.d(t,"updateSpec",(function(){return ge})),n.d(t,"updateResolved",(function(){return ye})),n.d(t,"updateUrl",(function(){return be})),n.d(t,"updateJsonSpec",(function(){return we})),n.d(t,"parseToJson",(function(){return xe})),n.d(t,"resolveSpec",(function(){return Ee})),n.d(t,"requestResolvedSubtree",(function(){return Ae})),n.d(t,"changeParam",(function(){return Oe})),n.d(t,"changeParamByIdentity",(function(){return Ce})),n.d(t,"updateResolvedSubtree",(function(){return je})),n.d(t,"invalidateResolvedSubtreeCache",(function(){return Te})),n.d(t,"validateParams",(function(){return Ie})),n.d(t,"updateEmptyParamInclusion",(function(){return Ne})),n.d(t,"clearValidateParams",(function(){return Pe})),n.d(t,"changeConsumesValue",(function(){return Me})),n.d(t,"changeProducesValue",(function(){return Re})),n.d(t,"setResponse",(function(){return De})),n.d(t,"setRequest",(function(){return Le})),n.d(t,"setMutatedRequest",(function(){return Be})),n.d(t,"logRequest",(function(){return Fe})),n.d(t,"executeRequest",(function(){return ze})),n.d(t,"execute",(function(){return qe})),n.d(t,"clearResponse",(function(){return Ue})),n.d(t,"clearRequest",(function(){return Ve})),n.d(t,"setScheme",(function(){return We}));var r=n(25),o=n.n(r),a=n(54),i=n.n(a),u=n(72),s=n.n(u),c=n(19),l=n.n(c),f=n(40),p=n.n(f),h=n(24),d=n.n(h),m=n(4),v=n.n(m),g=n(319),y=n.n(g),b=n(30),w=n.n(b),x=n(197),_=n.n(x),E=n(66),S=n.n(E),k=n(12),A=n.n(k),O=n(198),C=n.n(O),j=n(18),T=n.n(j),I=n(23),N=n.n(I),P=n(2),M=n.n(P),R=n(15),D=n.n(R),L=n(21),B=n.n(L),F=n(320),z=n.n(F),q=n(70),U=n(1),V=n(89),W=n.n(V),H=n(141),$=n(457),J=n.n($),K=n(458),Y=n.n(K),G=n(321),Q=n.n(G),Z=n(5),X=["path","method"],ee="spec_update_spec",te="spec_update_url",ne="spec_update_json",re="spec_update_param",oe="spec_update_empty_param_inclusion",ae="spec_validate_param",ie="spec_set_response",ue="spec_set_request",se="spec_set_mutated_request",ce="spec_log_request",le="spec_clear_response",fe="spec_clear_request",pe="spec_clear_validate_param",he="spec_update_operation_meta_value",de="spec_update_resolved",me="spec_update_resolved_subtree",ve="set_scheme";function ge(e){var t,n=(t=e,J()(t)?t:"").replace(/\t/g," ");if("string"==typeof e)return{type:ee,payload:n}}function ye(e){return{type:de,payload:e}}function be(e){return{type:te,payload:e}}function we(e){return{type:ne,payload:e}}var xe=function(e){return function(t){var n=t.specActions,r=t.specSelectors,o=t.errActions,a=r.specStr,i=null;try{e=e||a(),o.clear({source:"parser"}),i=q.a.load(e)}catch(e){return console.error(e),o.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return i&&"object"===l()(i)?n.updateJsonSpec(i):{}}},_e=!1,Ee=function(e,t){return function(n){var r=n.specActions,o=n.specSelectors,a=n.errActions,i=n.fn,u=i.fetch,s=i.resolve,c=i.AST,l=void 0===c?{}:c,f=n.getConfigs;_e||(console.warn("specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!"),_e=!0);var p=f(),h=p.modelPropertyMacro,m=p.parameterMacro,g=p.requestInterceptor,b=p.responseInterceptor;void 0===e&&(e=o.specJson()),void 0===t&&(t=o.url());var w=l.getLineNumberForPath?l.getLineNumberForPath:function(){},x=o.specStr();return s({fetch:u,spec:e,baseDoc:t,modelPropertyMacro:h,parameterMacro:m,requestInterceptor:g,responseInterceptor:b}).then((function(e){var t=e.spec,n=e.errors;if(a.clear({type:"thrown"}),d()(n)&&n.length>0){var o=v()(n).call(n,(function(e){return console.error(e),e.line=e.fullPath?w(x,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",y()(e,"message",{enumerable:!0,value:e.message}),e}));a.newThrownErrBatch(o)}return r.updateResolved(t)}))}},Se=[],ke=Y()(s()(p.a.mark((function e(){var t,n,r,o,a,i,u,c,l,f,h,m,g,b,x,E,k,O;return p.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t=Se.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,a=o.resolveSubtree,i=o.fetch,u=o.AST,c=void 0===u?{}:u,l=t.specSelectors,f=t.specActions,a){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return h=c.getLineNumberForPath?c.getLineNumberForPath:function(){},m=l.specStr(),g=t.getConfigs(),b=g.modelPropertyMacro,x=g.parameterMacro,E=g.requestInterceptor,k=g.responseInterceptor,e.prev=11,e.next=14,w()(Se).call(Se,function(){var e=s()(p.a.mark((function e(t,o){var u,c,f,g,w,O,j,T,I;return p.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return u=e.sent,c=u.resultMap,f=u.specWithCurrentSubtrees,e.next=7,a(f,o,{baseDoc:l.url(),modelPropertyMacro:b,parameterMacro:x,requestInterceptor:E,responseInterceptor:k});case 7:if(g=e.sent,w=g.errors,O=g.spec,r.allErrors().size&&n.clearBy((function(e){var t;return"thrown"!==e.get("type")||"resolver"!==e.get("source")||!_()(t=e.get("fullPath")).call(t,(function(e,t){return e===o[t]||void 0===o[t]}))})),d()(w)&&w.length>0&&(j=v()(w).call(w,(function(e){return e.line=e.fullPath?h(m,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",y()(e,"message",{enumerable:!0,value:e.message}),e})),n.newThrownErrBatch(j)),!O||!l.isOAS3()||"components"!==o[0]||"securitySchemes"!==o[1]){e.next=15;break}return e.next=15,S.a.all(v()(T=A()(I=C()(O)).call(I,(function(e){return"openIdConnect"===e.type}))).call(T,function(){var e=s()(p.a.mark((function e(t){var n,r;return p.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n={url:t.openIdConnectUrl,requestInterceptor:E,responseInterceptor:k},e.prev=1,e.next=4,i(n);case 4:(r=e.sent)instanceof Error||r.status>=400?console.error(r.statusText+" "+n.url):t.openIdConnectData=JSON.parse(r.text),e.next=11;break;case 8:e.prev=8,e.t0=e.catch(1),console.error(e.t0);case 11:case"end":return e.stop()}}),e,null,[[1,8]])})));return function(t){return e.apply(this,arguments)}}()));case 15:return Q()(c,o,O),Q()(f,o,O),e.abrupt("return",{resultMap:c,specWithCurrentSubtrees:f});case 18:case"end":return e.stop()}}),e)})));return function(t,n){return e.apply(this,arguments)}}(),S.a.resolve({resultMap:(l.specResolvedSubtree([])||Object(U.Map)()).toJS(),specWithCurrentSubtrees:l.specJson().toJS()}));case 14:O=e.sent,delete Se.system,Se=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:f.updateResolvedSubtree([],O.resultMap);case 23:case"end":return e.stop()}}),e,null,[[11,19]])}))),35),Ae=function(e){return function(t){var n;T()(n=v()(Se).call(Se,(function(e){return e.join("@@")}))).call(n,e.join("@@"))>-1||(Se.push(e),Se.system=t,ke())}};function Oe(e,t,n,r,o){return{type:re,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}}function Ce(e,t,n,r){return{type:re,payload:{path:e,param:t,value:n,isXml:r}}}var je=function(e,t){return{type:me,payload:{path:e,value:t}}},Te=function(){return{type:me,payload:{path:[],value:Object(U.Map)()}}},Ie=function(e,t){return{type:ae,payload:{pathMethod:e,isOAS3:t}}},Ne=function(e,t,n,r){return{type:oe,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};function Pe(e){return{type:pe,payload:{pathMethod:e}}}function Me(e,t){return{type:he,payload:{path:e,value:t,key:"consumes_value"}}}function Re(e,t){return{type:he,payload:{path:e,value:t,key:"produces_value"}}}var De=function(e,t,n){return{payload:{path:e,method:t,res:n},type:ie}},Le=function(e,t,n){return{payload:{path:e,method:t,req:n},type:ue}},Be=function(e,t,n){return{payload:{path:e,method:t,req:n},type:se}},Fe=function(e){return{payload:e,type:ce}},ze=function(e){return function(t){var n,r,o=t.fn,a=t.specActions,i=t.specSelectors,u=t.getConfigs,c=t.oas3Selectors,l=e.pathName,f=e.method,h=e.operation,m=u(),g=m.requestInterceptor,y=m.responseInterceptor,b=h.toJS();h&&h.get("parameters")&&N()(n=A()(r=h.get("parameters")).call(r,(function(e){return e&&!0===e.get("allowEmptyValue")}))).call(n,(function(t){if(i.parameterInclusionSettingFor([l,f],t.get("name"),t.get("in"))){e.parameters=e.parameters||{};var n=Object(Z.B)(t,e.parameters);(!n||n&&0===n.size)&&(e.parameters[t.get("name")]="")}}));if(e.contextUrl=W()(i.url()).toString(),b&&b.operationId?e.operationId=b.operationId:b&&l&&f&&(e.operationId=o.opId(b,l,f)),i.isOAS3()){var w,x=M()(w="".concat(l,":")).call(w,f);e.server=c.selectedServer(x)||c.selectedServer();var _=c.serverVariables({server:e.server,namespace:x}).toJS(),E=c.serverVariables({server:e.server}).toJS();e.serverVariables=D()(_).length?_:E,e.requestContentType=c.requestContentType(l,f),e.responseContentType=c.responseContentType(l,f)||"*/*";var S,k=c.requestBodyValue(l,f),O=c.requestBodyInclusionSetting(l,f);if(k&&k.toJS)e.requestBody=A()(S=v()(k).call(k,(function(e){return U.Map.isMap(e)?e.get("value"):e}))).call(S,(function(e,t){return(d()(e)?0!==e.length:!Object(Z.q)(e))||O.get(t)})).toJS();else e.requestBody=k}var C=B()({},e);C=o.buildRequest(C),a.setRequest(e.pathName,e.method,C);var j=function(){var t=s()(p.a.mark((function t(n){var r,o;return p.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,g.apply(undefined,[n]);case 2:return r=t.sent,o=B()({},r),a.setMutatedRequest(e.pathName,e.method,o),t.abrupt("return",r);case 6:case"end":return t.stop()}}),t)})));return function(e){return t.apply(this,arguments)}}();e.requestInterceptor=j,e.responseInterceptor=y;var T=z()();return o.execute(e).then((function(t){t.duration=z()()-T,a.setResponse(e.pathName,e.method,t)})).catch((function(t){"Failed to fetch"===t.message&&(t.name="",t.message='**Failed to fetch.** \n**Possible Reasons:** \n - CORS \n - Network Failure \n - URL scheme must be "http" or "https" for CORS request.'),a.setResponse(e.pathName,e.method,{error:!0,err:Object(H.serializeError)(t)})}))}},qe=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=i()(e,X);return function(e){var a=e.fn.fetch,i=e.specSelectors,u=e.specActions,s=i.specJsonWithResolvedSubtrees().toJS(),c=i.operationScheme(t,n),l=i.contentTypeValues([t,n]).toJS(),f=l.requestContentType,p=l.responseContentType,h=/xml/i.test(f),d=i.parameterValues([t,n],h).toJS();return u.executeRequest(o()(o()({},r),{},{fetch:a,spec:s,pathName:t,method:n,parameters:d,requestContentType:f,scheme:c,responseContentType:p}))}};function Ue(e,t){return{type:le,payload:{path:e,method:t}}}function Ve(e,t){return{type:fe,payload:{path:e,method:t}}}function We(e,t,n){return{type:ve,payload:{scheme:e,path:t,method:n}}}},function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t=e.length?{done:!0}:{done:!1,value:e[u++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var c,l=!0,f=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){f=!0,c=e},f:function(){try{l||null==n.return||n.return()}finally{if(f)throw c}}}},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){var n=Function.prototype.call;e.exports=n.bind?n.bind(n):function(){return n.apply(n,arguments)}},function(e,t,n){var r=n(17),o=n(43),a=r.String,i=r.TypeError;e.exports=function(e){if(o(e))return e;throw i(a(e)+" is not an object")}},function(e,t){var n=Array.isArray;e.exports=n},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){var r=n(421),o=n(423),a=n(820);e.exports=function(e,t){if(null==e)return{};var n,i,u=a(e,t);if(r){var s=r(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(u[n]=e[n])}return u},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_SELECTED_SERVER",(function(){return r})),n.d(t,"UPDATE_REQUEST_BODY_VALUE",(function(){return o})),n.d(t,"UPDATE_REQUEST_BODY_VALUE_RETAIN_FLAG",(function(){return a})),n.d(t,"UPDATE_REQUEST_BODY_INCLUSION",(function(){return i})),n.d(t,"UPDATE_ACTIVE_EXAMPLES_MEMBER",(function(){return u})),n.d(t,"UPDATE_REQUEST_CONTENT_TYPE",(function(){return s})),n.d(t,"UPDATE_RESPONSE_CONTENT_TYPE",(function(){return c})),n.d(t,"UPDATE_SERVER_VARIABLE_VALUE",(function(){return l})),n.d(t,"SET_REQUEST_BODY_VALIDATE_ERROR",(function(){return f})),n.d(t,"CLEAR_REQUEST_BODY_VALIDATE_ERROR",(function(){return p})),n.d(t,"CLEAR_REQUEST_BODY_VALUE",(function(){return h})),n.d(t,"setSelectedServer",(function(){return d})),n.d(t,"setRequestBodyValue",(function(){return m})),n.d(t,"setRetainRequestBodyValueFlag",(function(){return v})),n.d(t,"setRequestBodyInclusion",(function(){return g})),n.d(t,"setActiveExamplesMember",(function(){return y})),n.d(t,"setRequestContentType",(function(){return b})),n.d(t,"setResponseContentType",(function(){return w})),n.d(t,"setServerVariableValue",(function(){return x})),n.d(t,"setRequestBodyValidateError",(function(){return _})),n.d(t,"clearRequestBodyValidateError",(function(){return E})),n.d(t,"initRequestBodyValidateError",(function(){return S})),n.d(t,"clearRequestBodyValue",(function(){return k}));var r="oas3_set_servers",o="oas3_set_request_body_value",a="oas3_set_request_body_retain_flag",i="oas3_set_request_body_inclusion",u="oas3_set_active_examples_member",s="oas3_set_request_content_type",c="oas3_set_response_content_type",l="oas3_set_server_variable_value",f="oas3_set_request_body_validate_error",p="oas3_clear_request_body_validate_error",h="oas3_clear_request_body_value";function d(e,t){return{type:r,payload:{selectedServerUrl:e,namespace:t}}}function m(e){var t=e.value,n=e.pathMethod;return{type:o,payload:{value:t,pathMethod:n}}}var v=function(e){var t=e.value,n=e.pathMethod;return{type:a,payload:{value:t,pathMethod:n}}};function g(e){var t=e.value,n=e.pathMethod,r=e.name;return{type:i,payload:{value:t,pathMethod:n,name:r}}}function y(e){var t=e.name,n=e.pathMethod,r=e.contextType,o=e.contextName;return{type:u,payload:{name:t,pathMethod:n,contextType:r,contextName:o}}}function b(e){var t=e.value,n=e.pathMethod;return{type:s,payload:{value:t,pathMethod:n}}}function w(e){var t=e.value,n=e.path,r=e.method;return{type:c,payload:{value:t,path:n,method:r}}}function x(e){var t=e.server,n=e.namespace,r=e.key,o=e.val;return{type:l,payload:{server:t,namespace:n,key:r,val:o}}}var _=function(e){var t=e.path,n=e.method,r=e.validationErrors;return{type:f,payload:{path:t,method:n,validationErrors:r}}},E=function(e){var t=e.path,n=e.method;return{type:p,payload:{path:t,method:n}}},S=function(e){var t=e.pathMethod;return{type:p,payload:{path:t[0],method:t[1]}}},k=function(e){var t=e.pathMethod;return{type:h,payload:{pathMethod:t}}}},function(e,t,n){e.exports=n(647)},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){var r=n(34),o=n(17),a=n(41),i=function(e){return a(e)?e:void 0};e.exports=function(e,t){return arguments.length<2?i(r[e])||i(o[e]):r[e]&&r[e][t]||o[e]&&o[e][t]}},function(e,t,n){"use strict";n.d(t,"b",(function(){return m})),n.d(t,"e",(function(){return v})),n.d(t,"c",(function(){return y})),n.d(t,"a",(function(){return b})),n.d(t,"d",(function(){return w}));var r=n(49),o=n.n(r),a=n(19),i=n.n(a),u=n(108),s=n.n(u),c=n(2),l=n.n(c),f=n(53),p=n.n(f),h=function(e){return String.prototype.toLowerCase.call(e)},d=function(e){return e.replace(/[^\w]/gi,"_")};function m(e){var t=e.openapi;return!!t&&s()(t).call(t,"3")}function v(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=r.v2OperationIdCompatibilityMode;if(!e||"object"!==i()(e))return null;var a=(e.operationId||"").replace(/\s/g,"");return a.length?d(e.operationId):g(t,n,{v2OperationIdCompatibilityMode:o})}function g(e,t){var n,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=r.v2OperationIdCompatibilityMode;if(o){var a,i,u=l()(a="".concat(t.toLowerCase(),"_")).call(a,e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g,"_");return(u=u||l()(i="".concat(e.substring(1),"_")).call(i,t)).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return l()(n="".concat(h(t))).call(n,d(e))}function y(e,t){var n;return l()(n="".concat(h(t),"-")).call(n,e)}function b(e,t){return e&&e.paths?function(e,t){return function(e,t,n){if(!e||"object"!==i()(e)||!e.paths||"object"!==i()(e.paths))return null;var r=e.paths;for(var o in r)for(var a in r[o])if("PARAMETERS"!==a.toUpperCase()){var u=r[o][a];if(u&&"object"===i()(u)){var s={spec:e,pathName:o,method:a.toUpperCase(),operation:u},c=t(s);if(n&&c)return s}}return}(e,t,!0)||null}(e,(function(e){var n=e.pathName,r=e.method,o=e.operation;if(!o||"object"!==i()(o))return!1;var a=o.operationId;return[v(o,n,r),y(n,r),a].some((function(e){return e&&e===t}))})):null}function w(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var a in n){var i=n[a];if(p()(i)){var u=i.parameters,s=function(e){var n=i[e];if(!p()(n))return"continue";var s=v(n,a,e);if(s){r[s]?r[s].push(n):r[s]=[n];var c=r[s];if(c.length>1)c.forEach((function(e,t){var n;e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId=l()(n="".concat(s)).call(n,t+1)}));else if(void 0!==n.operationId){var f=c[0];f.__originalOperationId=f.__originalOperationId||n.operationId,f.operationId=s}}if("parameters"!==e){var h=[],d={};for(var m in t)"produces"!==m&&"consumes"!==m&&"security"!==m||(d[m]=t[m],h.push(d));if(u&&(d.parameters=u,h.push(d)),h.length){var g,y=o()(h);try{for(y.s();!(g=y.n()).done;){var b=g.value;for(var w in b)if(n[w]){if("parameters"===w){var x,_=o()(b[w]);try{var E=function(){var e=x.value;n[w].some((function(t){return t.name&&t.name===e.name||t.$ref&&t.$ref===e.$ref||t.$$ref&&t.$$ref===e.$$ref||t===e}))||n[w].push(e)};for(_.s();!(x=_.n()).done;)E()}catch(e){_.e(e)}finally{_.f()}}}else n[w]=b[w]}}catch(e){y.e(e)}finally{y.f()}}}};for(var c in i)s(c)}}return t.$$normalized=!0,e}},function(e,t,n){"use strict";n.r(t),n.d(t,"NEW_THROWN_ERR",(function(){return o})),n.d(t,"NEW_THROWN_ERR_BATCH",(function(){return a})),n.d(t,"NEW_SPEC_ERR",(function(){return i})),n.d(t,"NEW_SPEC_ERR_BATCH",(function(){return u})),n.d(t,"NEW_AUTH_ERR",(function(){return s})),n.d(t,"CLEAR",(function(){return c})),n.d(t,"CLEAR_BY",(function(){return l})),n.d(t,"newThrownErr",(function(){return f})),n.d(t,"newThrownErrBatch",(function(){return p})),n.d(t,"newSpecErr",(function(){return h})),n.d(t,"newSpecErrBatch",(function(){return d})),n.d(t,"newAuthErr",(function(){return m})),n.d(t,"clear",(function(){return v})),n.d(t,"clearBy",(function(){return g}));var r=n(141),o="err_new_thrown_err",a="err_new_thrown_err_batch",i="err_new_spec_err",u="err_new_spec_err_batch",s="err_new_auth_err",c="err_clear",l="err_clear_by";function f(e){return{type:o,payload:Object(r.serializeError)(e)}}function p(e){return{type:a,payload:e}}function h(e){return{type:i,payload:e}}function d(e){return{type:u,payload:e}}function m(e){return{type:s,payload:e}}function v(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:c,payload:e}}function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:l,payload:e}}},function(e,t,n){var r=n(168),o=n(113);e.exports=function(e){return r(o(e))}},function(e,t,n){var r=n(17),o=n(113),a=r.Object;e.exports=function(e){return a(o(e))}},function(e,t,n){var r=n(17),o=n(48),a=n(330),i=n(51),u=n(169),s=r.TypeError,c=Object.defineProperty;t.f=o?c:function(e,t,n){if(i(e),t=u(t),i(n),a)try{return c(e,t,n)}catch(e){}if("get"in n||"set"in n)throw s("Accessors not supported");return"value"in n&&(e[t]=n.value),e}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}},function(e,t,n){var r=n(132),o=r.Buffer;function a(e,t){for(var n in e)t[n]=e[n]}function i(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(a(r,t),t.Buffer=i),a(o,i),i.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},i.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},i.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},i.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){e.exports=n(424)},function(e,t,n){var r=n(17),o=n(75),a=r.String;e.exports=function(e){if("Symbol"===o(e))throw TypeError("Cannot convert a Symbol value to a string");return a(e)}},function(e,t,n){n(77);var r=n(507),o=n(17),a=n(75),i=n(85),u=n(130),s=n(38)("toStringTag");for(var c in r){var l=o[c],f=l&&l.prototype;f&&a(f)!==s&&i(f,s,c),u[c]=u.Array}},function(e,t,n){var r=n(355),o="object"==typeof self&&self&&self.Object===Object&&self,a=r||o||Function("return this")();e.exports=a},function(e,t,n){"use strict";function r(e){return null==e}var o={isNothing:r,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:r(e)?[]:[e]},repeat:function(e,t){var n,r="";for(n=0;nu&&(t=r-u+(a=" ... ").length),n-r>u&&(n=r+u-(i=" ...").length),{str:a+e.slice(t,n).replace(/\t/g,"→")+i,pos:r-t+a.length}}function c(e,t){return o.repeat(" ",t-e.length)+e}var l=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var n,r=/\r?\n|\r|\0/g,a=[0],i=[],u=-1;n=r.exec(e.buffer);)i.push(n.index),a.push(n.index+n[0].length),e.position<=n.index&&u<0&&(u=a.length-2);u<0&&(u=a.length-1);var l,f,p="",h=Math.min(e.line+t.linesAfter,i.length).toString().length,d=t.maxLength-(t.indent+h+3);for(l=1;l<=t.linesBefore&&!(u-l<0);l++)f=s(e.buffer,a[u-l],i[u-l],e.position-(a[u]-a[u-l]),d),p=o.repeat(" ",t.indent)+c((e.line-l+1).toString(),h)+" | "+f.str+"\n"+p;for(f=s(e.buffer,a[u],i[u],e.position,d),p+=o.repeat(" ",t.indent)+c((e.line+1).toString(),h)+" | "+f.str+"\n",p+=o.repeat("-",t.indent+h+3+f.pos)+"^\n",l=1;l<=t.linesAfter&&!(u+l>=i.length);l++)f=s(e.buffer,a[u+l],i[u+l],e.position-(a[u]-a[u+l]),d),p+=o.repeat(" ",t.indent)+c((e.line+l+1).toString(),h)+" | "+f.str+"\n";return p.replace(/\n$/,"")},f=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],p=["scalar","sequence","mapping"];var h=function(e,t){if(t=t||{},Object.keys(t).forEach((function(t){if(-1===f.indexOf(t))throw new u('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach((function(n){e[n].forEach((function(e){t[String(e)]=n}))})),t}(t.styleAliases||null),-1===p.indexOf(this.kind))throw new u('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function d(e,t){var n=[];return e[t].forEach((function(e){var t=n.length;n.forEach((function(n,r){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=r)})),n[t]=e})),n}function m(e){return this.extend(e)}m.prototype.extend=function(e){var t=[],n=[];if(e instanceof h)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new u("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof h))throw new u("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new u("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new u("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),n.forEach((function(e){if(!(e instanceof h))throw new u("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var r=Object.create(m.prototype);return r.implicit=(this.implicit||[]).concat(t),r.explicit=(this.explicit||[]).concat(n),r.compiledImplicit=d(r,"implicit"),r.compiledExplicit=d(r,"explicit"),r.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function r(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kind][e.tag]=n.fallback[e.tag]=e}for(e=0,t=arguments.length;e=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),A=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");var O=/^[-+]?[0-9]+e/;var C=new h("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&!(!A.test(e)||"_"===e[e.length-1])},construct:function(e){var t,n;return n="-"===(t=e.replace(/_/g,"").toLowerCase())[0]?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:n*parseFloat(t,10)},predicate:function(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!=0||o.isNegativeZero(e))},represent:function(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(o.isNegativeZero(e))return"-0.0";return n=e.toString(10),O.test(n)?n.replace("e",".e"):n},defaultStyle:"lowercase"}),j=w.extend({implicit:[x,_,k,C]}),T=j,I=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),N=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");var P=new h("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==I.exec(e)||null!==N.exec(e))},construct:function(e){var t,n,r,o,a,i,u,s,c=0,l=null;if(null===(t=I.exec(e))&&(t=N.exec(e)),null===t)throw new Error("Date resolve error");if(n=+t[1],r=+t[2]-1,o=+t[3],!t[4])return new Date(Date.UTC(n,r,o));if(a=+t[4],i=+t[5],u=+t[6],t[7]){for(c=t[7].slice(0,3);c.length<3;)c+="0";c=+c}return t[9]&&(l=6e4*(60*+t[10]+ +(t[11]||0)),"-"===t[9]&&(l=-l)),s=new Date(Date.UTC(n,r,o,a,i,u,c)),l&&s.setTime(s.getTime()-l),s},instanceOf:Date,represent:function(e){return e.toISOString()}});var M=new h("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}}),R="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";var D=new h("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,n,r=0,o=e.length,a=R;for(n=0;n64)){if(t<0)return!1;r+=6}return r%8==0},construct:function(e){var t,n,r=e.replace(/[\r\n=]/g,""),o=r.length,a=R,i=0,u=[];for(t=0;t>16&255),u.push(i>>8&255),u.push(255&i)),i=i<<6|a.indexOf(r.charAt(t));return 0===(n=o%4*6)?(u.push(i>>16&255),u.push(i>>8&255),u.push(255&i)):18===n?(u.push(i>>10&255),u.push(i>>2&255)):12===n&&u.push(i>>4&255),new Uint8Array(u)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){var t,n,r="",o=0,a=e.length,i=R;for(t=0;t>18&63],r+=i[o>>12&63],r+=i[o>>6&63],r+=i[63&o]),o=(o<<8)+e[t];return 0===(n=a%3)?(r+=i[o>>18&63],r+=i[o>>12&63],r+=i[o>>6&63],r+=i[63&o]):2===n?(r+=i[o>>10&63],r+=i[o>>4&63],r+=i[o<<2&63],r+=i[64]):1===n&&(r+=i[o>>2&63],r+=i[o<<4&63],r+=i[64],r+=i[64]),r}}),L=Object.prototype.hasOwnProperty,B=Object.prototype.toString;var F=new h("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,n,r,o,a,i=[],u=e;for(t=0,n=u.length;t>10),56320+(e-65536&1023))}for(var ae=new Array(256),ie=new Array(256),ue=0;ue<256;ue++)ae[ue]=re(ue)?1:0,ie[ue]=re(ue);function se(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||W,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function ce(e,t){var n={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return n.snippet=l(n),new u(t,n)}function le(e,t){throw ce(e,t)}function fe(e,t){e.onWarning&&e.onWarning.call(null,ce(e,t))}var pe={YAML:function(e,t,n){var r,o,a;null!==e.version&&le(e,"duplication of %YAML directive"),1!==n.length&&le(e,"YAML directive accepts exactly one argument"),null===(r=/^([0-9]+)\.([0-9]+)$/.exec(n[0]))&&le(e,"ill-formed argument of the YAML directive"),o=parseInt(r[1],10),a=parseInt(r[2],10),1!==o&&le(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=a<2,1!==a&&2!==a&&fe(e,"unsupported YAML version of the document")},TAG:function(e,t,n){var r,o;2!==n.length&&le(e,"TAG directive accepts exactly two arguments"),r=n[0],o=n[1],Y.test(r)||le(e,"ill-formed tag handle (first argument) of the TAG directive"),H.call(e.tagMap,r)&&le(e,'there is a previously declared suffix for "'+r+'" tag handle'),G.test(o)||le(e,"ill-formed tag prefix (second argument) of the TAG directive");try{o=decodeURIComponent(o)}catch(t){le(e,"tag prefix is malformed: "+o)}e.tagMap[r]=o}};function he(e,t,n,r){var o,a,i,u;if(t1&&(e.result+=o.repeat("\n",t-1))}function we(e,t){var n,r,o=e.tag,a=e.anchor,i=[],u=!1;if(-1!==e.firstTabInLine)return!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=i),r=e.input.charCodeAt(e.position);0!==r&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,le(e,"tab characters must not be used in indentation")),45===r)&&ee(e.input.charCodeAt(e.position+1));)if(u=!0,e.position++,ge(e,!0,-1)&&e.lineIndent<=t)i.push(null),r=e.input.charCodeAt(e.position);else if(n=e.line,Ee(e,t,3,!1,!0),i.push(e.result),ge(e,!0,-1),r=e.input.charCodeAt(e.position),(e.line===n||e.lineIndent>t)&&0!==r)le(e,"bad indentation of a sequence entry");else if(e.lineIndentt?m=1:e.lineIndent===t?m=0:e.lineIndentt?m=1:e.lineIndent===t?m=0:e.lineIndentt)&&(g&&(i=e.line,u=e.lineStart,s=e.position),Ee(e,t,4,!0,o)&&(g?m=e.result:v=e.result),g||(me(e,p,h,d,m,v,i,u,s),d=m=v=null),ge(e,!0,-1),c=e.input.charCodeAt(e.position)),(e.line===a||e.lineIndent>t)&&0!==c)le(e,"bad indentation of a mapping entry");else if(e.lineIndent=0))break;0===a?le(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):l?le(e,"repeat of an indentation width identifier"):(f=t+a-1,l=!0)}if(X(i)){do{i=e.input.charCodeAt(++e.position)}while(X(i));if(35===i)do{i=e.input.charCodeAt(++e.position)}while(!Z(i)&&0!==i)}for(;0!==i;){for(ve(e),e.lineIndent=0,i=e.input.charCodeAt(e.position);(!l||e.lineIndentf&&(f=e.lineIndent),Z(i))p++;else{if(e.lineIndent0){for(o=i,a=0;o>0;o--)(i=ne(u=e.input.charCodeAt(++e.position)))>=0?a=(a<<4)+i:le(e,"expected hexadecimal character");e.result+=oe(a),e.position++}else le(e,"unknown escape sequence");n=r=e.position}else Z(u)?(he(e,n,r,!0),be(e,ge(e,!1,t)),n=r=e.position):e.position===e.lineStart&&ye(e)?le(e,"unexpected end of the document within a double quoted scalar"):(e.position++,r=e.position)}le(e,"unexpected end of the stream within a double quoted scalar")}(e,h)?g=!0:!function(e){var t,n,r;if(42!==(r=e.input.charCodeAt(e.position)))return!1;for(r=e.input.charCodeAt(++e.position),t=e.position;0!==r&&!ee(r)&&!te(r);)r=e.input.charCodeAt(++e.position);return e.position===t&&le(e,"name of an alias node must contain at least one character"),n=e.input.slice(t,e.position),H.call(e.anchorMap,n)||le(e,'unidentified alias "'+n+'"'),e.result=e.anchorMap[n],ge(e,!0,-1),!0}(e)?function(e,t,n){var r,o,a,i,u,s,c,l,f=e.kind,p=e.result;if(ee(l=e.input.charCodeAt(e.position))||te(l)||35===l||38===l||42===l||33===l||124===l||62===l||39===l||34===l||37===l||64===l||96===l)return!1;if((63===l||45===l)&&(ee(r=e.input.charCodeAt(e.position+1))||n&&te(r)))return!1;for(e.kind="scalar",e.result="",o=a=e.position,i=!1;0!==l;){if(58===l){if(ee(r=e.input.charCodeAt(e.position+1))||n&&te(r))break}else if(35===l){if(ee(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&ye(e)||n&&te(l))break;if(Z(l)){if(u=e.line,s=e.lineStart,c=e.lineIndent,ge(e,!1,-1),e.lineIndent>=t){i=!0,l=e.input.charCodeAt(e.position);continue}e.position=a,e.line=u,e.lineStart=s,e.lineIndent=c;break}}i&&(he(e,o,a,!1),be(e,e.line-u),o=a=e.position,i=!1),X(l)||(a=e.position+1),l=e.input.charCodeAt(++e.position)}return he(e,o,a,!1),!!e.result||(e.kind=f,e.result=p,!1)}(e,h,1===n)&&(g=!0,null===e.tag&&(e.tag="?")):(g=!0,null===e.tag&&null===e.anchor||le(e,"alias node should not have any properties")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===m&&(g=s&&we(e,d))),null===e.tag)null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);else if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&le(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),c=0,l=e.implicitTypes.length;c"),null!==e.result&&p.kind!==e.kind&&le(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+p.kind+'", not "'+e.kind+'"'),p.resolve(e.result,e.tag)?(e.result=p.construct(e.result,e.tag),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):le(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||g}function Se(e){var t,n,r,o,a=e.position,i=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);0!==(o=e.input.charCodeAt(e.position))&&(ge(e,!0,-1),o=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==o));){for(i=!0,o=e.input.charCodeAt(++e.position),t=e.position;0!==o&&!ee(o);)o=e.input.charCodeAt(++e.position);for(r=[],(n=e.input.slice(t,e.position)).length<1&&le(e,"directive name must not be less than one character in length");0!==o;){for(;X(o);)o=e.input.charCodeAt(++e.position);if(35===o){do{o=e.input.charCodeAt(++e.position)}while(0!==o&&!Z(o));break}if(Z(o))break;for(t=e.position;0!==o&&!ee(o);)o=e.input.charCodeAt(++e.position);r.push(e.input.slice(t,e.position))}0!==o&&ve(e),H.call(pe,n)?pe[n](e,n,r):fe(e,'unknown document directive "'+n+'"')}ge(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,ge(e,!0,-1)):i&&le(e,"directives end mark is expected"),Ee(e,e.lineIndent-1,4,!1,!0),ge(e,!0,-1),e.checkLineBreaks&&J.test(e.input.slice(a,e.position))&&fe(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&ye(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,ge(e,!0,-1)):e.position=55296&&r<=56319&&t+1=56320&&n<=57343?1024*(r-55296)+n-56320+65536:r}function Ue(e){return/^\n* /.test(e)}function Ve(e,t,n,r,o,a,i,u){var s,c,l=0,f=null,p=!1,h=!1,d=-1!==r,m=-1,v=Be(c=qe(e,0))&&c!==je&&!Le(c)&&45!==c&&63!==c&&58!==c&&44!==c&&91!==c&&93!==c&&123!==c&&125!==c&&35!==c&&38!==c&&42!==c&&33!==c&&124!==c&&61!==c&&62!==c&&39!==c&&34!==c&&37!==c&&64!==c&&96!==c&&function(e){return!Le(e)&&58!==e}(qe(e,e.length-1));if(t||i)for(s=0;s=65536?s+=2:s++){if(!Be(l=qe(e,s)))return 5;v=v&&ze(l,f,u),f=l}else{for(s=0;s=65536?s+=2:s++){if(10===(l=qe(e,s)))p=!0,d&&(h=h||s-m-1>r&&" "!==e[m+1],m=s);else if(!Be(l))return 5;v=v&&ze(l,f,u),f=l}h=h||d&&s-m-1>r&&" "!==e[m+1]}return p||h?n>9&&Ue(e)?5:i?2===a?5:2:h?4:3:!v||i||o(e)?2===a?5:2:1}function We(e,t,n,r,o){e.dump=function(){if(0===t.length)return 2===e.quotingType?'""':"''";if(!e.noCompatMode&&(-1!==Ie.indexOf(t)||Ne.test(t)))return 2===e.quotingType?'"'+t+'"':"'"+t+"'";var a=e.indent*Math.max(1,n),i=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-a),s=r||e.flowLevel>-1&&n>=e.flowLevel;switch(Ve(t,s,e.indent,i,(function(t){return function(e,t){var n,r;for(n=0,r=e.implicitTypes.length;n"+He(t,e.indent)+$e(Re(function(e,t){var n,r,o=/(\n+)([^\n]*)/g,a=(u=e.indexOf("\n"),u=-1!==u?u:e.length,o.lastIndex=u,Je(e.slice(0,u),t)),i="\n"===e[0]||" "===e[0];var u;for(;r=o.exec(e);){var s=r[1],c=r[2];n=" "===c[0],a+=s+(i||n||""===c?"":"\n")+Je(c,t),i=n}return a}(t,i),a));case 5:return'"'+function(e){for(var t,n="",r=0,o=0;o=65536?o+=2:o++)r=qe(e,o),!(t=Te[r])&&Be(r)?(n+=e[o],r>=65536&&(n+=e[o+1])):n+=t||Pe(r);return n}(t)+'"';default:throw new u("impossible error: invalid scalar style")}}()}function He(e,t){var n=Ue(e)?String(t):"",r="\n"===e[e.length-1];return n+(r&&("\n"===e[e.length-2]||"\n"===e)?"+":r?"":"-")+"\n"}function $e(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function Je(e,t){if(""===e||" "===e[0])return e;for(var n,r,o=/ [^ ]/g,a=0,i=0,u=0,s="";n=o.exec(e);)(u=n.index)-a>t&&(r=i>a?i:u,s+="\n"+e.slice(a,r),a=r+1),i=u;return s+="\n",e.length-a>t&&i>a?s+=e.slice(a,i)+"\n"+e.slice(i+1):s+=e.slice(a),s.slice(1)}function Ke(e,t,n,r){var o,a,i,u="",s=e.tag;for(o=0,a=n.length;o tag resolver accepts not "'+c+'" style');r=s.represent[c](t,c)}e.dump=r}return!0}return!1}function Ge(e,t,n,r,o,a,i){e.tag=null,e.dump=n,Ye(e,n,!1)||Ye(e,n,!0);var s,c=Oe.call(e.dump),l=r;r&&(r=e.flowLevel<0||e.flowLevel>t);var f,p,h="[object Object]"===c||"[object Array]"===c;if(h&&(p=-1!==(f=e.duplicates.indexOf(n))),(null!==e.tag&&"?"!==e.tag||p||2!==e.indent&&t>0)&&(o=!1),p&&e.usedDuplicates[f])e.dump="*ref_"+f;else{if(h&&p&&!e.usedDuplicates[f]&&(e.usedDuplicates[f]=!0),"[object Object]"===c)r&&0!==Object.keys(e.dump).length?(!function(e,t,n,r){var o,a,i,s,c,l,f="",p=e.tag,h=Object.keys(n);if(!0===e.sortKeys)h.sort();else if("function"==typeof e.sortKeys)h.sort(e.sortKeys);else if(e.sortKeys)throw new u("sortKeys must be a boolean or a function");for(o=0,a=h.length;o1024)&&(e.dump&&10===e.dump.charCodeAt(0)?l+="?":l+="? "),l+=e.dump,c&&(l+=De(e,t)),Ge(e,t+1,s,!0,c)&&(e.dump&&10===e.dump.charCodeAt(0)?l+=":":l+=": ",f+=l+=e.dump));e.tag=p,e.dump=f||"{}"}(e,t,e.dump,o),p&&(e.dump="&ref_"+f+e.dump)):(!function(e,t,n){var r,o,a,i,u,s="",c=e.tag,l=Object.keys(n);for(r=0,o=l.length;r1024&&(u+="? "),u+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Ge(e,t,i,!1,!1)&&(s+=u+=e.dump));e.tag=c,e.dump="{"+s+"}"}(e,t,e.dump),p&&(e.dump="&ref_"+f+" "+e.dump));else if("[object Array]"===c)r&&0!==e.dump.length?(e.noArrayIndent&&!i&&t>0?Ke(e,t-1,e.dump,o):Ke(e,t,e.dump,o),p&&(e.dump="&ref_"+f+e.dump)):(!function(e,t,n){var r,o,a,i="",u=e.tag;for(r=0,o=n.length;r",e.dump=s+" "+e.dump)}return!0}function Qe(e,t){var n,r,o=[],a=[];for(Ze(e,o,a),n=0,r=a.length;n=t.length?(e.target=void 0,{value:void 0,done:!0}):"keys"==n?{value:r,done:!1}:"values"==n?{value:t[r],done:!1}:{value:[r,t[r]],done:!1}}),"values"),a.Arguments=a.Array,o("keys"),o("values"),o("entries")},function(e,t){e.exports=function(e){return null!=e&&"object"==typeof e}},function(e,t,n){"use strict";(function(t){function n(e){return e instanceof t||e instanceof Date||e instanceof RegExp}function r(e){if(e instanceof t){var n=t.alloc?t.alloc(e.length):new t(e.length);return e.copy(n),n}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e);throw new Error("Unexpected situation")}function o(e){var t=[];return e.forEach((function(e,a){"object"==typeof e&&null!==e?Array.isArray(e)?t[a]=o(e):n(e)?t[a]=r(e):t[a]=i({},e):t[a]=e})),t}function a(e,t){return"__proto__"===t?void 0:e[t]}var i=e.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var e,t,u=arguments[0],s=Array.prototype.slice.call(arguments,1);return s.forEach((function(s){"object"!=typeof s||null===s||Array.isArray(s)||Object.keys(s).forEach((function(c){return t=a(u,c),(e=a(s,c))===u?void 0:"object"!=typeof e||null===e?void(u[c]=e):Array.isArray(e)?void(u[c]=o(e)):n(e)?void(u[c]=r(e)):"object"!=typeof t||null===t||Array.isArray(t)?void(u[c]=i({},e)):void(u[c]=i(t,e))}))})),u}}).call(this,n(132).Buffer)},function(e,t,n){e.exports=n(619)},function(e,t,n){"use strict";var r=n(946),o=n(947);function a(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}t.parse=b,t.resolve=function(e,t){return b(e,!1,!0).resolve(t)},t.resolveObject=function(e,t){return e?b(e,!1,!0).resolveObject(t):t},t.format=function(e){o.isString(e)&&(e=b(e));return e instanceof a?e.format():a.prototype.format.call(e)},t.Url=a;var i=/^([a-z0-9.+-]+:)/i,u=/:[0-9]*$/,s=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,c=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),l=["'"].concat(c),f=["%","/","?",";","#"].concat(l),p=["/","?","#"],h=/^[+a-z0-9A-Z_-]{0,63}$/,d=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},v={javascript:!0,"javascript:":!0},g={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},y=n(948);function b(e,t,n){if(e&&o.isObject(e)&&e instanceof a)return e;var r=new a;return r.parse(e,t,n),r}a.prototype.parse=function(e,t,n){if(!o.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var a=e.indexOf("?"),u=-1!==a&&a127?P+="x":P+=N[M];if(!P.match(h)){var D=T.slice(0,O),L=T.slice(O+1),B=N.match(d);B&&(D.push(B[1]),L.unshift(B[2])),L.length&&(b="/"+L.join(".")+b),this.hostname=D.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),j||(this.hostname=r.toASCII(this.hostname));var F=this.port?":"+this.port:"",z=this.hostname||"";this.host=z+F,this.href+=this.host,j&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==b[0]&&(b="/"+b))}if(!m[_])for(O=0,I=l.length;O0)&&n.host.split("@"))&&(n.auth=j.shift(),n.host=n.hostname=j.shift());return n.search=e.search,n.query=e.query,o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!E.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var k=E.slice(-1)[0],A=(n.host||e.host||E.length>1)&&("."===k||".."===k)||""===k,O=0,C=E.length;C>=0;C--)"."===(k=E[C])?E.splice(C,1):".."===k?(E.splice(C,1),O++):O&&(E.splice(C,1),O--);if(!x&&!_)for(;O--;O)E.unshift("..");!x||""===E[0]||E[0]&&"/"===E[0].charAt(0)||E.unshift(""),A&&"/"!==E.join("/").substr(-1)&&E.push("");var j,T=""===E[0]||E[0]&&"/"===E[0].charAt(0);S&&(n.hostname=n.host=T?"":E.length?E.shift():"",(j=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@"))&&(n.auth=j.shift(),n.host=n.hostname=j.shift()));return(x=x||n.host&&E.length)&&!T&&E.unshift(""),E.length?n.pathname=E.join("/"):(n.pathname=null,n.path=null),o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=e.auth||n.auth,n.slashes=n.slashes||e.slashes,n.href=n.format(),n},a.prototype.parseHost=function(){var e=this.host,t=u.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},function(e,t,n){"use strict";n.r(t),n.d(t,"SHOW_AUTH_POPUP",(function(){return h})),n.d(t,"AUTHORIZE",(function(){return d})),n.d(t,"LOGOUT",(function(){return m})),n.d(t,"PRE_AUTHORIZE_OAUTH2",(function(){return v})),n.d(t,"AUTHORIZE_OAUTH2",(function(){return g})),n.d(t,"VALIDATE",(function(){return y})),n.d(t,"CONFIGURE_AUTH",(function(){return b})),n.d(t,"RESTORE_AUTHORIZATION",(function(){return w})),n.d(t,"showDefinitions",(function(){return x})),n.d(t,"authorize",(function(){return _})),n.d(t,"authorizeWithPersistOption",(function(){return E})),n.d(t,"logout",(function(){return S})),n.d(t,"logoutWithPersistOption",(function(){return k})),n.d(t,"preAuthorizeImplicit",(function(){return A})),n.d(t,"authorizeOauth2",(function(){return O})),n.d(t,"authorizeOauth2WithPersistOption",(function(){return C})),n.d(t,"authorizePassword",(function(){return j})),n.d(t,"authorizeApplication",(function(){return T})),n.d(t,"authorizeAccessCodeWithFormParams",(function(){return I})),n.d(t,"authorizeAccessCodeWithBasicAuthentication",(function(){return N})),n.d(t,"authorizeRequest",(function(){return P})),n.d(t,"configureAuth",(function(){return M})),n.d(t,"restoreAuthorization",(function(){return R})),n.d(t,"persistAuthorizationIfNeeded",(function(){return D}));var r=n(19),o=n.n(r),a=n(32),i=n.n(a),u=n(21),s=n.n(u),c=n(89),l=n.n(c),f=n(26),p=n(5),h="show_popup",d="authorize",m="logout",v="pre_authorize_oauth2",g="authorize_oauth2",y="validate",b="configure_auth",w="restore_authorization";function x(e){return{type:h,payload:e}}function _(e){return{type:d,payload:e}}var E=function(e){return function(t){var n=t.authActions;n.authorize(e),n.persistAuthorizationIfNeeded()}};function S(e){return{type:m,payload:e}}var k=function(e){return function(t){var n=t.authActions;n.logout(e),n.persistAuthorizationIfNeeded()}},A=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,a=e.token,u=e.isValid,s=o.schema,c=o.name,l=s.get("flow");delete f.a.swaggerUIRedirectOauth2,"accessCode"===l||u||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),a.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:i()(a)}):n.authorizeOauth2WithPersistOption({auth:o,token:a})}};function O(e){return{type:g,payload:e}}var C=function(e){return function(t){var n=t.authActions;n.authorizeOauth2(e),n.persistAuthorizationIfNeeded()}},j=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.name,a=e.username,i=e.password,u=e.passwordType,c=e.clientId,l=e.clientSecret,f={grant_type:"password",scope:e.scopes.join(" "),username:a,password:i},h={};switch(u){case"request-body":!function(e,t,n){t&&s()(e,{client_id:t});n&&s()(e,{client_secret:n})}(f,c,l);break;case"basic":h.Authorization="Basic "+Object(p.a)(c+":"+l);break;default:console.warn("Warning: invalid passwordType ".concat(u," was passed, not including client id and secret"))}return n.authorizeRequest({body:Object(p.b)(f),url:r.get("tokenUrl"),name:o,headers:h,query:{},auth:e})}};var T=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,a=e.name,i=e.clientId,u=e.clientSecret,s={Authorization:"Basic "+Object(p.a)(i+":"+u)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:Object(p.b)(c),name:a,url:r.get("tokenUrl"),auth:e,headers:s})}},I=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,a=t.name,i=t.clientId,u=t.clientSecret,s=t.codeVerifier,c={grant_type:"authorization_code",code:t.code,client_id:i,client_secret:u,redirect_uri:n,code_verifier:s};return r.authorizeRequest({body:Object(p.b)(c),name:a,url:o.get("tokenUrl"),auth:t})}},N=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,a=t.name,i=t.clientId,u=t.clientSecret,s=t.codeVerifier,c={Authorization:"Basic "+Object(p.a)(i+":"+u)},l={grant_type:"authorization_code",code:t.code,client_id:i,redirect_uri:n,code_verifier:s};return r.authorizeRequest({body:Object(p.b)(l),name:a,url:o.get("tokenUrl"),auth:t,headers:c})}},P=function(e){return function(t){var n,r=t.fn,a=t.getConfigs,u=t.authActions,c=t.errActions,f=t.oas3Selectors,p=t.specSelectors,h=t.authSelectors,d=e.body,m=e.query,v=void 0===m?{}:m,g=e.headers,y=void 0===g?{}:g,b=e.name,w=e.url,x=e.auth,_=(h.getConfigs()||{}).additionalQueryStringParams;if(p.isOAS3()){var E=f.serverEffectiveValue(f.selectedServer());n=l()(w,E,!0)}else n=l()(w,p.url(),!0);"object"===o()(_)&&(n.query=s()({},n.query,_));var S=n.toString(),k=s()({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},y);r.fetch({url:S,method:"post",headers:k,query:v,body:d,requestInterceptor:a().requestInterceptor,responseInterceptor:a().responseInterceptor}).then((function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?c.newAuthErr({authId:b,level:"error",source:"auth",message:i()(t)}):u.authorizeOauth2WithPersistOption({auth:x,token:t}):c.newAuthErr({authId:b,level:"error",source:"auth",message:e.statusText})})).catch((function(e){var t=new Error(e).message;if(e.response&&e.response.data){var n=e.response.data;try{var r="string"==typeof n?JSON.parse(n):n;r.error&&(t+=", error: ".concat(r.error)),r.error_description&&(t+=", description: ".concat(r.error_description))}catch(e){}}c.newAuthErr({authId:b,level:"error",source:"auth",message:t})}))}};function M(e){return{type:b,payload:e}}function R(e){return{type:w,payload:e}}var D=function(){return function(e){var t=e.authSelectors;if((0,e.getConfigs)().persistAuthorization){var n=t.authorized();localStorage.setItem("authorized",i()(n.toJS()))}}}},function(e,t,n){var r=n(919);e.exports=function(e){for(var t=1;tS;S++)if((h||S in x)&&(b=_(y=x[S],S,w),e))if(t)A[S]=b;else if(b)switch(e){case 3:return!0;case 5:return y;case 6:return S;case 2:c(A,y)}else switch(e){case 4:return!1;case 7:c(A,y)}return f?-1:o||l?l:A}};e.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},function(e,t,n){"use strict";n.r(t),n.d(t,"lastError",(function(){return M})),n.d(t,"url",(function(){return R})),n.d(t,"specStr",(function(){return D})),n.d(t,"specSource",(function(){return L})),n.d(t,"specJson",(function(){return B})),n.d(t,"specResolved",(function(){return F})),n.d(t,"specResolvedSubtree",(function(){return z})),n.d(t,"specJsonWithResolvedSubtrees",(function(){return U})),n.d(t,"spec",(function(){return V})),n.d(t,"isOAS3",(function(){return W})),n.d(t,"info",(function(){return H})),n.d(t,"externalDocs",(function(){return $})),n.d(t,"version",(function(){return J})),n.d(t,"semver",(function(){return K})),n.d(t,"paths",(function(){return Y})),n.d(t,"operations",(function(){return G})),n.d(t,"consumes",(function(){return Q})),n.d(t,"produces",(function(){return Z})),n.d(t,"security",(function(){return X})),n.d(t,"securityDefinitions",(function(){return ee})),n.d(t,"findDefinition",(function(){return te})),n.d(t,"definitions",(function(){return ne})),n.d(t,"basePath",(function(){return re})),n.d(t,"host",(function(){return oe})),n.d(t,"schemes",(function(){return ae})),n.d(t,"operationsWithRootInherited",(function(){return ie})),n.d(t,"tags",(function(){return ue})),n.d(t,"tagDetails",(function(){return se})),n.d(t,"operationsWithTags",(function(){return ce})),n.d(t,"taggedOperations",(function(){return le})),n.d(t,"responses",(function(){return fe})),n.d(t,"requests",(function(){return pe})),n.d(t,"mutatedRequests",(function(){return he})),n.d(t,"responseFor",(function(){return de})),n.d(t,"requestFor",(function(){return me})),n.d(t,"mutatedRequestFor",(function(){return ve})),n.d(t,"allowTryItOutFor",(function(){return ge})),n.d(t,"parameterWithMetaByIdentity",(function(){return ye})),n.d(t,"parameterInclusionSettingFor",(function(){return be})),n.d(t,"parameterWithMeta",(function(){return we})),n.d(t,"operationWithMeta",(function(){return xe})),n.d(t,"getParameter",(function(){return _e})),n.d(t,"hasHost",(function(){return Ee})),n.d(t,"parameterValues",(function(){return Se})),n.d(t,"parametersIncludeIn",(function(){return ke})),n.d(t,"parametersIncludeType",(function(){return Ae})),n.d(t,"contentTypeValues",(function(){return Oe})),n.d(t,"currentProducesFor",(function(){return Ce})),n.d(t,"producesOptionsFor",(function(){return je})),n.d(t,"consumesOptionsFor",(function(){return Te})),n.d(t,"operationScheme",(function(){return Ie})),n.d(t,"canExecuteScheme",(function(){return Ne})),n.d(t,"validateBeforeExecute",(function(){return Pe})),n.d(t,"getOAS3RequiredRequestBodyContentType",(function(){return Me})),n.d(t,"isMediaTypeSchemaPropertiesEqual",(function(){return Re}));var r=n(13),o=n.n(r),a=n(14),i=n.n(a),u=n(2),s=n.n(u),c=n(20),l=n.n(c),f=n(23),p=n.n(f),h=n(18),d=n.n(h),m=n(4),v=n.n(m),g=n(12),y=n.n(g),b=n(56),w=n.n(b),x=n(30),_=n.n(x),E=n(196),S=n.n(E),k=n(71),A=n.n(k),O=n(24),C=n.n(O),j=n(16),T=n(5),I=n(1),N=["get","put","post","delete","options","head","patch","trace"],P=function(e){return e||Object(I.Map)()},M=Object(j.a)(P,(function(e){return e.get("lastError")})),R=Object(j.a)(P,(function(e){return e.get("url")})),D=Object(j.a)(P,(function(e){return e.get("spec")||""})),L=Object(j.a)(P,(function(e){return e.get("specSource")||"not-editor"})),B=Object(j.a)(P,(function(e){return e.get("json",Object(I.Map)())})),F=Object(j.a)(P,(function(e){return e.get("resolved",Object(I.Map)())})),z=function(e,t){var n;return e.getIn(s()(n=["resolvedSubtrees"]).call(n,i()(t)),void 0)},q=function e(t,n){return I.Map.isMap(t)&&I.Map.isMap(n)?n.get("$$ref")?n:Object(I.OrderedMap)().mergeWith(e,t,n):n},U=Object(j.a)(P,(function(e){return Object(I.OrderedMap)().mergeWith(q,e.get("json"),e.get("resolvedSubtrees"))})),V=function(e){return B(e)},W=Object(j.a)(V,(function(){return!1})),H=Object(j.a)(V,(function(e){return De(e&&e.get("info"))})),$=Object(j.a)(V,(function(e){return De(e&&e.get("externalDocs"))})),J=Object(j.a)(H,(function(e){return e&&e.get("version")})),K=Object(j.a)(J,(function(e){var t;return l()(t=/v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(e)).call(t,1)})),Y=Object(j.a)(U,(function(e){return e.get("paths")})),G=Object(j.a)(Y,(function(e){if(!e||e.size<1)return Object(I.List)();var t=Object(I.List)();return e&&p()(e)?(p()(e).call(e,(function(e,n){if(!e||!p()(e))return{};p()(e).call(e,(function(e,r){var o;d()(N).call(N,r)<0||(t=t.push(Object(I.fromJS)({path:n,method:r,operation:e,id:s()(o="".concat(r,"-")).call(o,n)})))}))})),t):Object(I.List)()})),Q=Object(j.a)(V,(function(e){return Object(I.Set)(e.get("consumes"))})),Z=Object(j.a)(V,(function(e){return Object(I.Set)(e.get("produces"))})),X=Object(j.a)(V,(function(e){return e.get("security",Object(I.List)())})),ee=Object(j.a)(V,(function(e){return e.get("securityDefinitions")})),te=function(e,t){var n=e.getIn(["resolvedSubtrees","definitions",t],null),r=e.getIn(["json","definitions",t],null);return n||r||null},ne=Object(j.a)(V,(function(e){var t=e.get("definitions");return I.Map.isMap(t)?t:Object(I.Map)()})),re=Object(j.a)(V,(function(e){return e.get("basePath")})),oe=Object(j.a)(V,(function(e){return e.get("host")})),ae=Object(j.a)(V,(function(e){return e.get("schemes",Object(I.Map)())})),ie=Object(j.a)(G,Q,Z,(function(e,t,n){return v()(e).call(e,(function(e){return e.update("operation",(function(e){if(e){if(!I.Map.isMap(e))return;return e.withMutations((function(e){return e.get("consumes")||e.update("consumes",(function(e){return Object(I.Set)(e).merge(t)})),e.get("produces")||e.update("produces",(function(e){return Object(I.Set)(e).merge(n)})),e}))}return Object(I.Map)()}))}))})),ue=Object(j.a)(V,(function(e){var t=e.get("tags",Object(I.List)());return I.List.isList(t)?y()(t).call(t,(function(e){return I.Map.isMap(e)})):Object(I.List)()})),se=function(e,t){var n,r=ue(e)||Object(I.List)();return w()(n=y()(r).call(r,I.Map.isMap)).call(n,(function(e){return e.get("name")===t}),Object(I.Map)())},ce=Object(j.a)(ie,ue,(function(e,t){return _()(e).call(e,(function(e,t){var n=Object(I.Set)(t.getIn(["operation","tags"]));return n.count()<1?e.update("default",Object(I.List)(),(function(e){return e.push(t)})):_()(n).call(n,(function(e,n){return e.update(n,Object(I.List)(),(function(e){return e.push(t)}))}),e)}),_()(t).call(t,(function(e,t){return e.set(t.get("name"),Object(I.List)())}),Object(I.OrderedMap)()))})),le=function(e){return function(t){var n,r=(0,t.getConfigs)(),o=r.tagsSorter,a=r.operationsSorter;return v()(n=ce(e).sortBy((function(e,t){return t}),(function(e,t){var n="function"==typeof o?o:T.H.tagsSorter[o];return n?n(e,t):null}))).call(n,(function(t,n){var r="function"==typeof a?a:T.H.operationsSorter[a],o=r?S()(t).call(t,r):t;return Object(I.Map)({tagDetails:se(e,n),operations:o})}))}},fe=Object(j.a)(P,(function(e){return e.get("responses",Object(I.Map)())})),pe=Object(j.a)(P,(function(e){return e.get("requests",Object(I.Map)())})),he=Object(j.a)(P,(function(e){return e.get("mutatedRequests",Object(I.Map)())})),de=function(e,t,n){return fe(e).getIn([t,n],null)},me=function(e,t,n){return pe(e).getIn([t,n],null)},ve=function(e,t,n){return he(e).getIn([t,n],null)},ge=function(){return!0},ye=function(e,t,n){var r,o,a=U(e).getIn(s()(r=["paths"]).call(r,i()(t),["parameters"]),Object(I.OrderedMap)()),u=e.getIn(s()(o=["meta","paths"]).call(o,i()(t),["parameters"]),Object(I.OrderedMap)()),c=v()(a).call(a,(function(e){var t,r,o,a=u.get(s()(t="".concat(n.get("in"),".")).call(t,n.get("name"))),i=u.get(s()(r=s()(o="".concat(n.get("in"),".")).call(o,n.get("name"),".hash-")).call(r,n.hashCode()));return Object(I.OrderedMap)().merge(e,a,i)}));return w()(c).call(c,(function(e){return e.get("in")===n.get("in")&&e.get("name")===n.get("name")}),Object(I.OrderedMap)())},be=function(e,t,n,r){var o,a,u=s()(o="".concat(r,".")).call(o,n);return e.getIn(s()(a=["meta","paths"]).call(a,i()(t),["parameter_inclusions",u]),!1)},we=function(e,t,n,r){var o,a=U(e).getIn(s()(o=["paths"]).call(o,i()(t),["parameters"]),Object(I.OrderedMap)()),u=w()(a).call(a,(function(e){return e.get("in")===r&&e.get("name")===n}),Object(I.OrderedMap)());return ye(e,t,u)},xe=function(e,t,n){var r,o=U(e).getIn(["paths",t,n],Object(I.OrderedMap)()),a=e.getIn(["meta","paths",t,n],Object(I.OrderedMap)()),i=v()(r=o.get("parameters",Object(I.List)())).call(r,(function(r){return ye(e,[t,n],r)}));return Object(I.OrderedMap)().merge(o,a).set("parameters",i)};function _e(e,t,n,r){var o;t=t||[];var a=e.getIn(s()(o=["meta","paths"]).call(o,i()(t),["parameters"]),Object(I.fromJS)([]));return w()(a).call(a,(function(e){return I.Map.isMap(e)&&e.get("name")===n&&e.get("in")===r}))||Object(I.Map)()}var Ee=Object(j.a)(V,(function(e){var t=e.get("host");return"string"==typeof t&&t.length>0&&"/"!==t[0]}));function Se(e,t,n){var r;t=t||[];var o=xe.apply(void 0,s()(r=[e]).call(r,i()(t))).get("parameters",Object(I.List)());return _()(o).call(o,(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(Object(T.A)(t,{allowHashes:!1}),r)}),Object(I.fromJS)({}))}function ke(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(I.List.isList(e))return A()(e).call(e,(function(e){return I.Map.isMap(e)&&e.get("in")===t}))}function Ae(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(I.List.isList(e))return A()(e).call(e,(function(e){return I.Map.isMap(e)&&e.get("type")===t}))}function Oe(e,t){var n,r;t=t||[];var o=U(e).getIn(s()(n=["paths"]).call(n,i()(t)),Object(I.fromJS)({})),a=e.getIn(s()(r=["meta","paths"]).call(r,i()(t)),Object(I.fromJS)({})),u=Ce(e,t),c=o.get("parameters")||new I.List,l=a.get("consumes_value")?a.get("consumes_value"):Ae(c,"file")?"multipart/form-data":Ae(c,"formData")?"application/x-www-form-urlencoded":void 0;return Object(I.fromJS)({requestContentType:l,responseContentType:u})}function Ce(e,t){var n,r;t=t||[];var o=U(e).getIn(s()(n=["paths"]).call(n,i()(t)),null);if(null!==o){var a=e.getIn(s()(r=["meta","paths"]).call(r,i()(t),["produces_value"]),null),u=o.getIn(["produces",0],null);return a||u||"application/json"}}function je(e,t){var n;t=t||[];var r=U(e),a=r.getIn(s()(n=["paths"]).call(n,i()(t)),null);if(null!==a){var u=t,c=o()(u,1)[0],l=a.get("produces",null),f=r.getIn(["paths",c,"produces"],null),p=r.getIn(["produces"],null);return l||f||p}}function Te(e,t){var n;t=t||[];var r=U(e),a=r.getIn(s()(n=["paths"]).call(n,i()(t)),null);if(null!==a){var u=t,c=o()(u,1)[0],l=a.get("consumes",null),f=r.getIn(["paths",c,"consumes"],null),p=r.getIn(["consumes"],null);return l||f||p}}var Ie=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),o=C()(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||o||""},Ne=function(e,t,n){var r;return d()(r=["http","https"]).call(r,Ie(e,t,n))>-1},Pe=function(e,t){var n;t=t||[];var r=e.getIn(s()(n=["meta","paths"]).call(n,i()(t),["parameters"]),Object(I.fromJS)([])),o=!0;return p()(r).call(r,(function(e){var t=e.get("errors");t&&t.count()&&(o=!1)})),o},Me=function(e,t){var n,r,o={requestBody:!1,requestContentType:{}},a=e.getIn(s()(n=["resolvedSubtrees","paths"]).call(n,i()(t),["requestBody"]),Object(I.fromJS)([]));return a.size<1||(a.getIn(["required"])&&(o.requestBody=a.getIn(["required"])),p()(r=a.getIn(["content"]).entrySeq()).call(r,(function(e){var t=e[0];if(e[1].getIn(["schema","required"])){var n=e[1].getIn(["schema","required"]).toJS();o.requestContentType[t]=n}}))),o},Re=function(e,t,n,r){var o;if((n||r)&&n===r)return!0;var a=e.getIn(s()(o=["resolvedSubtrees","paths"]).call(o,i()(t),["requestBody","content"]),Object(I.fromJS)([]));if(a.size<2||!n||!r)return!1;var u=a.getIn([n,"schema","properties"],Object(I.fromJS)([])),c=a.getIn([r,"schema","properties"],Object(I.fromJS)([]));return!!u.equals(c)};function De(e){return I.Map.isMap(e)?e:new I.Map}},function(e,t,n){"use strict";(function(t){var r=n(847),o=n(848),a=/^[A-Za-z][A-Za-z0-9+-.]*:\/\//,i=/^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i,u=/^[a-zA-Z]:/,s=new RegExp("^[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]+");function c(e){return(e||"").toString().replace(s,"")}var l=[["#","hash"],["?","query"],function(e,t){return h(t.protocol)?e.replace(/\\/g,"/"):e},["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d+)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],f={hash:1,query:1};function p(e){var n,r=("undefined"!=typeof window?window:void 0!==t?t:"undefined"!=typeof self?self:{}).location||{},o={},i=typeof(e=e||r);if("blob:"===e.protocol)o=new m(unescape(e.pathname),{});else if("string"===i)for(n in o=new m(e,{}),f)delete o[n];else if("object"===i){for(n in e)n in f||(o[n]=e[n]);void 0===o.slashes&&(o.slashes=a.test(e.href))}return o}function h(e){return"file:"===e||"ftp:"===e||"http:"===e||"https:"===e||"ws:"===e||"wss:"===e}function d(e,t){e=c(e),t=t||{};var n,r=i.exec(e),o=r[1]?r[1].toLowerCase():"",a=!!r[2],u=!!r[3],s=0;return a?u?(n=r[2]+r[3]+r[4],s=r[2].length+r[3].length):(n=r[2]+r[4],s=r[2].length):u?(n=r[3]+r[4],s=r[3].length):n=r[4],"file:"===o?s>=2&&(n=n.slice(2)):h(o)?n=r[4]:o?a&&(n=n.slice(2)):s>=2&&h(t.protocol)&&(n=r[4]),{protocol:o,slashes:a||h(o),slashesCount:s,rest:n}}function m(e,t,n){if(e=c(e),!(this instanceof m))return new m(e,t,n);var a,i,s,f,v,g,y=l.slice(),b=typeof t,w=this,x=0;for("object"!==b&&"string"!==b&&(n=t,t=null),n&&"function"!=typeof n&&(n=o.parse),a=!(i=d(e||"",t=p(t))).protocol&&!i.slashes,w.slashes=i.slashes||a&&t.slashes,w.protocol=i.protocol||t.protocol||"",e=i.rest,("file:"===i.protocol&&(2!==i.slashesCount||u.test(e))||!i.slashes&&(i.protocol||i.slashesCount<2||!h(w.protocol)))&&(y[3]=[/(.*)/,"pathname"]);x=4?[t[0],t[1],t[2],t[3],"".concat(t[0],".").concat(t[1]),"".concat(t[0],".").concat(t[2]),"".concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[0]),"".concat(t[1],".").concat(t[2]),"".concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[1]),"".concat(t[2],".").concat(t[3]),"".concat(t[3],".").concat(t[0]),"".concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[0]),"".concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[1],".").concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[2],".").concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[3],".").concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[2],".").concat(t[1],".").concat(t[0])]:void 0),g[r]}function b(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=e.filter((function(e){return"token"!==e})),o=y(r);return o.reduce((function(e,t){return p()({},e,n[t])}),t)}function w(e){return e.join(" ")}function x(e){var t=e.node,n=e.stylesheet,r=e.style,o=void 0===r?{}:r,a=e.useInlineStyles,i=e.key,u=t.properties,s=t.type,c=t.tagName,l=t.value;if("text"===s)return l;if(c){var f,h=function(e,t){var n=0;return function(r){return n+=1,r.map((function(r,o){return x({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(o)})}))}}(n,a);if(a){var m=Object.keys(n).reduce((function(e,t){return t.split(".").forEach((function(t){e.includes(t)||e.push(t)})),e}),[]),g=u.className&&u.className.includes("token")?["token"]:[],y=u.className&&g.concat(u.className.filter((function(e){return!m.includes(e)})));f=p()({},u,{className:w(y)||void 0,style:b(u.className,Object.assign({},u.style,o),n)})}else f=p()({},u,{className:w(u.className)});var _=h(t.children);return d.a.createElement(c,v()({key:i},f),_)}}var _=/\n/g;function E(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,o=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,i=void 0===a?{}:a,u=e.startingLineNumber;return d.a.createElement("code",{style:Object.assign({},n,o)},function(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map((function(e,t){var o=t+n;return d.a.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(o):r},"".concat(o,"\n"))}))}({lines:t.replace(/\n$/,"").split("\n"),style:i,startingLineNumber:u}))}function S(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function k(e,t,n){var r,o={display:"inline-block",minWidth:(r=n,"".concat(r.toString().length,".25em")),paddingRight:"1em",textAlign:"right",userSelect:"none"},a="function"==typeof e?e(t):e;return p()({},o,a)}function A(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,o=e.largestLineNumber,a=e.showInlineLineNumbers,i=e.lineProps,u=void 0===i?{}:i,s=e.className,c=void 0===s?[]:s,l=e.showLineNumbers,f=e.wrapLongLines,h="function"==typeof u?u(n):u;if(h.className=c,n&&a){var d=k(r,n,o);t.unshift(S(n,d))}return f&l&&(h.style=p()({},h.style,{display:"flex"})),{type:"element",tagName:"span",properties:h,children:t}}function O(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return A({children:e,lineNumber:t,lineNumberStyle:u,largestLineNumber:i,showInlineLineNumbers:o,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:s})}function m(e,t){if(r&&t&&o){var n=k(u,t,i);e.unshift(S(t,n))}return e}function v(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?d(e,n,r):m(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(t.match(_)){var n=t.split("\n");n.forEach((function(t,o){var i=r&&f.length+a,u={type:"text",value:"".concat(t,"\n")};if(0===o){var s=v(l.slice(p+1,h).concat(A({children:[u],className:e.properties.className})),i);f.push(s)}else if(o===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var c=A({children:[{type:"text",value:"".concat(t)}],className:e.properties.className});l.splice(h+1,0,c)}else{var d=v([u],i,e.properties.className);f.push(d)}}else{var m=v([u],i,e.properties.className);f.push(m)}})),p=h}h++};h .hljs-title":{color:"#88C0D0"},"hljs-keyword":{color:"#81A1C1"},"hljs-literal":{color:"#81A1C1"},"hljs-symbol":{color:"#81A1C1"},"hljs-number":{color:"#B48EAD"},"hljs-regexp":{color:"#EBCB8B"},"hljs-string":{color:"#A3BE8C"},"hljs-title":{color:"#8FBCBB"},"hljs-params":{color:"#D8DEE9"},"hljs-bullet":{color:"#81A1C1"},"hljs-code":{color:"#8FBCBB"},"hljs-emphasis":{fontStyle:"italic"},"hljs-formula":{color:"#8FBCBB"},"hljs-strong":{fontWeight:"bold"},"hljs-link:hover":{textDecoration:"underline"},"hljs-quote":{color:"#4C566A"},"hljs-comment":{color:"#4C566A"},"hljs-doctag":{color:"#8FBCBB"},"hljs-meta":{color:"#5E81AC"},"hljs-meta-keyword":{color:"#5E81AC"},"hljs-meta-string":{color:"#A3BE8C"},"hljs-attr":{color:"#8FBCBB"},"hljs-attribute":{color:"#D8DEE9"},"hljs-builtin-name":{color:"#81A1C1"},"hljs-name":{color:"#81A1C1"},"hljs-section":{color:"#88C0D0"},"hljs-tag":{color:"#81A1C1"},"hljs-variable":{color:"#D8DEE9"},"hljs-template-variable":{color:"#D8DEE9"},"hljs-template-tag":{color:"#5E81AC"},"abnf .hljs-attribute":{color:"#88C0D0"},"abnf .hljs-symbol":{color:"#EBCB8B"},"apache .hljs-attribute":{color:"#88C0D0"},"apache .hljs-section":{color:"#81A1C1"},"arduino .hljs-built_in":{color:"#88C0D0"},"aspectj .hljs-meta":{color:"#D08770"},"aspectj > .hljs-title":{color:"#88C0D0"},"bnf .hljs-attribute":{color:"#8FBCBB"},"clojure .hljs-name":{color:"#88C0D0"},"clojure .hljs-symbol":{color:"#EBCB8B"},"coq .hljs-built_in":{color:"#88C0D0"},"cpp .hljs-meta-string":{color:"#8FBCBB"},"css .hljs-built_in":{color:"#88C0D0"},"css .hljs-keyword":{color:"#D08770"},"diff .hljs-meta":{color:"#8FBCBB"},"ebnf .hljs-attribute":{color:"#8FBCBB"},"glsl .hljs-built_in":{color:"#88C0D0"},"groovy .hljs-meta:not(:first-child)":{color:"#D08770"},"haxe .hljs-meta":{color:"#D08770"},"java .hljs-meta":{color:"#D08770"},"ldif .hljs-attribute":{color:"#8FBCBB"},"lisp .hljs-name":{color:"#88C0D0"},"lua .hljs-built_in":{color:"#88C0D0"},"moonscript .hljs-built_in":{color:"#88C0D0"},"nginx .hljs-attribute":{color:"#88C0D0"},"nginx .hljs-section":{color:"#5E81AC"},"pf .hljs-built_in":{color:"#88C0D0"},"processing .hljs-built_in":{color:"#88C0D0"},"scss .hljs-keyword":{color:"#81A1C1"},"stylus .hljs-keyword":{color:"#81A1C1"},"swift .hljs-meta":{color:"#D08770"},"vim .hljs-built_in":{color:"#88C0D0",fontStyle:"italic"},"yaml .hljs-meta":{color:"#D08770"}},obsidian:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#282b2e",color:"#e0e2e4"},"hljs-keyword":{color:"#93c763",fontWeight:"bold"},"hljs-selector-tag":{color:"#93c763",fontWeight:"bold"},"hljs-literal":{color:"#93c763",fontWeight:"bold"},"hljs-selector-id":{color:"#93c763"},"hljs-number":{color:"#ffcd22"},"hljs-attribute":{color:"#668bb0"},"hljs-code":{color:"white"},"hljs-class .hljs-title":{color:"white"},"hljs-section":{color:"white",fontWeight:"bold"},"hljs-regexp":{color:"#d39745"},"hljs-link":{color:"#d39745"},"hljs-meta":{color:"#557182"},"hljs-tag":{color:"#8cbbad"},"hljs-name":{color:"#8cbbad",fontWeight:"bold"},"hljs-bullet":{color:"#8cbbad"},"hljs-subst":{color:"#8cbbad"},"hljs-emphasis":{color:"#8cbbad"},"hljs-type":{color:"#8cbbad",fontWeight:"bold"},"hljs-built_in":{color:"#8cbbad"},"hljs-selector-attr":{color:"#8cbbad"},"hljs-selector-pseudo":{color:"#8cbbad"},"hljs-addition":{color:"#8cbbad"},"hljs-variable":{color:"#8cbbad"},"hljs-template-tag":{color:"#8cbbad"},"hljs-template-variable":{color:"#8cbbad"},"hljs-string":{color:"#ec7600"},"hljs-symbol":{color:"#ec7600"},"hljs-comment":{color:"#818e96"},"hljs-quote":{color:"#818e96"},"hljs-deletion":{color:"#818e96"},"hljs-selector-class":{color:"#A082BD"},"hljs-doctag":{fontWeight:"bold"},"hljs-title":{fontWeight:"bold"},"hljs-strong":{fontWeight:"bold"}},"tomorrow-night":{"hljs-comment":{color:"#969896"},"hljs-quote":{color:"#969896"},"hljs-variable":{color:"#cc6666"},"hljs-template-variable":{color:"#cc6666"},"hljs-tag":{color:"#cc6666"},"hljs-name":{color:"#cc6666"},"hljs-selector-id":{color:"#cc6666"},"hljs-selector-class":{color:"#cc6666"},"hljs-regexp":{color:"#cc6666"},"hljs-deletion":{color:"#cc6666"},"hljs-number":{color:"#de935f"},"hljs-built_in":{color:"#de935f"},"hljs-builtin-name":{color:"#de935f"},"hljs-literal":{color:"#de935f"},"hljs-type":{color:"#de935f"},"hljs-params":{color:"#de935f"},"hljs-meta":{color:"#de935f"},"hljs-link":{color:"#de935f"},"hljs-attribute":{color:"#f0c674"},"hljs-string":{color:"#b5bd68"},"hljs-symbol":{color:"#b5bd68"},"hljs-bullet":{color:"#b5bd68"},"hljs-addition":{color:"#b5bd68"},"hljs-title":{color:"#81a2be"},"hljs-section":{color:"#81a2be"},"hljs-keyword":{color:"#b294bb"},"hljs-selector-tag":{color:"#b294bb"},hljs:{display:"block",overflowX:"auto",background:"#1d1f21",color:"#c5c8c6",padding:"0.5em"},"hljs-emphasis":{fontStyle:"italic"},"hljs-strong":{fontWeight:"bold"}}},X=o()(Z),ee=function(e){return i()(X).call(X,e)?Z[e]:(console.warn("Request style '".concat(e,"' is not available, returning default instead")),Q)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.File=t.Blob=t.FormData=void 0;const r="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:window;t.FormData=r.FormData,t.Blob=r.Blob,t.File=r.File},function(e,t){var n=Function.prototype,r=n.apply,o=n.bind,a=n.call;e.exports="object"==typeof Reflect&&Reflect.apply||(o?a.bind(r):function(){return a.apply(r,arguments)})},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(58);e.exports=r("navigator","userAgent")||""},function(e,t){e.exports=!0},function(e,t){},function(e,t,n){var r,o=n(51),a=n(218),i=n(221),u=n(150),s=n(335),c=n(214),l=n(173),f=l("IE_PROTO"),p=function(){},h=function(e){return" + + + \ No newline at end of file diff --git a/src/Surging.Web/Properties/PublishProfiles/FolderProfile.pubxml b/src/Surging.Web/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 000000000..acc147b73 --- /dev/null +++ b/src/Surging.Web/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,13 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp2.2 + bin\Release\netcoreapp2.2\publish\ + + \ No newline at end of file diff --git a/src/Surging.Web/Surging.Web.csproj b/src/Surging.Web/Surging.Web.csproj new file mode 100644 index 000000000..1421b7fa7 --- /dev/null +++ b/src/Surging.Web/Surging.Web.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/src/Surging.Web/default.htm b/src/Surging.Web/default.htm new file mode 100644 index 000000000..7f1755305 --- /dev/null +++ b/src/Surging.Web/default.htm @@ -0,0 +1,409 @@ + + + + + + + Echo bot with counter sample + + + + + +
+
+
+
MicroService Engine Surging
+
+
+
+
+
Your engine is ready!
+
You can provide MQTT, HTTP, TCP, Websocket protocols by loading business modules into the engine.
+ +
+
+
+ + + + diff --git a/src/Surging.Web/f5.htm b/src/Surging.Web/f5.htm new file mode 100644 index 000000000..0125eb6e4 --- /dev/null +++ b/src/Surging.Web/f5.htm @@ -0,0 +1,290 @@ + + + + + + + + + + +
+

How to using a engine

+
+
+
+
+
+
Protocol:
+
+ MQTT protocol using the + DotNetty + +
+ HTTP protocol using the + KestrelHttpServer + +
+
+
+
+
+
+
+
+
Component:
+
+ +
+
+
+
+
+
+
+
+
Test:
+
+ Test using the swagger +
+
+
+
+
+
+
+
+
Publish:
+
+ +
+
+
+
+
+
+
+
+
Deploy:
+
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/src/Surging.Web/js/jsmpeg.min.js b/src/Surging.Web/js/jsmpeg.min.js new file mode 100644 index 000000000..4d3238014 --- /dev/null +++ b/src/Surging.Web/js/jsmpeg.min.js @@ -0,0 +1,5 @@ +var JSMpeg={Player:null,VideoElement:null,BitBuffer:null,Source:{},Demuxer:{},Decoder:{},Renderer:{},AudioOutput:{},Now:function(){return window.performance?window.performance.now()/1e3:Date.now()/1e3},CreateVideoElements:function(){var elements=document.querySelectorAll(".jsmpeg");for(var i=0;i'+''+''+"";VideoElement.UNMUTE_BUTTON=''+''+''+''+''+""+"";return VideoElement}();JSMpeg.Player=function(){"use strict";var Player=function(url,options){this.options=options||{};if(options.source){this.source=new options.source(url,options);options.streaming=!!this.source.streaming}else if(url.match(/^wss?:\/\//)){this.source=new JSMpeg.Source.WebSocket(url,options);options.streaming=true}else if(options.progressive!==false){this.source=new JSMpeg.Source.AjaxProgressive(url,options);options.streaming=false}else{this.source=new JSMpeg.Source.Ajax(url,options);options.streaming=false}this.maxAudioLag=options.maxAudioLag||.25;this.loop=options.loop!==false;this.autoplay=!!options.autoplay||options.streaming;this.demuxer=new JSMpeg.Demuxer.TS(options);this.source.connect(this.demuxer);if(!options.disableWebAssembly&&JSMpeg.WASMModule.IsSupported()){this.wasmModule=new JSMpeg.WASMModule;options.wasmModule=this.wasmModule}if(options.video!==false){this.video=options.wasmModule?new JSMpeg.Decoder.MPEG1VideoWASM(options):new JSMpeg.Decoder.MPEG1Video(options);this.renderer=!options.disableGl&&JSMpeg.Renderer.WebGL.IsSupported()?new JSMpeg.Renderer.WebGL(options):new JSMpeg.Renderer.Canvas2D(options);this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.VIDEO_1,this.video);this.video.connect(this.renderer)}if(options.audio!==false&&JSMpeg.AudioOutput.WebAudio.IsSupported()){this.audio=options.wasmModule?new JSMpeg.Decoder.MP2AudioWASM(options):new JSMpeg.Decoder.MP2Audio(options);this.audioOut=new JSMpeg.AudioOutput.WebAudio(options);this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.AUDIO_1,this.audio);this.audio.connect(this.audioOut)}Object.defineProperty(this,"currentTime",{get:this.getCurrentTime,set:this.setCurrentTime});Object.defineProperty(this,"volume",{get:this.getVolume,set:this.setVolume});this.paused=true;this.unpauseOnShow=false;if(options.pauseWhenHidden!==false){document.addEventListener("visibilitychange",this.showHide.bind(this))}if(this.wasmModule){if(JSMpeg.WASM_BINARY_INLINED){var wasm=JSMpeg.Base64ToArrayBuffer(JSMpeg.WASM_BINARY_INLINED);this.wasmModule.loadFromBuffer(wasm,this.startLoading.bind(this))}else{this.wasmModule.loadFromFile("jsmpeg.wasm",this.startLoading.bind(this))}}else{this.startLoading()}};Player.prototype.startLoading=function(){this.source.start();if(this.autoplay){this.play()}};Player.prototype.showHide=function(ev){if(document.visibilityState==="hidden"){this.unpauseOnShow=this.wantsToPlay;this.pause()}else if(this.unpauseOnShow){this.play()}};Player.prototype.play=function(ev){if(this.animationId){return}this.animationId=requestAnimationFrame(this.update.bind(this));this.wantsToPlay=true;this.paused=false};Player.prototype.pause=function(ev){if(this.paused){return}cancelAnimationFrame(this.animationId);this.animationId=null;this.wantsToPlay=false;this.isPlaying=false;this.paused=true;if(this.audio&&this.audio.canPlay){this.audioOut.stop();this.seek(this.currentTime)}if(this.options.onPause){this.options.onPause(this)}};Player.prototype.getVolume=function(){return this.audioOut?this.audioOut.volume:0};Player.prototype.setVolume=function(volume){if(this.audioOut){this.audioOut.volume=volume}};Player.prototype.stop=function(ev){this.pause();this.seek(0);if(this.video&&this.options.decodeFirstFrame!==false){this.video.decode()}};Player.prototype.destroy=function(){this.pause();this.source.destroy();this.video&&this.video.destroy();this.renderer&&this.renderer.destroy();this.audio&&this.audio.destroy();this.audioOut&&this.audioOut.destroy()};Player.prototype.seek=function(time){var startOffset=this.audio&&this.audio.canPlay?this.audio.startTime:this.video.startTime;if(this.video){this.video.seek(time+startOffset)}if(this.audio){this.audio.seek(time+startOffset)}this.startTime=JSMpeg.Now()-time};Player.prototype.getCurrentTime=function(){return this.audio&&this.audio.canPlay?this.audio.currentTime-this.audio.startTime:this.video.currentTime-this.video.startTime};Player.prototype.setCurrentTime=function(time){this.seek(time)};Player.prototype.update=function(){this.animationId=requestAnimationFrame(this.update.bind(this));if(!this.source.established){if(this.renderer){this.renderer.renderProgress(this.source.progress)}return}if(!this.isPlaying){this.isPlaying=true;this.startTime=JSMpeg.Now()-this.currentTime;if(this.options.onPlay){this.options.onPlay(this)}}if(this.options.streaming){this.updateForStreaming()}else{this.updateForStaticFile()}};Player.prototype.updateForStreaming=function(){if(this.video){this.video.decode()}if(this.audio){var decoded=false;do{if(this.audioOut.enqueuedTime>this.maxAudioLag){this.audioOut.resetEnqueuedTime();this.audioOut.enabled=false}decoded=this.audio.decode()}while(decoded);this.audioOut.enabled=true}};Player.prototype.nextFrame=function(){if(this.source.established&&this.video){return this.video.decode()}return false};Player.prototype.updateForStaticFile=function(){var notEnoughData=false,headroom=0;if(this.audio&&this.audio.canPlay){while(!notEnoughData&&this.audio.decodedTime-this.audio.currentTime<.25){notEnoughData=!this.audio.decode()}if(this.video&&this.video.currentTime0){if(lateTime>frameTime*2){this.startTime+=lateTime}notEnoughData=!this.video.decode()}headroom=this.demuxer.currentTime-targetTime}this.source.resume(headroom);if(notEnoughData&&this.source.completed){if(this.loop){this.seek(0)}else{this.pause();if(this.options.onEnded){this.options.onEnded(this)}}}else if(notEnoughData&&this.options.onStalled){this.options.onStalled(this)}};return Player}();JSMpeg.BitBuffer=function(){"use strict";var BitBuffer=function(bufferOrLength,mode){if(typeof bufferOrLength==="object"){this.bytes=bufferOrLength instanceof Uint8Array?bufferOrLength:new Uint8Array(bufferOrLength);this.byteLength=this.bytes.length}else{this.bytes=new Uint8Array(bufferOrLength||1024*1024);this.byteLength=0}this.mode=mode||BitBuffer.MODE.EXPAND;this.index=0};BitBuffer.prototype.resize=function(size){var newBytes=new Uint8Array(size);if(this.byteLength!==0){this.byteLength=Math.min(this.byteLength,size);newBytes.set(this.bytes,0,this.byteLength)}this.bytes=newBytes;this.index=Math.min(this.index,this.byteLength<<3)};BitBuffer.prototype.evict=function(sizeNeeded){var bytePos=this.index>>3,available=this.bytes.length-this.byteLength;if(this.index===this.byteLength<<3||sizeNeeded>available+bytePos){this.byteLength=0;this.index=0;return}else if(bytePos===0){return}if(this.bytes.copyWithin){this.bytes.copyWithin(0,bytePos,this.byteLength)}else{this.bytes.set(this.bytes.subarray(bytePos,this.byteLength))}this.byteLength=this.byteLength-bytePos;this.index-=bytePos<<3;return};BitBuffer.prototype.write=function(buffers){var isArrayOfBuffers=typeof buffers[0]==="object",totalLength=0,available=this.bytes.length-this.byteLength;if(isArrayOfBuffers){var totalLength=0;for(var i=0;iavailable){if(this.mode===BitBuffer.MODE.EXPAND){var newSize=Math.max(this.bytes.length*2,totalLength-available);this.resize(newSize)}else{this.evict(totalLength)}}if(isArrayOfBuffers){for(var i=0;i>3;i>3;return i>=this.byteLength||this.bytes[i]==0&&this.bytes[i+1]==0&&this.bytes[i+2]==1};BitBuffer.prototype.peek=function(count){var offset=this.index;var value=0;while(count){var currentByte=this.bytes[offset>>3],remaining=8-(offset&7),read=remaining>8-read;value=value<>shift;offset+=read;count-=read}return value};BitBuffer.prototype.read=function(count){var value=this.peek(count);this.index+=count;return value};BitBuffer.prototype.skip=function(count){return this.index+=count};BitBuffer.prototype.rewind=function(count){this.index=Math.max(this.index-count,0)};BitBuffer.prototype.has=function(count){return(this.byteLength<<3)-this.index>=count};BitBuffer.MODE={EVICT:1,EXPAND:2};return BitBuffer}();JSMpeg.Source.Ajax=function(){"use strict";var AjaxSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.streaming=false;this.completed=false;this.established=false;this.progress=0;this.onEstablishedCallback=options.onSourceEstablished;this.onCompletedCallback=options.onSourceCompleted};AjaxSource.prototype.connect=function(destination){this.destination=destination};AjaxSource.prototype.start=function(){this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE&&this.request.status===200){this.onLoad(this.request.response)}}.bind(this);this.request.onprogress=this.onProgress.bind(this);this.request.open("GET",this.url);this.request.responseType="arraybuffer";this.request.send()};AjaxSource.prototype.resume=function(secondsHeadroom){};AjaxSource.prototype.destroy=function(){this.request.abort()};AjaxSource.prototype.onProgress=function(ev){this.progress=ev.loaded/ev.total};AjaxSource.prototype.onLoad=function(data){this.established=true;this.completed=true;this.progress=1;if(this.onEstablishedCallback){this.onEstablishedCallback(this)}if(this.onCompletedCallback){this.onCompletedCallback(this)}if(this.destination){this.destination.write(data)}};return AjaxSource}();JSMpeg.Source.Fetch=function(){"use strict";var FetchSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.streaming=true;this.completed=false;this.established=false;this.progress=0;this.aborted=false;this.onEstablishedCallback=options.onSourceEstablished;this.onCompletedCallback=options.onSourceCompleted};FetchSource.prototype.connect=function(destination){this.destination=destination};FetchSource.prototype.start=function(){var params={method:"GET",headers:new Headers,cache:"default"};self.fetch(this.url,params).then(function(res){if(res.ok&&(res.status>=200&&res.status<=299)){this.progress=1;this.established=true;return this.pump(res.body.getReader())}else{}}.bind(this)).catch(function(err){throw err})};FetchSource.prototype.pump=function(reader){return reader.read().then(function(result){if(result.done){this.completed=true}else{if(this.aborted){return reader.cancel()}if(this.destination){this.destination.write(result.value.buffer)}return this.pump(reader)}}.bind(this)).catch(function(err){throw err})};FetchSource.prototype.resume=function(secondsHeadroom){};FetchSource.prototype.abort=function(){this.aborted=true};return FetchSource}();JSMpeg.Source.AjaxProgressive=function(){"use strict";var AjaxProgressiveSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.streaming=false;this.completed=false;this.established=false;this.progress=0;this.fileSize=0;this.loadedSize=0;this.chunkSize=options.chunkSize||1024*1024;this.isLoading=false;this.loadStartTime=0;this.throttled=options.throttled!==false;this.aborted=false;this.onEstablishedCallback=options.onSourceEstablished;this.onCompletedCallback=options.onSourceCompleted};AjaxProgressiveSource.prototype.connect=function(destination){this.destination=destination};AjaxProgressiveSource.prototype.start=function(){this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE){this.fileSize=parseInt(this.request.getResponseHeader("Content-Length"));this.loadNextChunk()}}.bind(this);this.request.onprogress=this.onProgress.bind(this);this.request.open("HEAD",this.url);this.request.send()};AjaxProgressiveSource.prototype.resume=function(secondsHeadroom){if(this.isLoading||!this.throttled){return}var worstCaseLoadingTime=this.loadTime*8+2;if(worstCaseLoadingTime>secondsHeadroom){this.loadNextChunk()}};AjaxProgressiveSource.prototype.destroy=function(){this.request.abort();this.aborted=true};AjaxProgressiveSource.prototype.loadNextChunk=function(){var start=this.loadedSize,end=Math.min(this.loadedSize+this.chunkSize-1,this.fileSize-1);if(start>=this.fileSize||this.aborted){this.completed=true;if(this.onCompletedCallback){this.onCompletedCallback(this)}return}this.isLoading=true;this.loadStartTime=JSMpeg.Now();this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE&&this.request.status>=200&&this.request.status<300){this.onChunkLoad(this.request.response)}else if(this.request.readyState===this.request.DONE){if(this.loadFails++<3){this.loadNextChunk()}}}.bind(this);if(start===0){this.request.onprogress=this.onProgress.bind(this)}this.request.open("GET",this.url+"?"+start+"-"+end);this.request.setRequestHeader("Range","bytes="+start+"-"+end);this.request.responseType="arraybuffer";this.request.send()};AjaxProgressiveSource.prototype.onProgress=function(ev){this.progress=ev.loaded/ev.total};AjaxProgressiveSource.prototype.onChunkLoad=function(data){var isFirstChunk=!this.established;this.established=true;this.progress=1;this.loadedSize+=data.byteLength;this.loadFails=0;this.isLoading=false;if(isFirstChunk&&this.onEstablishedCallback){this.onEstablishedCallback(this)}if(this.destination){this.destination.write(data)}this.loadTime=JSMpeg.Now()-this.loadStartTime;if(!this.throttled){this.loadNextChunk()}};return AjaxProgressiveSource}();JSMpeg.Source.WebSocket=function(){"use strict";var WSSource=function(url,options){this.url=url;this.options=options;this.socket=null;this.streaming=true;this.callbacks={connect:[],data:[]};this.destination=null;this.reconnectInterval=options.reconnectInterval!==undefined?options.reconnectInterval:5;this.shouldAttemptReconnect=!!this.reconnectInterval;this.completed=false;this.established=false;this.progress=0;this.reconnectTimeoutId=0;this.onEstablishedCallback=options.onSourceEstablished;this.onCompletedCallback=options.onSourceCompleted};WSSource.prototype.connect=function(destination){this.destination=destination};WSSource.prototype.destroy=function(){clearTimeout(this.reconnectTimeoutId);this.shouldAttemptReconnect=false;this.socket.close()};WSSource.prototype.start=function(){this.shouldAttemptReconnect=!!this.reconnectInterval;this.progress=0;this.established=false;this.socket=new WebSocket(this.url,this.options.protocols||null);this.socket.binaryType="arraybuffer";this.socket.onmessage=this.onMessage.bind(this);this.socket.onopen=this.onOpen.bind(this);this.socket.onerror=this.onClose.bind(this);this.socket.onclose=this.onClose.bind(this)};WSSource.prototype.resume=function(secondsHeadroom){};WSSource.prototype.onOpen=function(){this.progress=1};WSSource.prototype.onClose=function(){if(this.shouldAttemptReconnect){clearTimeout(this.reconnectTimeoutId);this.reconnectTimeoutId=setTimeout(function(){this.start()}.bind(this),this.reconnectInterval*1e3)}};WSSource.prototype.onMessage=function(ev){var isFirstChunk=!this.established;this.established=true;if(isFirstChunk&&this.onEstablishedCallback){this.onEstablishedCallback(this)}if(this.destination){this.destination.write(ev.data)}};return WSSource}();JSMpeg.Demuxer.TS=function(){"use strict";var TS=function(options){this.bits=null;this.leftoverBytes=null;this.guessVideoFrameEnd=true;this.pidsToStreamIds={};this.pesPacketInfo={};this.startTime=0;this.currentTime=0};TS.prototype.connect=function(streamId,destination){this.pesPacketInfo[streamId]={destination:destination,currentLength:0,totalLength:0,pts:0,buffers:[]}};TS.prototype.write=function(buffer){if(this.leftoverBytes){var totalLength=buffer.byteLength+this.leftoverBytes.byteLength;this.bits=new JSMpeg.BitBuffer(totalLength);this.bits.write([this.leftoverBytes,buffer])}else{this.bits=new JSMpeg.BitBuffer(buffer)}while(this.bits.has(188<<3)&&this.parsePacket()){}var leftoverCount=this.bits.byteLength-(this.bits.index>>3);this.leftoverBytes=leftoverCount>0?this.bits.bytes.subarray(this.bits.index>>3):null};TS.prototype.parsePacket=function(){if(this.bits.read(8)!==71){if(!this.resync()){return false}}var end=(this.bits.index>>3)+187;var transportError=this.bits.read(1),payloadStart=this.bits.read(1),transportPriority=this.bits.read(1),pid=this.bits.read(13),transportScrambling=this.bits.read(2),adaptationField=this.bits.read(2),continuityCounter=this.bits.read(4);var streamId=this.pidsToStreamIds[pid];if(payloadStart&&streamId){var pi=this.pesPacketInfo[streamId];if(pi&&pi.currentLength){this.packetComplete(pi)}}if(adaptationField&1){if(adaptationField&2){var adaptationFieldLength=this.bits.read(8);this.bits.skip(adaptationFieldLength<<3)}if(payloadStart&&this.bits.nextBytesAreStartCode()){this.bits.skip(24);streamId=this.bits.read(8);this.pidsToStreamIds[pid]=streamId;var packetLength=this.bits.read(16);this.bits.skip(8);var ptsDtsFlag=this.bits.read(2);this.bits.skip(6);var headerLength=this.bits.read(8);var payloadBeginIndex=this.bits.index+(headerLength<<3);var pi=this.pesPacketInfo[streamId];if(pi){var pts=0;if(ptsDtsFlag&2){this.bits.skip(4);var p32_30=this.bits.read(3);this.bits.skip(1);var p29_15=this.bits.read(15);this.bits.skip(1);var p14_0=this.bits.read(15);this.bits.skip(1);pts=(p32_30*1073741824+p29_15*32768+p14_0)/9e4;this.currentTime=pts;if(this.startTime===-1){this.startTime=pts}}var payloadLength=packetLength?packetLength-headerLength-3:0;this.packetStart(pi,pts,payloadLength)}this.bits.index=payloadBeginIndex}if(streamId){var pi=this.pesPacketInfo[streamId];if(pi){var start=this.bits.index>>3;var complete=this.packetAddData(pi,start,end);var hasPadding=!payloadStart&&adaptationField&2;if(complete||this.guessVideoFrameEnd&&hasPadding){this.packetComplete(pi)}}}}this.bits.index=end<<3;return true};TS.prototype.resync=function(){if(!this.bits.has(188*6<<3)){return false}var byteIndex=this.bits.index>>3;for(var i=0;i<187;i++){if(this.bits.bytes[byteIndex+i]===71){var foundSync=true;for(var j=1;j<5;j++){if(this.bits.bytes[byteIndex+i+188*j]!==71){foundSync=false;break}}if(foundSync){this.bits.index=byteIndex+i+1<<3;return true}}}console.warn("JSMpeg: Possible garbage data. Skipping.");this.bits.skip(187<<3);return false};TS.prototype.packetStart=function(pi,pts,payloadLength){pi.totalLength=payloadLength;pi.currentLength=0;pi.pts=pts};TS.prototype.packetAddData=function(pi,start,end){pi.buffers.push(this.bits.bytes.subarray(start,end));pi.currentLength+=end-start;var complete=pi.totalLength!==0&&pi.currentLength>=pi.totalLength;return complete};TS.prototype.packetComplete=function(pi){pi.destination.write(pi.pts,pi.buffers);pi.totalLength=0;pi.currentLength=0;pi.buffers=[]};TS.STREAM={PACK_HEADER:186,SYSTEM_HEADER:187,PROGRAM_MAP:188,PRIVATE_1:189,PADDING:190,PRIVATE_2:191,AUDIO_1:192,VIDEO_1:224,DIRECTORY:255};return TS}();JSMpeg.Decoder.Base=function(){"use strict";var BaseDecoder=function(options){this.destination=null;this.canPlay=false;this.collectTimestamps=!options.streaming;this.bytesWritten=0;this.timestamps=[];this.timestampIndex=0;this.startTime=0;this.decodedTime=0;Object.defineProperty(this,"currentTime",{get:this.getCurrentTime})};BaseDecoder.prototype.destroy=function(){};BaseDecoder.prototype.connect=function(destination){this.destination=destination};BaseDecoder.prototype.bufferGetIndex=function(){return this.bits.index};BaseDecoder.prototype.bufferSetIndex=function(index){this.bits.index=index};BaseDecoder.prototype.bufferWrite=function(buffers){return this.bits.write(buffers)};BaseDecoder.prototype.write=function(pts,buffers){if(this.collectTimestamps){if(this.timestamps.length===0){this.startTime=pts;this.decodedTime=pts}this.timestamps.push({index:this.bytesWritten<<3,time:pts})}this.bytesWritten+=this.bufferWrite(buffers);this.canPlay=true};BaseDecoder.prototype.seek=function(time){if(!this.collectTimestamps){return}this.timestampIndex=0;for(var i=0;itime){break}this.timestampIndex=i}var ts=this.timestamps[this.timestampIndex];if(ts){this.bufferSetIndex(ts.index);this.decodedTime=ts.time}else{this.bufferSetIndex(0);this.decodedTime=this.startTime}};BaseDecoder.prototype.decode=function(){this.advanceDecodedTime(0)};BaseDecoder.prototype.advanceDecodedTime=function(seconds){if(this.collectTimestamps){var newTimestampIndex=-1;var currentIndex=this.bufferGetIndex();for(var i=this.timestampIndex;icurrentIndex){break}newTimestampIndex=i}if(newTimestampIndex!==-1&&newTimestampIndex!==this.timestampIndex){this.timestampIndex=newTimestampIndex;this.decodedTime=this.timestamps[this.timestampIndex].time;return}}this.decodedTime+=seconds};BaseDecoder.prototype.getCurrentTime=function(){return this.decodedTime};return BaseDecoder}();JSMpeg.Decoder.MPEG1Video=function(){"use strict";var MPEG1=function(options){JSMpeg.Decoder.Base.call(this,options);this.onDecodeCallback=options.onVideoDecode;var bufferSize=options.videoBufferSize||512*1024;var bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.bits=new JSMpeg.BitBuffer(bufferSize,bufferMode);this.customIntraQuantMatrix=new Uint8Array(64);this.customNonIntraQuantMatrix=new Uint8Array(64);this.blockData=new Int32Array(64);this.currentFrame=0;this.decodeFirstFrame=options.decodeFirstFrame!==false};MPEG1.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MPEG1.prototype.constructor=MPEG1;MPEG1.prototype.write=function(pts,buffers){JSMpeg.Decoder.Base.prototype.write.call(this,pts,buffers);if(!this.hasSequenceHeader){if(this.bits.findStartCode(MPEG1.START.SEQUENCE)===-1){return false}this.decodeSequenceHeader();if(this.decodeFirstFrame){this.decode()}}};MPEG1.prototype.decode=function(){var startTime=JSMpeg.Now();if(!this.hasSequenceHeader){return false}if(this.bits.findStartCode(MPEG1.START.PICTURE)===-1){var bufferedBytes=this.bits.byteLength-(this.bits.index>>3);return false}this.decodePicture();this.advanceDecodedTime(1/this.frameRate);var elapsedTime=JSMpeg.Now()-startTime;if(this.onDecodeCallback){this.onDecodeCallback(this,elapsedTime)}return true};MPEG1.prototype.readHuffman=function(codeTable){var state=0;do{state=codeTable[state+this.bits.read(1)]}while(state>=0&&codeTable[state]!==0);return codeTable[state+2]};MPEG1.prototype.frameRate=30;MPEG1.prototype.decodeSequenceHeader=function(){var newWidth=this.bits.read(12),newHeight=this.bits.read(12);this.bits.skip(4);this.frameRate=MPEG1.PICTURE_RATE[this.bits.read(4)];this.bits.skip(18+1+10+1);if(newWidth!==this.width||newHeight!==this.height){this.width=newWidth;this.height=newHeight;this.initBuffers();if(this.destination){this.destination.resize(newWidth,newHeight)}}if(this.bits.read(1)){for(var i=0;i<64;i++){this.customIntraQuantMatrix[MPEG1.ZIG_ZAG[i]]=this.bits.read(8)}this.intraQuantMatrix=this.customIntraQuantMatrix}if(this.bits.read(1)){for(var i=0;i<64;i++){var idx=MPEG1.ZIG_ZAG[i];this.customNonIntraQuantMatrix[idx]=this.bits.read(8)}this.nonIntraQuantMatrix=this.customNonIntraQuantMatrix}this.hasSequenceHeader=true};MPEG1.prototype.initBuffers=function(){this.intraQuantMatrix=MPEG1.DEFAULT_INTRA_QUANT_MATRIX;this.nonIntraQuantMatrix=MPEG1.DEFAULT_NON_INTRA_QUANT_MATRIX;this.mbWidth=this.width+15>>4;this.mbHeight=this.height+15>>4;this.mbSize=this.mbWidth*this.mbHeight;this.codedWidth=this.mbWidth<<4;this.codedHeight=this.mbHeight<<4;this.codedSize=this.codedWidth*this.codedHeight;this.halfWidth=this.mbWidth<<3;this.halfHeight=this.mbHeight<<3;this.currentY=new Uint8ClampedArray(this.codedSize);this.currentY32=new Uint32Array(this.currentY.buffer);this.currentCr=new Uint8ClampedArray(this.codedSize>>2);this.currentCr32=new Uint32Array(this.currentCr.buffer);this.currentCb=new Uint8ClampedArray(this.codedSize>>2);this.currentCb32=new Uint32Array(this.currentCb.buffer);this.forwardY=new Uint8ClampedArray(this.codedSize);this.forwardY32=new Uint32Array(this.forwardY.buffer);this.forwardCr=new Uint8ClampedArray(this.codedSize>>2);this.forwardCr32=new Uint32Array(this.forwardCr.buffer);this.forwardCb=new Uint8ClampedArray(this.codedSize>>2);this.forwardCb32=new Uint32Array(this.forwardCb.buffer)};MPEG1.prototype.currentY=null;MPEG1.prototype.currentCr=null;MPEG1.prototype.currentCb=null;MPEG1.prototype.pictureType=0;MPEG1.prototype.forwardY=null;MPEG1.prototype.forwardCr=null;MPEG1.prototype.forwardCb=null;MPEG1.prototype.fullPelForward=false;MPEG1.prototype.forwardFCode=0;MPEG1.prototype.forwardRSize=0;MPEG1.prototype.forwardF=0;MPEG1.prototype.decodePicture=function(skipOutput){this.currentFrame++;this.bits.skip(10);this.pictureType=this.bits.read(3);this.bits.skip(16);if(this.pictureType<=0||this.pictureType>=MPEG1.PICTURE_TYPE.B){return}if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.fullPelForward=this.bits.read(1);this.forwardFCode=this.bits.read(3);if(this.forwardFCode===0){return}this.forwardRSize=this.forwardFCode-1;this.forwardF=1<=MPEG1.START.SLICE_FIRST&&code<=MPEG1.START.SLICE_LAST){this.decodeSlice(code&255);code=this.bits.findNextStartCode()}if(code!==-1){this.bits.rewind(32)}if(this.destination){this.destination.render(this.currentY,this.currentCr,this.currentCb,true)}if(this.pictureType===MPEG1.PICTURE_TYPE.INTRA||this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){var tmpY=this.forwardY,tmpY32=this.forwardY32,tmpCr=this.forwardCr,tmpCr32=this.forwardCr32,tmpCb=this.forwardCb,tmpCb32=this.forwardCb32;this.forwardY=this.currentY;this.forwardY32=this.currentY32;this.forwardCr=this.currentCr;this.forwardCr32=this.currentCr32;this.forwardCb=this.currentCb;this.forwardCb32=this.currentCb32;this.currentY=tmpY;this.currentY32=tmpY32;this.currentCr=tmpCr;this.currentCr32=tmpCr32;this.currentCb=tmpCb;this.currentCb32=tmpCb32}};MPEG1.prototype.quantizerScale=0;MPEG1.prototype.sliceBegin=false;MPEG1.prototype.decodeSlice=function(slice){this.sliceBegin=true;this.macroblockAddress=(slice-1)*this.mbWidth-1;this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0;this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;this.quantizerScale=this.bits.read(5);while(this.bits.read(1)){this.bits.skip(8)}do{this.decodeMacroblock()}while(!this.bits.nextBytesAreStartCode())};MPEG1.prototype.macroblockAddress=0;MPEG1.prototype.mbRow=0;MPEG1.prototype.mbCol=0;MPEG1.prototype.macroblockType=0;MPEG1.prototype.macroblockIntra=false;MPEG1.prototype.macroblockMotFw=false;MPEG1.prototype.motionFwH=0;MPEG1.prototype.motionFwV=0;MPEG1.prototype.motionFwHPrev=0;MPEG1.prototype.motionFwVPrev=0;MPEG1.prototype.decodeMacroblock=function(){var increment=0,t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT);while(t===34){t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT)}while(t===35){increment+=33; + +t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT)}increment+=t;if(this.sliceBegin){this.sliceBegin=false;this.macroblockAddress+=increment}else{if(this.macroblockAddress+increment>=this.mbSize){return}if(increment>1){this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}}while(increment>1){this.macroblockAddress++;this.mbRow=this.macroblockAddress/this.mbWidth|0;this.mbCol=this.macroblockAddress%this.mbWidth;this.copyMacroblock(this.motionFwH,this.motionFwV,this.forwardY,this.forwardCr,this.forwardCb);increment--}this.macroblockAddress++}this.mbRow=this.macroblockAddress/this.mbWidth|0;this.mbCol=this.macroblockAddress%this.mbWidth;var mbTable=MPEG1.MACROBLOCK_TYPE[this.pictureType];this.macroblockType=this.readHuffman(mbTable);this.macroblockIntra=this.macroblockType&1;this.macroblockMotFw=this.macroblockType&8;if((this.macroblockType&16)!==0){this.quantizerScale=this.bits.read(5)}if(this.macroblockIntra){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}else{this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;this.decodeMotionVectors();this.copyMacroblock(this.motionFwH,this.motionFwV,this.forwardY,this.forwardCr,this.forwardCb)}var cbp=(this.macroblockType&2)!==0?this.readHuffman(MPEG1.CODE_BLOCK_PATTERN):this.macroblockIntra?63:0;for(var block=0,mask=32;block<6;block++){if((cbp&mask)!==0){this.decodeBlock(block)}mask>>=1}};MPEG1.prototype.decodeMotionVectors=function(){var code,d,r=0;if(this.macroblockMotFw){code=this.readHuffman(MPEG1.MOTION);if(code!==0&&this.forwardF!==1){r=this.bits.read(this.forwardRSize);d=(Math.abs(code)-1<(this.forwardF<<4)-1){this.motionFwHPrev-=this.forwardF<<5}else if(this.motionFwHPrev<-this.forwardF<<4){this.motionFwHPrev+=this.forwardF<<5}this.motionFwH=this.motionFwHPrev;if(this.fullPelForward){this.motionFwH<<=1}code=this.readHuffman(MPEG1.MOTION);if(code!==0&&this.forwardF!==1){r=this.bits.read(this.forwardRSize);d=(Math.abs(code)-1<(this.forwardF<<4)-1){this.motionFwVPrev-=this.forwardF<<5}else if(this.motionFwVPrev<-this.forwardF<<4){this.motionFwVPrev+=this.forwardF<<5}this.motionFwV=this.motionFwVPrev;if(this.fullPelForward){this.motionFwV<<=1}}else if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}};MPEG1.prototype.copyMacroblock=function(motionH,motionV,sY,sCr,sCb){var width,scan,H,V,oddH,oddV,src,dest,last;var dY=this.currentY32,dCb=this.currentCb32,dCr=this.currentCr32;width=this.codedWidth;scan=width-16;H=motionH>>1;V=motionV>>1;oddH=(motionH&1)===1;oddV=(motionV&1)===1;src=((this.mbRow<<4)+V)*width+(this.mbCol<<4)+H;dest=this.mbRow*width+this.mbCol<<2;last=dest+(width<<2);var x,y1,y2,y;if(oddH){if(oddV){while(dest>2&255;y1=sY[src]+sY[src+width];src++;y|=y1+y2+2<<6&65280;y2=sY[src]+sY[src+width];src++;y|=y1+y2+2<<14&16711680;y1=sY[src]+sY[src+width];src++;y|=y1+y2+2<<22&4278190080;dY[dest++]=y}dest+=scan>>2;src+=scan-1}}else{while(dest>1&255;y1=sY[src++];y|=y1+y2+1<<7&65280;y2=sY[src++];y|=y1+y2+1<<15&16711680;y1=sY[src++];y|=y1+y2+1<<23&4278190080;dY[dest++]=y}dest+=scan>>2;src+=scan-1}}}else{if(oddV){while(dest>1&255;src++;y|=sY[src]+sY[src+width]+1<<7&65280;src++;y|=sY[src]+sY[src+width]+1<<15&16711680;src++;y|=sY[src]+sY[src+width]+1<<23&4278190080;src++;dY[dest++]=y}dest+=scan>>2;src+=scan}}else{while(dest>2;src+=scan}}}width=this.halfWidth;scan=width-8;H=motionH/2>>1;V=motionV/2>>1;oddH=(motionH/2&1)===1;oddV=(motionV/2&1)===1;src=((this.mbRow<<3)+V)*width+(this.mbCol<<3)+H;dest=this.mbRow*width+this.mbCol<<1;last=dest+(width<<1);var cr1,cr2,cr,cb1,cb2,cb;if(oddH){if(oddV){while(dest>2&255;cb=cb1+cb2+2>>2&255;cr1=sCr[src]+sCr[src+width];cb1=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<6&65280;cb|=cb1+cb2+2<<6&65280;cr2=sCr[src]+sCr[src+width];cb2=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<14&16711680;cb|=cb1+cb2+2<<14&16711680;cr1=sCr[src]+sCr[src+width];cb1=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<22&4278190080;cb|=cb1+cb2+2<<22&4278190080;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan-1}}else{while(dest>1&255;cb=cb1+cb2+1>>1&255;cr1=sCr[src];cb1=sCb[src++];cr|=cr1+cr2+1<<7&65280;cb|=cb1+cb2+1<<7&65280;cr2=sCr[src];cb2=sCb[src++];cr|=cr1+cr2+1<<15&16711680;cb|=cb1+cb2+1<<15&16711680;cr1=sCr[src];cb1=sCb[src++];cr|=cr1+cr2+1<<23&4278190080;cb|=cb1+cb2+1<<23&4278190080;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan-1}}}else{if(oddV){while(dest>1&255;cb=sCb[src]+sCb[src+width]+1>>1&255;src++;cr|=sCr[src]+sCr[src+width]+1<<7&65280;cb|=sCb[src]+sCb[src+width]+1<<7&65280;src++;cr|=sCr[src]+sCr[src+width]+1<<15&16711680;cb|=sCb[src]+sCb[src+width]+1<<15&16711680;src++;cr|=sCr[src]+sCr[src+width]+1<<23&4278190080;cb|=sCb[src]+sCb[src+width]+1<<23&4278190080;src++;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan}}else{while(dest>2;src+=scan}}}};MPEG1.prototype.dcPredictorY=0;MPEG1.prototype.dcPredictorCr=0;MPEG1.prototype.dcPredictorCb=0;MPEG1.prototype.blockData=null;MPEG1.prototype.decodeBlock=function(block){var n=0,quantMatrix;if(this.macroblockIntra){var predictor,dctSize;if(block<4){predictor=this.dcPredictorY;dctSize=this.readHuffman(MPEG1.DCT_DC_SIZE_LUMINANCE)}else{predictor=block===4?this.dcPredictorCr:this.dcPredictorCb;dctSize=this.readHuffman(MPEG1.DCT_DC_SIZE_CHROMINANCE)}if(dctSize>0){var differential=this.bits.read(dctSize);if((differential&1<0&&this.bits.read(1)===0){break}if(coeff===65535){run=this.bits.read(6);level=this.bits.read(8);if(level===0){level=this.bits.read(8)}else if(level===128){level=this.bits.read(8)-256}else if(level>128){level=level-256}}else{run=coeff>>8;level=coeff&255;if(this.bits.read(1)){level=-level}}n+=run;var dezigZagged=MPEG1.ZIG_ZAG[n];n++;level<<=1;if(!this.macroblockIntra){level+=level<0?-1:1}level=level*this.quantizerScale*quantMatrix[dezigZagged]>>4;if((level&1)===0){level-=level>0?1:-1}if(level>2047){level=2047}else if(level<-2048){level=-2048}this.blockData[dezigZagged]=level*MPEG1.PREMULTIPLIER_MATRIX[dezigZagged]}var destArray,destIndex,scan;if(block<4){destArray=this.currentY;scan=this.codedWidth-8;destIndex=this.mbRow*this.codedWidth+this.mbCol<<4;if((block&1)!==0){destIndex+=8}if((block&2)!==0){destIndex+=this.codedWidth<<3}}else{destArray=block===4?this.currentCb:this.currentCr;scan=(this.codedWidth>>1)-8;destIndex=(this.mbRow*this.codedWidth<<2)+(this.mbCol<<3)}if(this.macroblockIntra){if(n===1){MPEG1.CopyValueToDestination(this.blockData[0]+128>>8,destArray,destIndex,scan);this.blockData[0]=0}else{MPEG1.IDCT(this.blockData);MPEG1.CopyBlockToDestination(this.blockData,destArray,destIndex,scan);JSMpeg.Fill(this.blockData,0)}}else{if(n===1){MPEG1.AddValueToDestination(this.blockData[0]+128>>8,destArray,destIndex,scan);this.blockData[0]=0}else{MPEG1.IDCT(this.blockData);MPEG1.AddBlockToDestination(this.blockData,destArray,destIndex,scan);JSMpeg.Fill(this.blockData,0)}}n=0};MPEG1.CopyBlockToDestination=function(block,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]=block[n+0];dest[index+1]=block[n+1];dest[index+2]=block[n+2];dest[index+3]=block[n+3];dest[index+4]=block[n+4];dest[index+5]=block[n+5];dest[index+6]=block[n+6];dest[index+7]=block[n+7]}};MPEG1.AddBlockToDestination=function(block,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]+=block[n+0];dest[index+1]+=block[n+1];dest[index+2]+=block[n+2];dest[index+3]+=block[n+3];dest[index+4]+=block[n+4];dest[index+5]+=block[n+5];dest[index+6]+=block[n+6];dest[index+7]+=block[n+7]}};MPEG1.CopyValueToDestination=function(value,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]=value;dest[index+1]=value;dest[index+2]=value;dest[index+3]=value;dest[index+4]=value;dest[index+5]=value;dest[index+6]=value;dest[index+7]=value}};MPEG1.AddValueToDestination=function(value,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]+=value;dest[index+1]+=value;dest[index+2]+=value;dest[index+3]+=value;dest[index+4]+=value;dest[index+5]+=value;dest[index+6]+=value;dest[index+7]+=value}};MPEG1.IDCT=function(block){var b1,b3,b4,b6,b7,tmp1,tmp2,m0,x0,x1,x2,x3,x4,y3,y4,y5,y6,y7;for(var i=0;i<8;++i){b1=block[4*8+i];b3=block[2*8+i]+block[6*8+i];b4=block[5*8+i]-block[3*8+i];tmp1=block[1*8+i]+block[7*8+i];tmp2=block[3*8+i]+block[5*8+i];b6=block[1*8+i]-block[7*8+i];b7=tmp1+tmp2;m0=block[0*8+i];x4=(b6*473-b4*196+128>>8)-b7;x0=x4-((tmp1-tmp2)*362+128>>8);x1=m0-b1;x2=((block[2*8+i]-block[6*8+i])*362+128>>8)-b3;x3=m0+b1;y3=x1+x2;y4=x3+b3;y5=x1-x2;y6=x3-b3;y7=-x0-(b4*473+b6*196+128>>8);block[0*8+i]=b7+y4;block[1*8+i]=x4+y3;block[2*8+i]=y5-x0;block[3*8+i]=y6-y7;block[4*8+i]=y6+y7;block[5*8+i]=x0+y5;block[6*8+i]=y3-x4;block[7*8+i]=y4-b7}for(var i=0;i<64;i+=8){b1=block[4+i];b3=block[2+i]+block[6+i];b4=block[5+i]-block[3+i];tmp1=block[1+i]+block[7+i];tmp2=block[3+i]+block[5+i];b6=block[1+i]-block[7+i];b7=tmp1+tmp2;m0=block[0+i];x4=(b6*473-b4*196+128>>8)-b7;x0=x4-((tmp1-tmp2)*362+128>>8);x1=m0-b1;x2=((block[2+i]-block[6+i])*362+128>>8)-b3;x3=m0+b1;y3=x1+x2;y4=x3+b3;y5=x1-x2;y6=x3-b3;y7=-x0-(b4*473+b6*196+128>>8);block[0+i]=b7+y4+128>>8;block[1+i]=x4+y3+128>>8;block[2+i]=y5-x0+128>>8;block[3+i]=y6-y7+128>>8;block[4+i]=y6+y7+128>>8;block[5+i]=x0+y5+128>>8;block[6+i]=y3-x4+128>>8;block[7+i]=y4-b7+128>>8}};MPEG1.PICTURE_RATE=[0,23.976,24,25,29.97,30,50,59.94,60,0,0,0,0,0,0,0];MPEG1.ZIG_ZAG=new Uint8Array([0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63]);MPEG1.DEFAULT_INTRA_QUANT_MATRIX=new Uint8Array([8,16,19,22,26,27,29,34,16,16,22,24,27,29,34,37,19,22,26,27,29,34,34,38,22,22,26,27,29,34,37,40,22,26,27,29,32,35,40,48,26,27,29,32,35,40,48,58,26,27,29,34,38,46,56,69,27,29,35,38,46,56,69,83]);MPEG1.DEFAULT_NON_INTRA_QUANT_MATRIX=new Uint8Array([16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);MPEG1.PREMULTIPLIER_MATRIX=new Uint8Array([32,44,42,38,32,25,17,9,44,62,58,52,44,35,24,12,42,58,55,49,42,33,23,12,38,52,49,44,38,30,20,10,32,44,42,38,32,25,17,9,25,35,33,30,25,20,14,7,17,24,23,20,17,14,9,5,9,12,12,10,9,7,5,2]);MPEG1.MACROBLOCK_ADDRESS_INCREMENT=new Int16Array([1*3,2*3,0,3*3,4*3,0,0,0,1,5*3,6*3,0,7*3,8*3,0,9*3,10*3,0,11*3,12*3,0,0,0,3,0,0,2,13*3,14*3,0,15*3,16*3,0,0,0,5,0,0,4,17*3,18*3,0,19*3,20*3,0,0,0,7,0,0,6,21*3,22*3,0,23*3,24*3,0,25*3,26*3,0,27*3,28*3,0,-1,29*3,0,-1,30*3,0,31*3,32*3,0,33*3,34*3,0,35*3,36*3,0,37*3,38*3,0,0,0,9,0,0,8,39*3,40*3,0,41*3,42*3,0,43*3,44*3,0,45*3,46*3,0,0,0,15,0,0,14,0,0,13,0,0,12,0,0,11,0,0,10,47*3,-1,0,-1,48*3,0,49*3,50*3,0,51*3,52*3,0,53*3,54*3,0,55*3,56*3,0,57*3,58*3,0,59*3,60*3,0,61*3,-1,0,-1,62*3,0,63*3,64*3,0,65*3,66*3,0,67*3,68*3,0,69*3,70*3,0,71*3,72*3,0,73*3,74*3,0,0,0,21,0,0,20,0,0,19,0,0,18,0,0,17,0,0,16,0,0,35,0,0,34,0,0,33,0,0,32,0,0,31,0,0,30,0,0,29,0,0,28,0,0,27,0,0,26,0,0,25,0,0,24,0,0,23,0,0,22]);MPEG1.MACROBLOCK_TYPE_INTRA=new Int8Array([1*3,2*3,0,-1,3*3,0,0,0,1,0,0,17]);MPEG1.MACROBLOCK_TYPE_PREDICTIVE=new Int8Array([1*3,2*3,0,3*3,4*3,0,0,0,10,5*3,6*3,0,0,0,2,7*3,8*3,0,0,0,8,9*3,10*3,0,11*3,12*3,0,-1,13*3,0,0,0,18,0,0,26,0,0,1,0,0,17]);MPEG1.MACROBLOCK_TYPE_B=new Int8Array([1*3,2*3,0,3*3,5*3,0,4*3,6*3,0,8*3,7*3,0,0,0,12,9*3,10*3,0,0,0,14,13*3,14*3,0,12*3,11*3,0,0,0,4,0,0,6,18*3,16*3,0,15*3,17*3,0,0,0,8,0,0,10,-1,19*3,0,0,0,1,20*3,21*3,0,0,0,30,0,0,17,0,0,22,0,0,26]);MPEG1.MACROBLOCK_TYPE=[null,MPEG1.MACROBLOCK_TYPE_INTRA,MPEG1.MACROBLOCK_TYPE_PREDICTIVE,MPEG1.MACROBLOCK_TYPE_B];MPEG1.CODE_BLOCK_PATTERN=new Int16Array([2*3,1*3,0,3*3,6*3,0,4*3,5*3,0,8*3,11*3,0,12*3,13*3,0,9*3,7*3,0,10*3,14*3,0,20*3,19*3,0,18*3,16*3,0,23*3,17*3,0,27*3,25*3,0,21*3,28*3,0,15*3,22*3,0,24*3,26*3,0,0,0,60,35*3,40*3,0,44*3,48*3,0,38*3,36*3,0,42*3,47*3,0,29*3,31*3,0,39*3,32*3,0,0,0,32,45*3,46*3,0,33*3,41*3,0,43*3,34*3,0,0,0,4,30*3,37*3,0,0,0,8,0,0,16,0,0,44,50*3,56*3,0,0,0,28,0,0,52,0,0,62,61*3,59*3,0,52*3,60*3,0,0,0,1,55*3,54*3,0,0,0,61,0,0,56,57*3,58*3,0,0,0,2,0,0,40,51*3,62*3,0,0,0,48,64*3,63*3,0,49*3,53*3,0,0,0,20,0,0,12,80*3,83*3,0,0,0,63,77*3,75*3,0,65*3,73*3,0,84*3,66*3,0,0,0,24,0,0,36,0,0,3,69*3,87*3,0,81*3,79*3,0,68*3,71*3,0,70*3,78*3,0,67*3,76*3,0,72*3,74*3,0,86*3,85*3,0,88*3,82*3,0,-1,94*3,0,95*3,97*3,0,0,0,33,0,0,9,106*3,110*3,0,102*3,116*3,0,0,0,5,0,0,10,93*3,89*3,0,0,0,6,0,0,18,0,0,17,0,0,34,113*3,119*3,0,103*3,104*3,0,90*3,92*3,0,109*3,107*3,0,117*3,118*3,0,101*3,99*3,0,98*3,96*3,0,100*3,91*3,0,114*3,115*3,0,105*3,108*3,0,112*3,111*3,0,121*3,125*3,0,0,0,41,0,0,14,0,0,21,124*3,122*3,0,120*3,123*3,0,0,0,11,0,0,19,0,0,7,0,0,35,0,0,13,0,0,50,0,0,49,0,0,58,0,0,37,0,0,25,0,0,45,0,0,57,0,0,26,0,0,29,0,0,38,0,0,53,0,0,23,0,0,43,0,0,46,0,0,42,0,0,22,0,0,54,0,0,51,0,0,15,0,0,30,0,0,39,0,0,47,0,0,55,0,0,27,0,0,59,0,0,31]);MPEG1.MOTION=new Int16Array([1*3,2*3,0,4*3,3*3,0,0,0,0,6*3,5*3,0,8*3,7*3,0,0,0,-1,0,0,1,9*3,10*3,0,12*3,11*3,0,0,0,2,0,0,-2,14*3,15*3,0,16*3,13*3,0,20*3,18*3,0,0,0,3,0,0,-3,17*3,19*3,0,-1,23*3,0,27*3,25*3,0,26*3,21*3,0,24*3,22*3,0,32*3,28*3,0,29*3,31*3,0,-1,33*3,0,36*3,35*3,0,0,0,-4,30*3,34*3,0,0,0,4,0,0,-7,0,0,5,37*3,41*3,0,0,0,-5,0,0,7,38*3,40*3,0,42*3,39*3,0,0,0,-6,0,0,6,51*3,54*3,0,50*3,49*3,0,45*3,46*3,0,52*3,47*3,0,43*3,53*3,0,44*3,48*3,0,0,0,10,0,0,9,0,0,8,0,0,-8,57*3,66*3,0,0,0,-9,60*3,64*3,0,56*3,61*3,0,55*3,62*3,0,58*3,63*3,0,0,0,-10,59*3,65*3,0,0,0,12,0,0,16,0,0,13,0,0,14,0,0,11,0,0,15,0,0,-16,0,0,-12,0,0,-14,0,0,-15,0,0,-11,0,0,-13]);MPEG1.DCT_DC_SIZE_LUMINANCE=new Int8Array([2*3,1*3,0,6*3,5*3,0,3*3,4*3,0,0,0,1,0,0,2,9*3,8*3,0,7*3,10*3,0,0,0,0,12*3,11*3,0,0,0,4,0,0,3,13*3,14*3,0,0,0,5,0,0,6,16*3,15*3,0,17*3,-1,0,0,0,7,0,0,8]);MPEG1.DCT_DC_SIZE_CHROMINANCE=new Int8Array([2*3,1*3,0,4*3,3*3,0,6*3,5*3,0,8*3,7*3,0,0,0,2,0,0,1,0,0,0,10*3,9*3,0,0,0,3,12*3,11*3,0,0,0,4,14*3,13*3,0,0,0,5,16*3,15*3,0,0,0,6,17*3,-1,0,0,0,7,0,0,8]);MPEG1.DCT_COEFF=new Int32Array([1*3,2*3,0,4*3,3*3,0,0,0,1,7*3,8*3,0,6*3,5*3,0,13*3,9*3,0,11*3,10*3,0,14*3,12*3,0,0,0,257,20*3,22*3,0,18*3,21*3,0,16*3,19*3,0,0,0,513,17*3,15*3,0,0,0,2,0,0,3,27*3,25*3,0,29*3,31*3,0,24*3,26*3,0,32*3,30*3,0,0,0,1025,23*3,28*3,0,0,0,769,0,0,258,0,0,1793,0,0,65535,0,0,1537,37*3,36*3,0,0,0,1281,35*3,34*3,0,39*3,38*3,0,33*3,42*3,0,40*3,41*3,0,52*3,50*3,0,54*3,53*3,0,48*3,49*3,0,43*3,45*3,0,46*3,44*3,0,0,0,2049,0,0,4,0,0,514,0,0,2305,51*3,47*3,0,55*3,57*3,0,60*3,56*3,0,59*3,58*3,0,61*3,62*3,0,0,0,2561,0,0,3329,0,0,6,0,0,259,0,0,5,0,0,770,0,0,2817,0,0,3073,76*3,75*3,0,67*3,70*3,0,73*3,71*3,0,78*3,74*3,0,72*3,77*3,0,69*3,64*3,0,68*3,63*3,0,66*3,65*3,0,81*3,87*3,0,91*3,80*3,0,82*3,79*3,0,83*3,86*3,0,93*3,92*3,0,84*3,85*3,0,90*3,94*3,0,88*3,89*3,0,0,0,515,0,0,260,0,0,7,0,0,1026,0,0,1282,0,0,4097,0,0,3841,0,0,3585,105*3,107*3,0,111*3,114*3,0,104*3,97*3,0,125*3,119*3,0,96*3,98*3,0,-1,123*3,0,95*3,101*3,0,106*3,121*3,0,99*3,102*3,0,113*3,103*3,0,112*3,116*3,0,110*3,100*3,0,124*3,115*3,0,117*3,122*3,0,109*3,118*3,0,120*3,108*3,0,127*3,136*3,0,139*3,140*3,0,130*3,126*3,0,145*3,146*3,0,128*3,129*3,0,0,0,2050,132*3,134*3,0,155*3,154*3,0,0,0,8,137*3,133*3,0,143*3,144*3,0,151*3,138*3,0,142*3,141*3,0,0,0,10,0,0,9,0,0,11,0,0,5377,0,0,1538,0,0,771,0,0,5121,0,0,1794,0,0,4353,0,0,4609,0,0,4865,148*3,152*3,0,0,0,1027,153*3,150*3,0,0,0,261,131*3,135*3,0,0,0,516,149*3,147*3,0,172*3,173*3,0,162*3,158*3,0,170*3,161*3,0,168*3,166*3,0,157*3,179*3,0,169*3,167*3,0,174*3,171*3,0,178*3,177*3,0,156*3,159*3,0,164*3,165*3,0,183*3,182*3,0,175*3,176*3,0,0,0,263,0,0,2562,0,0,2306,0,0,5633,0,0,5889,0,0,6401,0,0,6145,0,0,1283,0,0,772,0,0,13,0,0,12,0,0,14,0,0,15,0,0,517,0,0,6657,0,0,262,180*3,181*3,0,160*3,163*3,0,196*3,199*3,0,0,0,27,203*3,185*3,0,202*3,201*3,0,0,0,19,0,0,22,197*3,207*3,0,0,0,18,191*3,192*3,0,188*3,190*3,0,0,0,20,184*3,194*3,0,0,0,21,186*3,193*3,0,0,0,23,204*3,198*3,0,0,0,25,0,0,24,200*3,205*3,0,0,0,31,0,0,30,0,0,28,0,0,29,0,0,26,0,0,17,0,0,16,189*3,206*3,0,187*3,195*3,0,218*3,211*3,0,0,0,37,215*3,216*3,0,0,0,36,210*3,212*3,0,0,0,34,213*3,209*3,0,221*3,222*3,0,219*3,208*3,0,217*3,214*3,0,223*3,220*3,0,0,0,35,0,0,267,0,0,40,0,0,268,0,0,266,0,0,32,0,0,264,0,0,265,0,0,38,0,0,269,0,0,270,0,0,33,0,0,39,0,0,7937,0,0,6913,0,0,7681,0,0,4098,0,0,7425,0,0,7169,0,0,271,0,0,274,0,0,273,0,0,272,0,0,1539,0,0,2818,0,0,3586,0,0,3330,0,0,3074,0,0,3842]);MPEG1.PICTURE_TYPE={INTRA:1,PREDICTIVE:2,B:3};MPEG1.START={SEQUENCE:179,SLICE_FIRST:1,SLICE_LAST:175,PICTURE:0,EXTENSION:181,USER_DATA:178};return MPEG1}();JSMpeg.Decoder.MPEG1VideoWASM=function(){"use strict";var MPEG1WASM=function(options){JSMpeg.Decoder.Base.call(this,options);this.onDecodeCallback=options.onVideoDecode;this.module=options.wasmModule;this.bufferSize=options.videoBufferSize||512*1024;this.bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.decodeFirstFrame=options.decodeFirstFrame!==false;this.hasSequenceHeader=false};MPEG1WASM.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MPEG1WASM.prototype.constructor=MPEG1WASM;MPEG1WASM.prototype.initializeWasmDecoder=function(){if(!this.module.instance){console.warn("JSMpeg: WASM module not compiled yet");return}this.instance=this.module.instance;this.functions=this.module.instance.exports;this.decoder=this.functions._mpeg1_decoder_create(this.bufferSize,this.bufferMode)};MPEG1WASM.prototype.destroy=function(){if(!this.decoder){return}this.functions._mpeg1_decoder_destroy(this.decoder)};MPEG1WASM.prototype.bufferGetIndex=function(){if(!this.decoder){return}return this.functions._mpeg1_decoder_get_index(this.decoder)};MPEG1WASM.prototype.bufferSetIndex=function(index){if(!this.decoder){return}this.functions._mpeg1_decoder_set_index(this.decoder,index)};MPEG1WASM.prototype.bufferWrite=function(buffers){if(!this.decoder){this.initializeWasmDecoder()}var totalLength=0;for(var i=0;i>2));var dcb=this.instance.heapU8.subarray(ptrCb,ptrCb+(this.codedSize>>2));this.destination.render(dy,dcr,dcb,false)}this.advanceDecodedTime(1/this.frameRate);var elapsedTime=JSMpeg.Now()-startTime;if(this.onDecodeCallback){this.onDecodeCallback(this,elapsedTime)}return true};return MPEG1WASM}();JSMpeg.Decoder.MP2Audio=function(){"use strict";var MP2=function(options){JSMpeg.Decoder.Base.call(this,options);this.onDecodeCallback=options.onAudioDecode;var bufferSize=options.audioBufferSize||128*1024;var bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.bits=new JSMpeg.BitBuffer(bufferSize,bufferMode);this.left=new Float32Array(1152);this.right=new Float32Array(1152);this.sampleRate=44100;this.D=new Float32Array(1024);this.D.set(MP2.SYNTHESIS_WINDOW,0);this.D.set(MP2.SYNTHESIS_WINDOW,512);this.V=new Float32Array(1024);this.U=new Int32Array(32);this.VPos=0;this.allocation=[new Array(32),new Array(32)];this.scaleFactorInfo=[new Uint8Array(32),new Uint8Array(32)];this.scaleFactor=[new Array(32),new Array(32)];this.sample=[new Array(32),new Array(32)];for(var j=0;j<2;j++){for(var i=0;i<32;i++){this.scaleFactor[j][i]=[0,0,0];this.sample[j][i]=[0,0,0]}}};MP2.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MP2.prototype.constructor=MP2;MP2.prototype.decode=function(){var startTime=JSMpeg.Now();var pos=this.bits.index>>3;if(pos>=this.bits.byteLength){return false}var decoded=this.decodeFrame(this.left,this.right);this.bits.index=pos+decoded<<3;if(!decoded){return false}if(this.destination){this.destination.play(this.sampleRate,this.left,this.right)}this.advanceDecodedTime(this.left.length/this.sampleRate);var elapsedTime=JSMpeg.Now()-startTime;if(this.onDecodeCallback){this.onDecodeCallback(this,elapsedTime)}return true};MP2.prototype.getCurrentTime=function(){var enqueuedTime=this.destination?this.destination.enqueuedTime:0;return this.decodedTime-enqueuedTime};MP2.prototype.decodeFrame=function(left,right){var sync=this.bits.read(11),version=this.bits.read(2),layer=this.bits.read(2),hasCRC=!this.bits.read(1);if(sync!==MP2.FRAME_SYNC||version!==MP2.VERSION.MPEG_1||layer!==MP2.LAYER.II){return 0}var bitrateIndex=this.bits.read(4)-1;if(bitrateIndex>13){return 0}var sampleRateIndex=this.bits.read(2);var sampleRate=MP2.SAMPLE_RATE[sampleRateIndex];if(sampleRateIndex===3){return 0}if(version===MP2.VERSION.MPEG_2){sampleRateIndex+=4;bitrateIndex+=14}var padding=this.bits.read(1),privat=this.bits.read(1),mode=this.bits.read(2);var bound=0;if(mode===MP2.MODE.JOINT_STEREO){bound=this.bits.read(2)+1<<2}else{this.bits.skip(2);bound=mode===MP2.MODE.MONO?0:32}this.bits.skip(4);if(hasCRC){this.bits.skip(16)}var bitrate=MP2.BIT_RATE[bitrateIndex],sampleRate=MP2.SAMPLE_RATE[sampleRateIndex],frameSize=144e3*bitrate/sampleRate+padding|0;var tab3=0;var sblimit=0;if(version===MP2.VERSION.MPEG_2){tab3=2;sblimit=30}else{var tab1=mode===MP2.MODE.MONO?0:1;var tab2=MP2.QUANT_LUT_STEP_1[tab1][bitrateIndex];tab3=MP2.QUANT_LUT_STEP_2[tab2][sampleRateIndex];sblimit=tab3&63;tab3>>=6}if(bound>sblimit){bound=sblimit}for(var sb=0;sb>1);var vIndex=this.VPos%128>>1;while(vIndex<1024){for(var i=0;i<32;++i){this.U[i]+=this.D[dIndex++]*this.V[vIndex++]}vIndex+=128-32;dIndex+=64-32}vIndex=128-32+1024-vIndex;dIndex-=512-32;while(vIndex<1024){for(var i=0;i<32;++i){this.U[i]+=this.D[dIndex++]*this.V[vIndex++]}vIndex+=128-32;dIndex+=64-32}var outChannel=ch===0?left:right;for(var j=0;j<32;j++){outChannel[outPos+j]=this.U[j]/2147418112}}outPos+=32}}}this.sampleRate=sampleRate;return frameSize};MP2.prototype.readAllocation=function(sb,tab3){var tab4=MP2.QUANT_LUT_STEP_3[tab3][sb];var qtab=MP2.QUANT_LUT_STEP4[tab4&15][this.bits.read(tab4>>4)];return qtab?MP2.QUANT_TAB[qtab-1]:0};MP2.prototype.readSamples=function(ch,sb,part){var q=this.allocation[ch][sb],sf=this.scaleFactor[ch][sb][part],sample=this.sample[ch][sb],val=0;if(!q){sample[0]=sample[1]=sample[2]=0;return}if(sf===63){sf=0}else{var shift=sf/3|0;sf=MP2.SCALEFACTOR_BASE[sf%3]+(1<>1)>>shift}var adj=q.levels;if(q.group){val=this.bits.read(q.bits);sample[0]=val%adj;val=val/adj|0;sample[1]=val%adj;sample[2]=val/adj|0}else{sample[0]=this.bits.read(q.bits);sample[1]=this.bits.read(q.bits);sample[2]=this.bits.read(q.bits)}var scale=65536/(adj+1)|0;adj=(adj+1>>1)-1;val=(adj-sample[0])*scale;sample[0]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12;val=(adj-sample[1])*scale;sample[1]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12;val=(adj-sample[2])*scale;sample[2]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12};MP2.MatrixTransform=function(s,ss,d,dp){var t01,t02,t03,t04,t05,t06,t07,t08,t09,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33;t01=s[0][ss]+s[31][ss];t02=(s[0][ss]-s[31][ss])*.500602998235;t03=s[1][ss]+s[30][ss];t04=(s[1][ss]-s[30][ss])*.505470959898;t05=s[2][ss]+s[29][ss];t06=(s[2][ss]-s[29][ss])*.515447309923;t07=s[3][ss]+s[28][ss];t08=(s[3][ss]-s[28][ss])*.53104259109;t09=s[4][ss]+s[27][ss];t10=(s[4][ss]-s[27][ss])*.553103896034;t11=s[5][ss]+s[26][ss];t12=(s[5][ss]-s[26][ss])*.582934968206;t13=s[6][ss]+s[25][ss];t14=(s[6][ss]-s[25][ss])*.622504123036;t15=s[7][ss]+s[24][ss];t16=(s[7][ss]-s[24][ss])*.674808341455;t17=s[8][ss]+s[23][ss];t18=(s[8][ss]-s[23][ss])*.744536271002;t19=s[9][ss]+s[22][ss];t20=(s[9][ss]-s[22][ss])*.839349645416;t21=s[10][ss]+s[21][ss];t22=(s[10][ss]-s[21][ss])*.972568237862;t23=s[11][ss]+s[20][ss];t24=(s[11][ss]-s[20][ss])*1.16943993343;t25=s[12][ss]+s[19][ss];t26=(s[12][ss]-s[19][ss])*1.48416461631;t27=s[13][ss]+s[18][ss];t28=(s[13][ss]-s[18][ss])*2.05778100995;t29=s[14][ss]+s[17][ss];t30=(s[14][ss]-s[17][ss])*3.40760841847;t31=s[15][ss]+s[16][ss];t32=(s[15][ss]-s[16][ss])*10.1900081235;t33=t01+t31;t31=(t01-t31)*.502419286188;t01=t03+t29;t29=(t03-t29)*.52249861494;t03=t05+t27;t27=(t05-t27)*.566944034816;t05=t07+t25;t25=(t07-t25)*.64682178336;t07=t09+t23;t23=(t09-t23)*.788154623451;t09=t11+t21;t21=(t11-t21)*1.06067768599;t11=t13+t19;t19=(t13-t19)*1.72244709824;t13=t15+t17;t17=(t15-t17)*5.10114861869;t15=t33+t13;t13=(t33-t13)*.509795579104;t33=t01+t11;t01=(t01-t11)*.601344886935;t11=t03+t09;t09=(t03-t09)*.899976223136;t03=t05+t07;t07=(t05-t07)*2.56291544774;t05=t15+t03;t15=(t15-t03)*.541196100146;t03=t33+t11;t11=(t33-t11)*1.30656296488;t33=t05+t03;t05=(t05-t03)*.707106781187;t03=t15+t11;t15=(t15-t11)*.707106781187;t03+=t15;t11=t13+t07;t13=(t13-t07)*.541196100146;t07=t01+t09;t09=(t01-t09)*1.30656296488;t01=t11+t07;t07=(t11-t07)*.707106781187;t11=t13+t09;t13=(t13-t09)*.707106781187;t11+=t13;t01+=t11;t11+=t07;t07+=t13;t09=t31+t17;t31=(t31-t17)*.509795579104;t17=t29+t19;t29=(t29-t19)*.601344886935;t19=t27+t21;t21=(t27-t21)*.899976223136;t27=t25+t23;t23=(t25-t23)*2.56291544774;t25=t09+t27;t09=(t09-t27)*.541196100146;t27=t17+t19;t19=(t17-t19)*1.30656296488;t17=t25+t27;t27=(t25-t27)*.707106781187;t25=t09+t19;t19=(t09-t19)*.707106781187;t25+=t19;t09=t31+t23;t31=(t31-t23)*.541196100146;t23=t29+t21;t21=(t29-t21)*1.30656296488;t29=t09+t23;t23=(t09-t23)*.707106781187;t09=t31+t21;t31=(t31-t21)*.707106781187;t09+=t31;t29+=t09;t09+=t23;t23+=t31;t17+=t29;t29+=t25;t25+=t09;t09+=t27;t27+=t23;t23+=t19;t19+=t31;t21=t02+t32;t02=(t02-t32)*.502419286188;t32=t04+t30;t04=(t04-t30)*.52249861494;t30=t06+t28;t28=(t06-t28)*.566944034816;t06=t08+t26;t08=(t08-t26)*.64682178336;t26=t10+t24;t10=(t10-t24)*.788154623451;t24=t12+t22;t22=(t12-t22)*1.06067768599;t12=t14+t20;t20=(t14-t20)*1.72244709824;t14=t16+t18;t16=(t16-t18)*5.10114861869;t18=t21+t14;t14=(t21-t14)*.509795579104;t21=t32+t12;t32=(t32-t12)*.601344886935;t12=t30+t24;t24=(t30-t24)*.899976223136;t30=t06+t26;t26=(t06-t26)*2.56291544774;t06=t18+t30;t18=(t18-t30)*.541196100146;t30=t21+t12;t12=(t21-t12)*1.30656296488;t21=t06+t30;t30=(t06-t30)*.707106781187;t06=t18+t12;t12=(t18-t12)*.707106781187;t06+=t12;t18=t14+t26;t26=(t14-t26)*.541196100146;t14=t32+t24;t24=(t32-t24)*1.30656296488;t32=t18+t14;t14=(t18-t14)*.707106781187;t18=t26+t24;t24=(t26-t24)*.707106781187;t18+=t24;t32+=t18;t18+=t14;t26=t14+t24;t14=t02+t16;t02=(t02-t16)*.509795579104;t16=t04+t20;t04=(t04-t20)*.601344886935;t20=t28+t22;t22=(t28-t22)*.899976223136;t28=t08+t10;t10=(t08-t10)*2.56291544774;t08=t14+t28;t14=(t14-t28)*.541196100146;t28=t16+t20;t20=(t16-t20)*1.30656296488;t16=t08+t28;t28=(t08-t28)*.707106781187;t08=t14+t20;t20=(t14-t20)*.707106781187;t08+=t20;t14=t02+t10;t02=(t02-t10)*.541196100146;t10=t04+t22;t22=(t04-t22)*1.30656296488;t04=t14+t10;t10=(t14-t10)*.707106781187;t14=t02+t22;t02=(t02-t22)*.707106781187;t14+=t02;t04+=t14;t14+=t10;t10+=t02;t16+=t04;t04+=t08;t08+=t14;t14+=t28;t28+=t10;t10+=t20;t20+=t02;t21+=t16;t16+=t32;t32+=t04;t04+=t06;t06+=t08;t08+=t18;t18+=t14;t14+=t30;t30+=t28;t28+=t26;t26+=t10;t10+=t12;t12+=t20;t20+=t24;t24+=t02;d[dp+48]=-t33;d[dp+49]=d[dp+47]=-t21;d[dp+50]=d[dp+46]=-t17;d[dp+51]=d[dp+45]=-t16;d[dp+52]=d[dp+44]=-t01;d[dp+53]=d[dp+43]=-t32;d[dp+54]=d[dp+42]=-t29;d[dp+55]=d[dp+41]=-t04;d[dp+56]=d[dp+40]=-t03;d[dp+57]=d[dp+39]=-t06;d[dp+58]=d[dp+38]=-t25;d[dp+59]=d[dp+37]=-t08;d[dp+60]=d[dp+36]=-t11;d[dp+61]=d[dp+35]=-t18;d[dp+62]=d[dp+34]=-t09;d[dp+63]=d[dp+33]=-t14;d[dp+32]=-t05;d[dp+0]=t05;d[dp+31]=-t30;d[dp+1]=t30;d[dp+30]=-t27;d[dp+2]=t27;d[dp+29]=-t28;d[dp+3]=t28;d[dp+28]=-t07;d[dp+4]=t07;d[dp+27]=-t26;d[dp+5]=t26;d[dp+26]=-t23;d[dp+6]=t23;d[dp+25]=-t10;d[dp+7]=t10; + +d[dp+24]=-t15;d[dp+8]=t15;d[dp+23]=-t12;d[dp+9]=t12;d[dp+22]=-t19;d[dp+10]=t19;d[dp+21]=-t20;d[dp+11]=t20;d[dp+20]=-t13;d[dp+12]=t13;d[dp+19]=-t24;d[dp+13]=t24;d[dp+18]=-t31;d[dp+14]=t31;d[dp+17]=-t02;d[dp+15]=t02;d[dp+16]=0};MP2.FRAME_SYNC=2047;MP2.VERSION={MPEG_2_5:0,MPEG_2:2,MPEG_1:3};MP2.LAYER={III:1,II:2,I:3};MP2.MODE={STEREO:0,JOINT_STEREO:1,DUAL_CHANNEL:2,MONO:3};MP2.SAMPLE_RATE=new Uint16Array([44100,48e3,32e3,0,22050,24e3,16e3,0]);MP2.BIT_RATE=new Uint16Array([32,48,56,64,80,96,112,128,160,192,224,256,320,384,8,16,24,32,40,48,56,64,80,96,112,128,144,160]);MP2.SCALEFACTOR_BASE=new Uint32Array([33554432,26632170,21137968]);MP2.SYNTHESIS_WINDOW=new Float32Array([0,-.5,-.5,-.5,-.5,-.5,-.5,-1,-1,-1,-1,-1.5,-1.5,-2,-2,-2.5,-2.5,-3,-3.5,-3.5,-4,-4.5,-5,-5.5,-6.5,-7,-8,-8.5,-9.5,-10.5,-12,-13,-14.5,-15.5,-17.5,-19,-20.5,-22.5,-24.5,-26.5,-29,-31.5,-34,-36.5,-39.5,-42.5,-45.5,-48.5,-52,-55.5,-58.5,-62.5,-66,-69.5,-73.5,-77,-80.5,-84.5,-88,-91.5,-95,-98,-101,-104,106.5,109,111,112.5,113.5,114,114,113.5,112,110.5,107.5,104,100,94.5,88.5,81.5,73,63.5,53,41.5,28.5,14.5,-1,-18,-36,-55.5,-76.5,-98.5,-122,-147,-173.5,-200.5,-229.5,-259.5,-290.5,-322.5,-355.5,-389.5,-424,-459.5,-495.5,-532,-568.5,-605,-641.5,-678,-714,-749,-783.5,-817,-849,-879.5,-908.5,-935,-959.5,-981,-1000.5,-1016,-1028.5,-1037.5,-1042.5,-1043.5,-1040,-1031.5,1018.5,1e3,976,946.5,911,869.5,822,767.5,707,640,565.5,485,397,302.5,201,92.5,-22.5,-144,-272.5,-407,-547.5,-694,-846,-1003,-1165,-1331.5,-1502,-1675.5,-1852.5,-2031.5,-2212.5,-2394,-2576.5,-2758.5,-2939.5,-3118.5,-3294.5,-3467.5,-3635.5,-3798.5,-3955,-4104.5,-4245.5,-4377.5,-4499,-4609.5,-4708,-4792.5,-4863.5,-4919,-4958,-4979.5,-4983,-4967.5,-4931.5,-4875,-4796,-4694.5,-4569.5,-4420,-4246,-4046,-3820,-3567,3287,2979.5,2644,2280.5,1888,1467.5,1018.5,541,35,-499,-1061,-1650,-2266.5,-2909,-3577,-4270,-4987.5,-5727.5,-6490,-7274,-8077.5,-8899.5,-9739,-10594.5,-11464.5,-12347,-13241,-14144.5,-15056,-15973.5,-16895.5,-17820,-18744.5,-19668,-20588,-21503,-22410.5,-23308.5,-24195,-25068.5,-25926.5,-26767,-27589,-28389,-29166.5,-29919,-30644.5,-31342,-32009.5,-32645,-33247,-33814.5,-34346,-34839.5,-35295,-35710,-36084.5,-36417.5,-36707.5,-36954,-37156.5,-37315,-37428,-37496,37519,37496,37428,37315,37156.5,36954,36707.5,36417.5,36084.5,35710,35295,34839.5,34346,33814.5,33247,32645,32009.5,31342,30644.5,29919,29166.5,28389,27589,26767,25926.5,25068.5,24195,23308.5,22410.5,21503,20588,19668,18744.5,17820,16895.5,15973.5,15056,14144.5,13241,12347,11464.5,10594.5,9739,8899.5,8077.5,7274,6490,5727.5,4987.5,4270,3577,2909,2266.5,1650,1061,499,-35,-541,-1018.5,-1467.5,-1888,-2280.5,-2644,-2979.5,3287,3567,3820,4046,4246,4420,4569.5,4694.5,4796,4875,4931.5,4967.5,4983,4979.5,4958,4919,4863.5,4792.5,4708,4609.5,4499,4377.5,4245.5,4104.5,3955,3798.5,3635.5,3467.5,3294.5,3118.5,2939.5,2758.5,2576.5,2394,2212.5,2031.5,1852.5,1675.5,1502,1331.5,1165,1003,846,694,547.5,407,272.5,144,22.5,-92.5,-201,-302.5,-397,-485,-565.5,-640,-707,-767.5,-822,-869.5,-911,-946.5,-976,-1e3,1018.5,1031.5,1040,1043.5,1042.5,1037.5,1028.5,1016,1000.5,981,959.5,935,908.5,879.5,849,817,783.5,749,714,678,641.5,605,568.5,532,495.5,459.5,424,389.5,355.5,322.5,290.5,259.5,229.5,200.5,173.5,147,122,98.5,76.5,55.5,36,18,1,-14.5,-28.5,-41.5,-53,-63.5,-73,-81.5,-88.5,-94.5,-100,-104,-107.5,-110.5,-112,-113.5,-114,-114,-113.5,-112.5,-111,-109,106.5,104,101,98,95,91.5,88,84.5,80.5,77,73.5,69.5,66,62.5,58.5,55.5,52,48.5,45.5,42.5,39.5,36.5,34,31.5,29,26.5,24.5,22.5,20.5,19,17.5,15.5,14.5,13,12,10.5,9.5,8.5,8,7,6.5,5.5,5,4.5,4,3.5,3.5,3,2.5,2.5,2,2,1.5,1.5,1,1,1,1,.5,.5,.5,.5,.5,.5]);MP2.QUANT_LUT_STEP_1=[[0,0,1,1,1,2,2,2,2,2,2,2,2,2],[0,0,0,0,0,0,1,1,1,2,2,2,2,2]];MP2.QUANT_TAB={A:27|64,B:30|64,C:8,D:12};MP2.QUANT_LUT_STEP_2=[[MP2.QUANT_TAB.C,MP2.QUANT_TAB.C,MP2.QUANT_TAB.D],[MP2.QUANT_TAB.A,MP2.QUANT_TAB.A,MP2.QUANT_TAB.A],[MP2.QUANT_TAB.B,MP2.QUANT_TAB.A,MP2.QUANT_TAB.B]];MP2.QUANT_LUT_STEP_3=[[68,68,52,52,52,52,52,52,52,52,52,52],[67,67,67,66,66,66,66,66,66,66,66,49,49,49,49,49,49,49,49,49,49,49,49,32,32,32,32,32,32,32],[69,69,69,69,52,52,52,52,52,52,52,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36]];MP2.QUANT_LUT_STEP4=[[0,1,2,17],[0,1,2,3,4,5,6,17],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17],[0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17],[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,17],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]];MP2.QUANT_TAB=[{levels:3,group:1,bits:5},{levels:5,group:1,bits:7},{levels:7,group:0,bits:3},{levels:9,group:1,bits:10},{levels:15,group:0,bits:4},{levels:31,group:0,bits:5},{levels:63,group:0,bits:6},{levels:127,group:0,bits:7},{levels:255,group:0,bits:8},{levels:511,group:0,bits:9},{levels:1023,group:0,bits:10},{levels:2047,group:0,bits:11},{levels:4095,group:0,bits:12},{levels:8191,group:0,bits:13},{levels:16383,group:0,bits:14},{levels:32767,group:0,bits:15},{levels:65535,group:0,bits:16}];return MP2}();JSMpeg.Decoder.MP2AudioWASM=function(){"use strict";var MP2WASM=function(options){JSMpeg.Decoder.Base.call(this,options);this.onDecodeCallback=options.onAudioDecode;this.module=options.wasmModule;this.bufferSize=options.audioBufferSize||128*1024;this.bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.sampleRate=0};MP2WASM.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MP2WASM.prototype.constructor=MP2WASM;MP2WASM.prototype.initializeWasmDecoder=function(){if(!this.module.instance){console.warn("JSMpeg: WASM module not compiled yet");return}this.instance=this.module.instance;this.functions=this.module.instance.exports;this.decoder=this.functions._mp2_decoder_create(this.bufferSize,this.bufferMode)};MP2WASM.prototype.destroy=function(){if(!this.decoder){return}this.functions._mp2_decoder_destroy(this.decoder)};MP2WASM.prototype.bufferGetIndex=function(){if(!this.decoder){return}return this.functions._mp2_decoder_get_index(this.decoder)};MP2WASM.prototype.bufferSetIndex=function(index){if(!this.decoder){return}this.functions._mp2_decoder_set_index(this.decoder,index)};MP2WASM.prototype.bufferWrite=function(buffers){if(!this.decoder){this.initializeWasmDecoder()}var totalLength=0;for(var i=0;i>4<<4;this.gl.viewport(0,0,codedWidth,this.height)};WebGLRenderer.prototype.createTexture=function(index,name){var gl=this.gl;var texture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,texture);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.uniform1i(gl.getUniformLocation(this.program,name),index);return texture};WebGLRenderer.prototype.createProgram=function(vsh,fsh){var gl=this.gl;var program=gl.createProgram();gl.attachShader(program,this.compileShader(gl.VERTEX_SHADER,vsh));gl.attachShader(program,this.compileShader(gl.FRAGMENT_SHADER,fsh));gl.linkProgram(program);gl.useProgram(program);return program};WebGLRenderer.prototype.compileShader=function(type,source){var gl=this.gl;var shader=gl.createShader(type);gl.shaderSource(shader,source);gl.compileShader(shader);if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){throw new Error(gl.getShaderInfoLog(shader))}return shader};WebGLRenderer.prototype.allowsClampedTextureData=function(){var gl=this.gl;var texture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,texture);gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,1,1,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,new Uint8ClampedArray([0]));return gl.getError()===0};WebGLRenderer.prototype.renderProgress=function(progress){var gl=this.gl;gl.useProgram(this.loadingProgram);var loc=gl.getUniformLocation(this.loadingProgram,"progress");gl.uniform1f(loc,progress);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};WebGLRenderer.prototype.render=function(y,cb,cr,isClampedArray){if(!this.enabled){return}var gl=this.gl;var w=this.width+15>>4<<4,h=this.height,w2=w>>1,h2=h>>1;if(isClampedArray&&this.shouldCreateUnclampedViews){y=new Uint8Array(y.buffer),cb=new Uint8Array(cb.buffer),cr=new Uint8Array(cr.buffer)}gl.useProgram(this.program);this.updateTexture(gl.TEXTURE0,this.textureY,w,h,y);this.updateTexture(gl.TEXTURE1,this.textureCb,w2,h2,cb);this.updateTexture(gl.TEXTURE2,this.textureCr,w2,h2,cr);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};WebGLRenderer.prototype.updateTexture=function(unit,texture,w,h,data){var gl=this.gl;gl.activeTexture(unit);gl.bindTexture(gl.TEXTURE_2D,texture);if(this.hasTextureData[unit]){gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,w,h,gl.LUMINANCE,gl.UNSIGNED_BYTE,data)}else{this.hasTextureData[unit]=true;gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,w,h,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,data)}};WebGLRenderer.IsSupported=function(){try{if(!window.WebGLRenderingContext){return false}var canvas=document.createElement("canvas");return!!(canvas.getContext("webgl")||canvas.getContext("experimental-webgl"))}catch(err){return false}};WebGLRenderer.SHADER={FRAGMENT_YCRCB_TO_RGBA:["precision mediump float;","uniform sampler2D textureY;","uniform sampler2D textureCb;","uniform sampler2D textureCr;","varying vec2 texCoord;","mat4 rec601 = mat4(","1.16438, 0.00000, 1.59603, -0.87079,","1.16438, -0.39176, -0.81297, 0.52959,","1.16438, 2.01723, 0.00000, -1.08139,","0, 0, 0, 1",");","void main() {","float y = texture2D(textureY, texCoord).r;","float cb = texture2D(textureCb, texCoord).r;","float cr = texture2D(textureCr, texCoord).r;","gl_FragColor = vec4(y, cr, cb, 1.0) * rec601;","}"].join("\n"),FRAGMENT_LOADING:["precision mediump float;","uniform float progress;","varying vec2 texCoord;","void main() {","float c = ceil(progress-(1.0-texCoord.y));","gl_FragColor = vec4(c,c,c,1);","}"].join("\n"),VERTEX_IDENTITY:["attribute vec2 vertex;","varying vec2 texCoord;","void main() {","texCoord = vertex;","gl_Position = vec4((vertex * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0);","}"].join("\n")};return WebGLRenderer}();JSMpeg.Renderer.Canvas2D=function(){"use strict";var CanvasRenderer=function(options){this.canvas=options.canvas||document.createElement("canvas");this.width=this.canvas.width;this.height=this.canvas.height;this.enabled=true;this.context=this.canvas.getContext("2d")};CanvasRenderer.prototype.destroy=function(){};CanvasRenderer.prototype.resize=function(width,height){this.width=width|0;this.height=height|0;this.canvas.width=this.width;this.canvas.height=this.height;this.imageData=this.context.getImageData(0,0,this.width,this.height);JSMpeg.Fill(this.imageData.data,255)};CanvasRenderer.prototype.renderProgress=function(progress){var w=this.canvas.width,h=this.canvas.height,ctx=this.context;ctx.fillStyle="#222";ctx.fillRect(0,0,w,h);ctx.fillStyle="#fff";ctx.fillRect(0,h-h*progress,w,h*progress)};CanvasRenderer.prototype.render=function(y,cb,cr){this.YCbCrToRGBA(y,cb,cr,this.imageData.data);this.context.putImageData(this.imageData,0,0)};CanvasRenderer.prototype.YCbCrToRGBA=function(y,cb,cr,rgba){if(!this.enabled){return}var w=this.width+15>>4<<4,w2=w>>1;var yIndex1=0,yIndex2=w,yNext2Lines=w+(w-this.width);var cIndex=0,cNextLine=w2-(this.width>>1);var rgbaIndex1=0,rgbaIndex2=this.width*4,rgbaNext2Lines=this.width*4;var cols=this.width>>1,rows=this.height>>1;var ccb,ccr,r,g,b;for(var row=0;row>8)-179;g=(ccr*88>>8)-44+(ccb*183>>8)-91;b=ccr+(ccr*198>>8)-227;var y1=y[yIndex1++];var y2=y[yIndex1++];rgba[rgbaIndex1]=y1+r;rgba[rgbaIndex1+1]=y1-g;rgba[rgbaIndex1+2]=y1+b;rgba[rgbaIndex1+4]=y2+r;rgba[rgbaIndex1+5]=y2-g;rgba[rgbaIndex1+6]=y2+b;rgbaIndex1+=8;var y3=y[yIndex2++];var y4=y[yIndex2++];rgba[rgbaIndex2]=y3+r;rgba[rgbaIndex2+1]=y3-g;rgba[rgbaIndex2+2]=y3+b;rgba[rgbaIndex2+4]=y4+r;rgba[rgbaIndex2+5]=y4-g;rgba[rgbaIndex2+6]=y4+b;rgbaIndex2+=8}yIndex1+=yNext2Lines;yIndex2+=yNext2Lines;rgbaIndex1+=rgbaNext2Lines;rgbaIndex2+=rgbaNext2Lines;cIndex+=cNextLine}};return CanvasRenderer}();JSMpeg.AudioOutput.WebAudio=function(){"use strict";var WebAudioOut=function(options){this.context=WebAudioOut.CachedContext=WebAudioOut.CachedContext||new(window.AudioContext||window.webkitAudioContext);this.gain=this.context.createGain();this.destination=this.gain;this.gain.connect(this.context.destination);this.context._connections=(this.context._connections||0)+1;this.startTime=0;this.buffer=null;this.wallclockStartTime=0;this.volume=1;this.enabled=true;this.unlocked=!WebAudioOut.NeedsUnlocking();Object.defineProperty(this,"enqueuedTime",{get:this.getEnqueuedTime})};WebAudioOut.prototype.destroy=function(){this.gain.disconnect();this.context._connections--;if(this.context._connections===0){this.context.close();WebAudioOut.CachedContext=null}};WebAudioOut.prototype.play=function(sampleRate,left,right){if(!this.enabled){return}if(!this.unlocked){var ts=JSMpeg.Now();if(this.wallclockStartTimethis.memory.buffer.byteLength){var bytesNeeded=this.brk-this.memory.buffer.byteLength;var pagesNeeded=Math.ceil(bytesNeeded/this.pageSize);this.memory.grow(pagesNeeded);this.createHeapViews()}return previousBrk};WASM.prototype.c_abort=function(size){console.warn("JSMPeg: WASM abort",arguments)};WASM.prototype.c_assertFail=function(size){console.warn("JSMPeg: WASM ___assert_fail",arguments)};WASM.prototype.readDylinkSection=function(buffer){var bytes=new Uint8Array(buffer);var next=0;var readVarUint=function(){var ret=0;var mul=1;while(1){var byte=bytes[next++];ret+=(byte&127)*mul;mul*=128;if(!(byte&128)){return ret}}};var matchNextBytes=function(expected){for(var i=0;i is already in use. /// /// - [Obsolete ("This method will be removed. Use added one instead.")] public void AddWebSocketService ( string path, Func creator ) diff --git a/src/WebSocket/WebSocketCore/WebSocketCore.csproj b/src/WebSocket/WebSocketCore/WebSocketCore.csproj index 86ea3bbe7..7816abde2 100644 --- a/src/WebSocket/WebSocketCore/WebSocketCore.csproj +++ b/src/WebSocket/WebSocketCore/WebSocketCore.csproj @@ -1,7 +1,18 @@ - netcoreapp2.1 + net6.0 + Surging.WebSocketCore + .NET CORE version based on websocket-sharp + fanly + fanly + WebSocketCore Framework + Copyright © fanly All Rights Reserved. + https://github.com/dotnetcore/surging/blob/master/LICENSE + https://github.com/dotnetcore/surging + 1.9.2.0 + 1.9.2.0 + 1.9.2 diff --git a/toc.yml b/toc.yml new file mode 100644 index 000000000..f749b9aa0 --- /dev/null +++ b/toc.yml @@ -0,0 +1,7 @@ +- name: 开发者文档 + href: docs/index + homepage: docs/index.md + +- name: 博文 + href: docs/blogs/index + homepage: docs/blogs/index.md \ No newline at end of file