diff --git a/README.en.md b/README.en.md index a2ec889..16f104d 100644 --- a/README.en.md +++ b/README.en.md @@ -1,13 +1,36 @@ -#kongx +# kongx + -#### Description kongx是网关kong的可视化界面管理平台(参考konga的部分界面布局方式),能够集中化管理应用不同环境的网关配置,提供同步各环境的网关配置功能,并且具备规范的权限管理、参数配置、环境管理及日志审计等特性。 基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器 -#### Screenshots -![](https://gitee.com/raoxy/kongx/blob/master/docs/screen.png) -#### Features +Kongx 使用指南请参考:[Wiki](https://www.kancloud.cn/raoxiaoyan/kongx/1984321) + +平台快速部署请参见[Quick Start](https://www.kancloud.cn/raoxiaoyan/kongx/1984323) + +系统环境默认用户:admin/123456(部署登录后,请前往'个人设置'页面,及时修改密码) +## Screenshots +![](./docs/screen.png) + +![](./docs/services.png) + +![](./docs/service1.png) + +![](./docs/kong%20shell.png) + +![](./docs/user.png) + +![](./docs/env.png) + +![](./docs/params.png) + +![](./docs/log.png) + +![](./docs/synclog.png) + + +## Features - Kong Manage:Upstream,Service,Route,Plugin,Consumer等 - 同步Kong配置:同步不同环境间的kong配置,便于多环境同一项目配置管理; @@ -15,15 +38,42 @@ kongx是网关kong的可视化界面管理平台(参考konga的部分界面布 - 参数管理:具有良好的扩展性,基于平台的参数管理可扩展多环境及服务管理;包括:环境管理、参数参数等 - 日志管理:平台具有完善的日志审计功能,包括:同步日志、操作日志; -#### Quick start -[快速安装](https://gitee.com/raoxy/kongx/wikis/pages?sort_id=2979225&doc_id=983590) +## Kong插件列表 +- [官网插件](https://docs.konghq.com/hub/) +- [灰度插件canary](https://gitee.com/raoxy/kong-plugins-canary) +- [防攻击 kong_injection](https://github.com/ror6ax/kong_injection) -#### Kong网关插件列表 -- [灰度插件Canary](https://gitee.com/raoxy/kong-plugins-canary) -- [...] +## kong最佳实践 -#### kong网关最佳实践 - -- Kong与consul自主发现服务 +- [Kong与consul自主发现服务](https://www.kancloud.cn/raoxiaoyan/kongx/1984357) - 如何应用灰度插件(canary)及使用场景介绍 -- 整理中...尽情期待 \ No newline at end of file +- kong插件开发实践 +- 整理中...尽情期待 + + +## kongx与kong版本关系 + + +## RoadMap +1、初步计划kongx自适应kong后续所有版本; + +2、增加shell界面和可视化管理界面; + +## 技术支持 +![](./docs/Kongx技术支持1群聊二维码.png) + +## 版本支持 +| 序号 | kongx版本 | Kong版本 | 说明 | +| --- | --- | --- | --- | +| 1 | 1.2.x | 1.2.x | 1.2.x测试| +| 1 | 1.3.x | 1.2.x、1.3.x+ | 只做过1.2.x、1.3.x测试,对1.4.x以上版本与1.3.x对比差异,原则上基础功能全部可用,(参考差异对比)[https://www.kancloud.cn/raoxiaoyan/kongx/1991178]| + +## 升级历史 +- 1.3.x发布版本(2020/11/10) +> 1. 增加upstream被动健康检查的配置 +> 2. 所有页面由弹窗改为面包屑导航 +> 3. 增加版本自适应功能,1.3.x可适配至kong所有版本(1.3.x,1.4.x,1.5.x,2.0.x,2.1.x) +> +## 参考链接 +- [Kong官网](https://docs.konghq.com/1.2.x/admin-api/) +- [OpenResty最佳实践](https://www.kancloud.cn/kancloud/openresty-best-practices/50428) \ No newline at end of file diff --git a/README.md b/README.md index e2eeea8..47f5600 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # kongx -kongx是网关kong的可视化界面管理平台(参考konga的部分界面布局方式),能够集中化管理应用不同环境的网关配置,提供同步各环境的网关配置功能,并且具备规范的权限管理、参数配置、环境管理及日志审计等特性。 +kongx(最新版本2.0.0)是网关kong的可视化界面管理平台(参考konga的部分界面布局方式),能够集中化管理应用不同环境的网关配置,提供同步各环境的网关配置功能,并且具备规范的权限管理、参数配置、环境管理及日志审计等特性。 基于Spring Boot和Spring Cloud开发,打包后可以直接运行,不需要额外安装Tomcat等应用容器 @@ -17,23 +17,18 @@ Kongx 使用指南请参考:[Wiki](https://www.kancloud.cn/raoxiaoyan/kongx/19 ![](./docs/service1.png) +![](./docs/service2.png) + +![](./docs/consumers.png) + +![](./docs/certificate.png) + ![](./docs/kong%20shell.png) -![](./docs/user.png) - -![](./docs/env.png) - -![](./docs/params.png) - -![](./docs/log.png) - -![](./docs/synclog.png) - - ## Features -- Kong Manage:Upstream,Service,Route,Plugin,Consumer等 -- 同步Kong配置:同步不同环境间的kong配置,便于多环境同一项目配置管理; +- Kong Manage:Upstream,Service,Route,Plugin,Consumer,Certificates及Ca Certificates等 +- 同步Kong配置:不同环境间的kong配置进行同步,便于多环境配置管理; - 系统管理:具有完善的权限管理系统,包括:用户管理、菜单管理、角色管理及用户组管理等功能; - 参数管理:具有良好的扩展性,基于平台的参数管理可扩展多环境及服务管理;包括:环境管理、参数参数等 - 日志管理:平台具有完善的日志审计功能,包括:同步日志、操作日志; @@ -50,13 +45,38 @@ Kongx 使用指南请参考:[Wiki](https://www.kancloud.cn/raoxiaoyan/kongx/19 - kong插件开发实践 - 整理中...尽情期待 + + + + ## RoadMap -1、初步计划kongx自适应kong后续所有版本; +1、初步计划kongx自适应kong后续所有版本;(已完成自动适配至2.1.x版本) 2、增加shell界面和可视化管理界面; ## 技术支持 -![](./docs/Kongx技术支持1群聊二维码.png) + + + + + + + + + + + +
Kongx技术支持1群
群号:980245072(未满)
技术合作
请扫描微信二维码
tech-support-qq-1cooperate
+ + +## kongx与kong版本关系 +| 序号 | kongx版本 | Kong版本 | 说明 | +| --- | --- | --- | --- | +| 1 | 1.2.x | 1.2.x | 1.2.x测试| +| 1 | 2.0.0 | 1.2.x、1.3.x、1.4.x、1.5.x、2.0.x | 目前仅针对kong版本1.2.x、1.3.x测试通过,对1.4.x以上版本与1.3.x对比差异,原则上基础功能全部可用,(参考差异对比)[https://www.kancloud.cn/raoxiaoyan/kongx/1991178]| + +## Upgrade +[更新历史](docs/upgrade.md) ## 参考链接 - [Kong官网](https://docs.konghq.com/1.2.x/admin-api/) - [OpenResty最佳实践](https://www.kancloud.cn/kancloud/openresty-best-practices/50428) \ No newline at end of file diff --git a/docs/Kongx技术支持1群聊二维码.png b/docs/Kongx技术支持1群聊二维码.png deleted file mode 100644 index 1fa3b8d..0000000 Binary files a/docs/Kongx技术支持1群聊二维码.png and /dev/null differ diff --git a/docs/certificate.png b/docs/certificate.png new file mode 100644 index 0000000..c586736 Binary files /dev/null and b/docs/certificate.png differ diff --git a/docs/consumers.png b/docs/consumers.png new file mode 100644 index 0000000..e453f0f Binary files /dev/null and b/docs/consumers.png differ diff --git a/docs/service1.png b/docs/service1.png index 0eaef34..3f8c280 100644 Binary files a/docs/service1.png and b/docs/service1.png differ diff --git a/docs/service2.png b/docs/service2.png new file mode 100644 index 0000000..cb7797e Binary files /dev/null and b/docs/service2.png differ diff --git a/docs/services.png b/docs/services.png index 800f765..bd45559 100644 Binary files a/docs/services.png and b/docs/services.png differ diff --git a/docs/upgrade.md b/docs/upgrade.md new file mode 100644 index 0000000..dd5dcf5 --- /dev/null +++ b/docs/upgrade.md @@ -0,0 +1,15 @@ +## 升级向导 +- 2.0.0发布(2020/11/10) +> 1. 增加certificate及ca_certificate +> 2. 增加upstream被动健康检查的配置 +> 3. 所有页面由弹窗改为面包屑导航 +> 4. 增加版本自适应功能,2.0.0可适配至kong所有版本(1.2.x、1.3.x,1.4.x,1.5.x,2.0.x) + +## 1. 升级到2.0.0 +参考Kongx [Quick Start](https://www.kancloud.cn/raoxiaoyan/kongx/1984323) +## 2. 1.2.x升级到2.0.0 +由1.2.x升级到2.0.0只需要两个步骤: + +2.1、 下载2.0.0的kongx安装包,具体安装步骤参考 [Quick Start](https://www.kancloud.cn/raoxiaoyan/kongx/1984323) + +2.2、 下载数据库升级脚本,[1.2.x to 2.0.0.sql](upgrade/1.2.xto2.0.0log.md),在原1.2.x版本数据库基础上执行即可。 diff --git a/docs/upgrade/1.2.xto2.0.0log.md b/docs/upgrade/1.2.xto2.0.0log.md new file mode 100644 index 0000000..d441bc1 --- /dev/null +++ b/docs/upgrade/1.2.xto2.0.0log.md @@ -0,0 +1,33 @@ +# 1.2.x 升级2.0.0 sql脚本 +```sql +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('5', '', 'Snis', 'icon-sni', 'views/gateway/sni/index', 'snis', 'y', 'menu', 'kongx', '7'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('5', '', 'Certificates', 'icon-certificate', 'views/gateway/certificate/index', 'certificate', 'y', 'menu', 'kongx', '8'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('53', 'consumer_add', '新增consumer', '', '', '', 'y', 'point', 'kongx', '999'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('53', 'consumer_update', '更新consumer', '', '', '', 'y', 'point', 'kongx', '999'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('53', 'consumer_delete', '删除consumer', '', '', '', 'y', 'point', 'kongx', '999'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('60', 'certificate_view', '查看certificate', '', '', '', 'y', 'point', 'kongx', '999'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('60', 'certificate_add', '新增certificate', '', '', '', 'y', 'point', 'kongx', '999'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('60', 'certificate_update', '修改certificate', '', '', '', 'y', 'point', 'kongx', '999'); +INSERT INTO `kongx_system_function` (`parent_id`, `code`, `name`, `menu_icon`, `visit_view`, `visit_path`, `use_yn`, `menu_type`, `application_code`, `sort_order`) VALUES ('60', 'certificate_delete', '删除certificate', '', '', '', 'y', 'point', 'kongx', '999'); + +insert into kongx_system_role_function(role_id,half_checked,function_id) +select * from ( +select '1' role_id,'n' half_checked,'-1' as function_id +union all +select '1' role_id,'n' half_checked,id as function_id from kongx_system_function +) a +where not EXISTS (select * from kongx_system_role_function b where a.function_id=b.function_id and b.role_id=a.role_id); + + +insert into kongx_system_role_function(role_id,half_checked,function_id) +select * from ( +select '2' role_id,'y' half_checked,'-1' as function_id +union +select '2' role_id,'y' half_checked,id as function_id from kongx_system_function where name in ('Gateway','Upstreams','Services','Routes','Plugins','Kong Shell','Consumers','Certificates','日志管理') +union +select '2' role_id,'n' half_checked,id as function_id from kongx_system_function where code in ('service_view','upstream_view','route_view','plugin_view','consumer_view','certificate_view') +union +select '2' role_id,'n' half_checked,id as function_id from kongx_system_function where name='操作日志' +) a +where not EXISTS (select * from kongx_system_role_function b where a.function_id=b.function_id and b.role_id=a.role_id); +``` \ No newline at end of file diff --git a/docs/wechat.jpg b/docs/wechat.jpg new file mode 100644 index 0000000..64307d0 Binary files /dev/null and b/docs/wechat.jpg differ diff --git a/kongx-common/pom.xml b/kongx-common/pom.xml index b7da931..e459f8f 100644 --- a/kongx-common/pom.xml +++ b/kongx-common/pom.xml @@ -5,7 +5,7 @@ kongx com.kongx - 1.2.x + 2.0.0 4.0.0 diff --git a/kongx-common/src/main/java/com/kongx/common/KongxBanner.java b/kongx-common/src/main/java/com/kongx/common/KongxBanner.java index edf425a..557f51c 100644 --- a/kongx-common/src/main/java/com/kongx/common/KongxBanner.java +++ b/kongx-common/src/main/java/com/kongx/common/KongxBanner.java @@ -23,7 +23,7 @@ public class KongxBanner implements Banner { @Override public void printBanner(Environment environment, Class sourceClass, PrintStream printStream) { - this.print(" :: Support kong :: ", "(v1.2.1)", printStream); + this.print(" :: Support kong :: ", "(v2.0.0)", printStream); printStream.println(BANNER); String copyright = " :: Copyright@2020 :: "; String version = SpringBootVersion.getVersion(); diff --git a/kongx-serve/pom.xml b/kongx-serve/pom.xml index 116dcd5..5b57624 100644 --- a/kongx-serve/pom.xml +++ b/kongx-serve/pom.xml @@ -5,7 +5,7 @@ kongx com.kongx - 1.2.x + 2.0.0 4.0.0 @@ -14,7 +14,7 @@ com.kongx kongx-common - 1.2.x + 2.0.0 diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/CaCertificateController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/CaCertificateController.java new file mode 100644 index 0000000..df97a73 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/CaCertificateController.java @@ -0,0 +1,128 @@ +package com.kongx.serve.controller.gateway; + +import com.kongx.common.core.entity.UserInfo; +import com.kongx.common.jsonwrapper.JsonHeaderWrapper; +import com.kongx.serve.controller.BaseController; +import com.kongx.serve.entity.gateway.CaCertificate; +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.entity.system.OperationLog; +import com.kongx.serve.service.gateway.CaCertificateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.net.URISyntaxException; + +@RestController("CaCertificateController") +@RequestMapping("/kong/api/") +@Slf4j +public class CaCertificateController extends BaseController { + private static final String CERTIFICATES_URI = "/ca_certificates"; + private static final String CERTIFICATES_URI_ID = "/ca_certificates/{id}"; + + @Autowired + private CaCertificateService caCertificateService; + + /** + * 查询所有sni + * + * @return + */ + @RequestMapping(value = CERTIFICATES_URI, method = RequestMethod.GET) + public JsonHeaderWrapper findAll(UserInfo userInfo) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + KongEntity upstreamKongEntity = caCertificateService.findAll(systemProfile(userInfo)); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 新增upstream + * + * @param sni + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI, method = RequestMethod.POST) + public JsonHeaderWrapper addUpstream(UserInfo userInfo, @RequestBody CaCertificate sni) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + CaCertificate results = this.caCertificateService.add(systemProfile(userInfo), sni.trim()); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.CaCertificate, sni); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 更新consumer + * + * @param id + * @param sni + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI_ID, method = RequestMethod.POST) + public JsonHeaderWrapper update(UserInfo userInfo, @PathVariable String id, @RequestBody CaCertificate sni) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + CaCertificate results = this.caCertificateService.update(systemProfile(userInfo), id, sni.trim()); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.CaCertificate, sni, sni.getId()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 删除sni + * + * @param id + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI_ID, method = RequestMethod.DELETE) + public JsonHeaderWrapper remove(UserInfo userInfo, @PathVariable String id) throws Exception { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + CaCertificate sni = this.caCertificateService.findEntity(systemProfile(userInfo), id); + KongEntity upstreamKongEntity = this.caCertificateService.remove(systemProfile(userInfo), id); + this.log(userInfo, OperationLog.OperationType.OPERATION_DELETE, OperationLog.OperationTarget.CaCertificate, sni); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 查询单个sni的信息 + * + * @param id + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI_ID, method = RequestMethod.GET) + public JsonHeaderWrapper findSni(UserInfo userInfo, @PathVariable String id) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + CaCertificate results = this.caCertificateService.findEntity(systemProfile(userInfo), id); + jsonHeaderWrapper.setData(results); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/CertificateController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/CertificateController.java new file mode 100644 index 0000000..3b13713 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/CertificateController.java @@ -0,0 +1,128 @@ +package com.kongx.serve.controller.gateway; + +import com.kongx.common.core.entity.UserInfo; +import com.kongx.common.jsonwrapper.JsonHeaderWrapper; +import com.kongx.serve.controller.BaseController; +import com.kongx.serve.entity.gateway.Certificate; +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.entity.system.OperationLog; +import com.kongx.serve.service.gateway.CertificateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.net.URISyntaxException; + +@RestController("CertificateController") +@RequestMapping("/kong/api/") +@Slf4j +public class CertificateController extends BaseController { + private static final String CERTIFICATES_URI = "/certificates"; + private static final String CERTIFICATES_URI_ID = "/certificates/{id}"; + + @Autowired + private CertificateService certificateService; + + /** + * 查询所有sni + * + * @return + */ + @RequestMapping(value = CERTIFICATES_URI, method = RequestMethod.GET) + public JsonHeaderWrapper findAll(UserInfo userInfo) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + KongEntity upstreamKongEntity = certificateService.findAll(systemProfile(userInfo)); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 新增upstream + * + * @param sni + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI, method = RequestMethod.POST) + public JsonHeaderWrapper addUpstream(UserInfo userInfo, @RequestBody Certificate sni) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Certificate results = this.certificateService.add(systemProfile(userInfo), sni.trim()); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.Certificate, sni); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 更新consumer + * + * @param id + * @param sni + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI_ID, method = RequestMethod.POST) + public JsonHeaderWrapper update(UserInfo userInfo, @PathVariable String id, @RequestBody Certificate sni) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Certificate results = this.certificateService.update(systemProfile(userInfo), id, sni.trim()); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.Certificate, sni, sni.getKey()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 删除sni + * + * @param id + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI_ID, method = RequestMethod.DELETE) + public JsonHeaderWrapper remove(UserInfo userInfo, @PathVariable String id) throws Exception { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Certificate sni = this.certificateService.findEntity(systemProfile(userInfo), id); + KongEntity upstreamKongEntity = this.certificateService.remove(systemProfile(userInfo), id); + this.log(userInfo, OperationLog.OperationType.OPERATION_DELETE, OperationLog.OperationTarget.Certificate, sni); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 查询单个sni的信息 + * + * @param id + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = CERTIFICATES_URI_ID, method = RequestMethod.GET) + public JsonHeaderWrapper findSni(UserInfo userInfo, @PathVariable String id) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Certificate results = this.certificateService.findEntity(systemProfile(userInfo), id); + jsonHeaderWrapper.setData(results); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ConsumerController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ConsumerController.java index 6392c3e..ae3f585 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ConsumerController.java +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ConsumerController.java @@ -5,13 +5,17 @@ import com.kongx.common.jsonwrapper.JsonHeaderWrapper; import com.kongx.serve.controller.BaseController; import com.kongx.serve.entity.gateway.Consumer; import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.entity.gateway.PluginVO; import com.kongx.serve.entity.system.OperationLog; +import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.service.gateway.ConsumerService; +import com.kongx.serve.service.gateway.PluginService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.net.URISyntaxException; +import java.util.Map; @RestController("consumerController") @RequestMapping("/kong/api/") @@ -19,10 +23,16 @@ import java.net.URISyntaxException; public class ConsumerController extends BaseController { private static final String CONSUMER_URI = "/consumers"; private static final String CONSUMER_URI_ID = "/consumers/{id}"; + private static final String CONSUMER_URI_plugins = "/consumers/{customerId}/plugins"; + private static final String CREDENTIALS_URI = "/consumers/{customerId}/{entityName}"; + private static final String CREDENTIALS_URI_ID = "/consumers/{customerId}/{entityName}/{entityId}"; @Autowired private ConsumerService consumerService; + @Autowired + private PluginService pluginService; + /** * 查询所有upstream * @@ -41,6 +51,48 @@ public class ConsumerController extends BaseController { return jsonHeaderWrapper; } + @RequestMapping(value = CONSUMER_URI_plugins, method = {RequestMethod.POST}) + public JsonHeaderWrapper findAllPlugin(UserInfo userInfo, @PathVariable String customerId, @RequestBody SystemProfile systemProfile) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + SystemProfile activeClient = this.systemProfile(userInfo); + KongEntity pluginVOKongEntity = pluginService.findAllByConsumer(systemProfile.IS_NULL() ? activeClient : systemProfile, customerId); + jsonHeaderWrapper.setData(pluginVOKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + + @RequestMapping(value = CREDENTIALS_URI, method = RequestMethod.GET) + public JsonHeaderWrapper findAllCredentials(UserInfo userInfo, @PathVariable String customerId, @PathVariable String entityName) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + KongEntity upstreamKongEntity = consumerService.findAllCredentials(systemProfile(userInfo), customerId, entityName); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + @RequestMapping(value = CREDENTIALS_URI, method = RequestMethod.POST) + public JsonHeaderWrapper addCredentials(UserInfo userInfo, @RequestBody Map map, @PathVariable String customerId, @PathVariable String entityName) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Map results = this.consumerService.addCredentials(systemProfile(userInfo), map, customerId, entityName); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.CONSUMERS, map); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + /** * 新增upstream * @@ -49,12 +101,12 @@ public class ConsumerController extends BaseController { * @throws URISyntaxException */ @RequestMapping(value = CONSUMER_URI, method = RequestMethod.POST) - public JsonHeaderWrapper addUpstream(UserInfo userInfo, @RequestBody Consumer consumer) { + public JsonHeaderWrapper add(UserInfo userInfo, @RequestBody Consumer consumer) { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { Consumer results = this.consumerService.add(systemProfile(userInfo), consumer.trim()); jsonHeaderWrapper.setData(results); - this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.UPSTREAM, consumer.getUsername()); + this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.CONSUMERS, consumer.getUsername()); } catch (Exception e) { jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); jsonHeaderWrapper.setErrmsg(e.getMessage()); @@ -76,7 +128,7 @@ public class ConsumerController extends BaseController { try { Consumer results = this.consumerService.update(systemProfile(userInfo), id, consumer.trim()); jsonHeaderWrapper.setData(results); - this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.UPSTREAM, consumer, consumer.getUsername()); + this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.CONSUMERS, consumer, consumer.getUsername()); } catch (Exception e) { jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); jsonHeaderWrapper.setErrmsg(e.getMessage()); @@ -85,19 +137,34 @@ public class ConsumerController extends BaseController { } /** - * 删除consumer + * 删除credential * - * @param id * @return * @throws URISyntaxException */ + @RequestMapping(value = CREDENTIALS_URI_ID, method = RequestMethod.DELETE) + public JsonHeaderWrapper removeCredential(UserInfo userInfo, @PathVariable String customerId, @PathVariable String entityName, + @PathVariable String entityId) throws Exception { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + KongEntity upstreamKongEntity = + this.consumerService.removeCredentials(systemProfile(userInfo), customerId, entityName, entityId); + this.log(userInfo, OperationLog.OperationType.OPERATION_DELETE, OperationLog.OperationTarget.CONSUMERS, entityId); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + @RequestMapping(value = CONSUMER_URI_ID, method = RequestMethod.DELETE) public JsonHeaderWrapper remove(UserInfo userInfo, @PathVariable String id) throws Exception { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { Consumer consumer = this.consumerService.findConsumer(systemProfile(userInfo), id); KongEntity upstreamKongEntity = this.consumerService.remove(systemProfile(userInfo), id); - this.log(userInfo, OperationLog.OperationType.OPERATION_DELETE, OperationLog.OperationTarget.UPSTREAM, consumer); + this.log(userInfo, OperationLog.OperationType.OPERATION_DELETE, OperationLog.OperationTarget.CONSUMERS, consumer); jsonHeaderWrapper.setData(upstreamKongEntity.getData()); } catch (Exception e) { jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ServiceController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ServiceController.java index b8dbd5a..2d5ac28 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ServiceController.java +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/ServiceController.java @@ -54,7 +54,6 @@ public class ServiceController extends BaseController { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { SystemProfile activeClient = this.systemProfile(userInfo); - Service service = this.kongFeignService.find(this.systemProfile(userInfo), serviceId); KongEntity pluginVOKongEntity = pluginService.findAllPluginByService(systemProfile.IS_NULL() ? activeClient : systemProfile, serviceId); jsonHeaderWrapper.setData(pluginVOKongEntity.getData()); } catch (Exception e) { @@ -75,7 +74,7 @@ public class ServiceController extends BaseController { public JsonHeaderWrapper add(UserInfo userInfo, @RequestBody Service service) { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { - Service results = this.kongFeignService.add(systemProfile(userInfo), service); + Service results = this.kongFeignService.add(systemProfile(userInfo), service.trim()); jsonHeaderWrapper.setData(results); this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.SERVICE, results, results.getName()); } catch (Exception e) { @@ -97,7 +96,7 @@ public class ServiceController extends BaseController { public JsonHeaderWrapper update(UserInfo userInfo, @PathVariable String id, @RequestBody Service service) throws URISyntaxException { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { - Service results = this.kongFeignService.update(systemProfile(userInfo), id, service); + Service results = this.kongFeignService.update(systemProfile(userInfo), id, service.trim()); jsonHeaderWrapper.setData(results); this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.SERVICE, results, results.getName()); } catch (Exception e) { diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/SniController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/SniController.java new file mode 100644 index 0000000..dc660dc --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/SniController.java @@ -0,0 +1,128 @@ +package com.kongx.serve.controller.gateway; + +import com.kongx.common.core.entity.UserInfo; +import com.kongx.common.jsonwrapper.JsonHeaderWrapper; +import com.kongx.serve.controller.BaseController; +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.entity.gateway.Sni; +import com.kongx.serve.entity.system.OperationLog; +import com.kongx.serve.service.gateway.SniService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.net.URISyntaxException; + +@RestController("sniController") +@RequestMapping("/kong/api/") +@Slf4j +public class SniController extends BaseController { + private static final String SNIS_URI = "/snis"; + private static final String SNIS_URI_ID = "/snis/{id}"; + + @Autowired + private SniService sniService; + + /** + * 查询所有sni + * + * @return + */ + @RequestMapping(value = SNIS_URI, method = RequestMethod.GET) + public JsonHeaderWrapper findAll(UserInfo userInfo) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + KongEntity upstreamKongEntity = sniService.findAll(systemProfile(userInfo)); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 新增upstream + * + * @param sni + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = SNIS_URI, method = RequestMethod.POST) + public JsonHeaderWrapper addUpstream(UserInfo userInfo, @RequestBody Sni sni) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Sni results = this.sniService.add(systemProfile(userInfo), sni.trim()); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.SNI, sni); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 更新consumer + * + * @param id + * @param sni + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = SNIS_URI_ID, method = RequestMethod.POST) + public JsonHeaderWrapper update(UserInfo userInfo, @PathVariable String id, @RequestBody Sni sni) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Sni results = this.sniService.update(systemProfile(userInfo), id, sni.trim()); + jsonHeaderWrapper.setData(results); + this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.SNI, sni, sni.getName()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 删除sni + * + * @param id + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = SNIS_URI_ID, method = RequestMethod.DELETE) + public JsonHeaderWrapper remove(UserInfo userInfo, @PathVariable String id) throws Exception { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Sni sni = this.sniService.findEntity(systemProfile(userInfo), id); + KongEntity upstreamKongEntity = this.sniService.remove(systemProfile(userInfo), id); + this.log(userInfo, OperationLog.OperationType.OPERATION_DELETE, OperationLog.OperationTarget.SNI, sni); + jsonHeaderWrapper.setData(upstreamKongEntity.getData()); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } + + /** + * 查询单个sni的信息 + * + * @param id + * @return + * @throws URISyntaxException + */ + @RequestMapping(value = SNIS_URI_ID, method = RequestMethod.GET) + public JsonHeaderWrapper findSni(UserInfo userInfo, @PathVariable String id) { + JsonHeaderWrapper jsonHeaderWrapper = this.init(); + try { + Sni results = this.sniService.findEntity(systemProfile(userInfo), id); + jsonHeaderWrapper.setData(results); + } catch (Exception e) { + jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode()); + jsonHeaderWrapper.setErrmsg(e.getMessage()); + } + return jsonHeaderWrapper; + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/UpstreamController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/UpstreamController.java index abd8064..19a2206 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/UpstreamController.java +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/gateway/UpstreamController.java @@ -54,11 +54,10 @@ public class UpstreamController extends BaseController { * @throws URISyntaxException */ @RequestMapping(value = UPSTREAM_URI, method = RequestMethod.POST) - @PreAuthorize("upstream_add") public JsonHeaderWrapper addUpstream(UserInfo userInfo, @RequestBody Upstream upstream) { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { - Upstream results = this.upstreamService.add(systemProfile(userInfo), upstream.clear()); + Upstream results = this.upstreamService.add(systemProfile(userInfo), upstream.trim()); jsonHeaderWrapper.setData(results); this.log(userInfo, OperationLog.OperationType.OPERATION_ADD, OperationLog.OperationTarget.UPSTREAM, upstream, upstream.getName()); } catch (Exception e) { @@ -80,7 +79,7 @@ public class UpstreamController extends BaseController { public JsonHeaderWrapper update(UserInfo userInfo, @PathVariable String id, @RequestBody Upstream upstream) { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { - Upstream results = this.upstreamService.update(systemProfile(userInfo), id, upstream.clear()); + Upstream results = this.upstreamService.update(systemProfile(userInfo), id, upstream.trim()); jsonHeaderWrapper.setData(results); this.log(userInfo, OperationLog.OperationType.OPERATION_UPDATE, OperationLog.OperationTarget.UPSTREAM, upstream, upstream.getName()); } catch (Exception e) { diff --git a/kongx-serve/src/main/java/com/kongx/serve/controller/system/ServerConfigController.java b/kongx-serve/src/main/java/com/kongx/serve/controller/system/ServerConfigController.java index f70050a..c663447 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/controller/system/ServerConfigController.java +++ b/kongx-serve/src/main/java/com/kongx/serve/controller/system/ServerConfigController.java @@ -70,7 +70,7 @@ public class ServerConfigController extends BaseController { JsonHeaderWrapper jsonHeaderWrapper = this.init(); try { ServerConfig serverConfig = this.serverConfigService.findByKey(key); - jsonHeaderWrapper.setData(Jackson2Helper.parsonObject(serverConfig.getConfigValue(), new TypeReference() { + jsonHeaderWrapper.setData(Jackson2Helper.parsonObject(serverConfig.getConfigValue().toString(), new TypeReference() { })); } catch (Exception e) { jsonHeaderWrapper.setErrmsg(e.getMessage()); diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/CaCertificate.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/CaCertificate.java new file mode 100644 index 0000000..d604e7a --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/CaCertificate.java @@ -0,0 +1,34 @@ +package com.kongx.serve.entity.gateway; + +import lombok.Data; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +@Data +/** + * @since 1.3.x + */ +public class CaCertificate implements Comparable { + private Timestamp created_at; + private String cert; + private String id; + private List tags = new ArrayList<>(); + + @Override + public int compareTo(Object o) { + if (o == null) { + return 1; + } + CaCertificate sni = null; + if (o instanceof CaCertificate) { + sni = (CaCertificate) o; + } + return sni.created_at.compareTo(this.created_at); + } + + public CaCertificate trim() { + return this; + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Certificate.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Certificate.java new file mode 100644 index 0000000..160aa39 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Certificate.java @@ -0,0 +1,33 @@ +package com.kongx.serve.entity.gateway; + +import lombok.Data; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +@Data +public class Certificate implements Comparable { + private Timestamp created_at; + private String cert; + private String key; + private String id; + private List tags = new ArrayList<>(); + private List snis = new ArrayList<>(); + + @Override + public int compareTo(Object o) { + if (o == null) { + return 1; + } + Certificate sni = null; + if (o instanceof Certificate) { + sni = (Certificate) o; + } + return sni.created_at.compareTo(this.created_at); + } + + public Certificate trim() { + return this; + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/EntityId.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/EntityId.java index f6912f0..79094bb 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/EntityId.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/EntityId.java @@ -1,6 +1,6 @@ /** - * Copyright 2019 bejson.com - */ + * Copyright 2019 bejson.com + */ package com.kongx.serve.entity.gateway; /** @@ -12,11 +12,12 @@ package com.kongx.serve.entity.gateway; public class EntityId { private String id; - public void setId(String id) { - this.id = id; - } - public String getId() { - return id; - } + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } } \ No newline at end of file diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Plugin.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Plugin.java index 50ec7ba..be520d7 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Plugin.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Plugin.java @@ -28,7 +28,7 @@ public class Plugin implements Comparable { private List protocols; private boolean enabled; private String run_on; - private String consumer; + private EntityId consumer; private EntityId route; private String tags; diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/PluginVO.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/PluginVO.java index 72f1228..15a275c 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/PluginVO.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/PluginVO.java @@ -27,7 +27,7 @@ public class PluginVO extends Plugin { private List protocols; private boolean enabled; private String run_on; - private String consumer; + private EntityId consumer; private EntityId route; private String tags; private String scope = "global"; diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Route.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Route.java index 16b2ef9..489dee1 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Route.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Route.java @@ -19,7 +19,7 @@ import java.util.List; public class Route implements Comparable { private String id; - private String tags; + private List tags = new ArrayList<>(); private List paths = new ArrayList<>(); private String destinations; private List protocols; @@ -31,6 +31,7 @@ public class Route implements Comparable { private int regex_priority; private boolean strip_path; private String sources; + private String path_handling; private Timestamp updated_at; private int https_redirect_status_code = 426; private EntityId service; diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Service.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Service.java index 6ded49d..2cb5f33 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Service.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Service.java @@ -15,7 +15,7 @@ import java.util.List; * @website http://www.bejson.com/java2pojo/ */ @Data -public class Service implements Comparable { +public class Service implements Comparable { private String host; private Timestamp created_at; @@ -29,6 +29,10 @@ public class Service implements Comparable { private long updated_at; private int retries; private int write_timeout; + /** + * @since 1.3.x + */ + private EntityId client_certificate; private List tags; @Override @@ -44,8 +48,11 @@ public class Service implements Comparable { } - public Service clear() { + public Service trim() { this.protocol = set(this.protocol); + if (this.client_certificate != null && this.client_certificate.getId() == null) { + this.client_certificate = null; + } return this; } diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Sni.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Sni.java new file mode 100644 index 0000000..991ad09 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Sni.java @@ -0,0 +1,32 @@ +package com.kongx.serve.entity.gateway; + +import lombok.Data; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +@Data +public class Sni implements Comparable { + private Timestamp created_at; + private String name; + private String id; + private List tags = new ArrayList<>(); + private EntityId certificate; + + @Override + public int compareTo(Object o) { + if (o == null) { + return 1; + } + Sni sni = null; + if (o instanceof Sni) { + sni = (Sni) o; + } + return sni.created_at.compareTo(this.created_at); + } + + public Sni trim() { + return this; + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Upstream.java b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Upstream.java index afec6bc..db609fc 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Upstream.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/gateway/Upstream.java @@ -7,13 +7,18 @@ import com.kongx.serve.entity.gateway.upstream.Healthchecks; import lombok.Data; import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; @Data public class Upstream implements Comparable { - private Timestamp created_at; private String id; - private String tags; + /** + * @since 1.3.x + */ + private String algorithm; + private List tags = new ArrayList<>(); private String hash_on; private String hash_fallback_header; private String hash_on_header; @@ -36,7 +41,7 @@ public class Upstream implements Comparable { return upstream.created_at.compareTo(this.created_at); } - public Upstream clear() { + public Upstream trim() { this.hash_fallback = set(this.hash_fallback); this.hash_on = set(this.hash_on); this.hash_fallback_header = set(this.hash_fallback_header); @@ -44,6 +49,7 @@ public class Upstream implements Comparable { this.hash_on_cookie = set(this.hash_on_cookie); this.hash_on_cookie_path = set(this.hash_on_cookie_path); this.hash_fallback = set(this.hash_fallback); + this.algorithm = set(this.algorithm); if (this.healthchecks != null) this.healthchecks.getActive().setHttps_sni(set(this.healthchecks.getActive().getHttps_sni())); return this; diff --git a/kongx-serve/src/main/java/com/kongx/serve/entity/system/OperationLog.java b/kongx-serve/src/main/java/com/kongx/serve/entity/system/OperationLog.java index 418b5a6..ec343ea 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/entity/system/OperationLog.java +++ b/kongx-serve/src/main/java/com/kongx/serve/entity/system/OperationLog.java @@ -81,6 +81,10 @@ public class OperationLog { ROUTE("route", "路由"), SERVICE("service", "服务"), UPSTREAM("upstream", "上游服务"), + SNI("sni", "sni"), + CONSUMERS("consumers", "消费者"), + CaCertificate("ca_certificate", "CA认证"), + Certificate("certificate", "认证"), TARGETS("targets", "上游代理"), SYSTEM("system", "系统"), SYSTEM_ROLE("system_role", "系统角色"), diff --git a/kongx-serve/src/main/java/com/kongx/serve/feign/CaCertificateFeignService.java b/kongx-serve/src/main/java/com/kongx/serve/feign/CaCertificateFeignService.java new file mode 100644 index 0000000..9911fc6 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/feign/CaCertificateFeignService.java @@ -0,0 +1,8 @@ +package com.kongx.serve.feign; + +import com.kongx.serve.entity.gateway.CaCertificate; +import org.springframework.cloud.openfeign.FeignClient; + +@FeignClient(name = "caCertificateFeignService") +public interface CaCertificateFeignService extends KongFeignService { +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/feign/CertificateFeignService.java b/kongx-serve/src/main/java/com/kongx/serve/feign/CertificateFeignService.java new file mode 100644 index 0000000..85d9a6e --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/feign/CertificateFeignService.java @@ -0,0 +1,8 @@ +package com.kongx.serve.feign; + +import com.kongx.serve.entity.gateway.Certificate; +import org.springframework.cloud.openfeign.FeignClient; + +@FeignClient(name = "certificateFeignService") +public interface CertificateFeignService extends KongFeignService { +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/feign/CredentialsFeignService.java b/kongx-serve/src/main/java/com/kongx/serve/feign/CredentialsFeignService.java new file mode 100644 index 0000000..e24a6a0 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/feign/CredentialsFeignService.java @@ -0,0 +1,9 @@ +package com.kongx.serve.feign; + +import org.springframework.cloud.openfeign.FeignClient; + +import java.util.Map; + +@FeignClient(name = "credentialsFeignService") +public interface CredentialsFeignService extends KongFeignService { +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/feign/SniFeignService.java b/kongx-serve/src/main/java/com/kongx/serve/feign/SniFeignService.java new file mode 100644 index 0000000..7beb379 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/feign/SniFeignService.java @@ -0,0 +1,8 @@ +package com.kongx.serve.feign; + +import com.kongx.serve.entity.gateway.Sni; +import org.springframework.cloud.openfeign.FeignClient; + +@FeignClient(name = "sniFeignService") +public interface SniFeignService extends KongFeignService { +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/feign/UpstreamMapFeignService.java b/kongx-serve/src/main/java/com/kongx/serve/feign/UpstreamMapFeignService.java new file mode 100644 index 0000000..f18a755 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/feign/UpstreamMapFeignService.java @@ -0,0 +1,9 @@ +package com.kongx.serve.feign; + +import org.springframework.cloud.openfeign.FeignClient; + +import java.util.Map; + +@FeignClient(name = "upstreamMapFeignService") +public interface UpstreamMapFeignService extends KongFeignService { +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/AbstractService.java b/kongx-serve/src/main/java/com/kongx/serve/service/AbstractCacheService.java similarity index 98% rename from kongx-serve/src/main/java/com/kongx/serve/service/AbstractService.java rename to kongx-serve/src/main/java/com/kongx/serve/service/AbstractCacheService.java index c1c8d21..5e23de5 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/AbstractService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/AbstractCacheService.java @@ -15,7 +15,7 @@ import java.net.URISyntaxException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -public abstract class AbstractService { +public abstract class AbstractCacheService { @Autowired protected ServerConfigService serverConfigService; diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/GatewayService.java b/kongx-serve/src/main/java/com/kongx/serve/service/GatewayService.java new file mode 100644 index 0000000..5fd8523 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/service/GatewayService.java @@ -0,0 +1,78 @@ +package com.kongx.serve.service; + +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.entity.system.SystemProfile; +import com.kongx.serve.feign.KongFeignService; + +import java.net.URISyntaxException; + +public abstract class GatewayService extends AbstractCacheService> { + + protected KongFeignService kongFeignService; + + protected String CACHE_KEY; + + protected String ENTITY_URI = ""; + protected String ENTITY_URI_ID = ""; + + /** + * 查询所有upstream + * + * @return + */ + public KongEntity findAll(SystemProfile systemProfile) { + return this.get(systemProfile, CACHE_KEY).getData(); + } + + /** + * 新增upstream + * + * @param entity + * @return + * @throws URISyntaxException + */ + public T add(SystemProfile systemProfile, T entity) throws Exception { + T results = this.kongFeignService.add(uri(systemProfile, ENTITY_URI), entity); + refresh(systemProfile, CACHE_KEY); + return results; + } + + /** + * 更新sni + * + * @param id + * @param entity + * @return + * @throws URISyntaxException + */ + public T update(SystemProfile systemProfile, String id, T entity) throws Exception { + T results = this.kongFeignService.update(uri(systemProfile, String.format(ENTITY_URI_ID, id)), entity); + refresh(systemProfile, CACHE_KEY); + return results; + } + + /** + * 删除sni + * + * @param id + * @return + * @throws URISyntaxException + */ + public KongEntity remove(SystemProfile systemProfile, String id) throws Exception { + this.kongFeignService.remove(uri(systemProfile, String.format(ENTITY_URI_ID, id))); + return refresh(systemProfile, CACHE_KEY).getData(); + } + + /** + * 查询单个sni的信息 + * + * @param id + * @return + * @throws URISyntaxException + */ + public T findEntity(SystemProfile systemProfile, String id) throws URISyntaxException { + return this.kongFeignService.findById(uri(systemProfile, String.format(ENTITY_URI_ID, id))); + } + + +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/CaCertificateService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/CaCertificateService.java new file mode 100644 index 0000000..76682a1 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/CaCertificateService.java @@ -0,0 +1,47 @@ +package com.kongx.serve.service.gateway; + +import com.kongx.common.cache.CacheResults; +import com.kongx.serve.entity.gateway.CaCertificate; +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.feign.CaCertificateFeignService; +import com.kongx.serve.service.GatewayService; +import feign.Feign; +import feign.RequestInterceptor; +import feign.Target; +import feign.codec.Decoder; +import feign.codec.Encoder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.openfeign.FeignClientsConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Service; + +import java.net.URISyntaxException; +import java.util.Collections; + +@Service("caCertificateService") +@Import(FeignClientsConfiguration.class) +@Slf4j +public class CaCertificateService extends GatewayService { + @Autowired + public CaCertificateService(Decoder decoder, Encoder encoder, RequestInterceptor requestInterceptor) { + kongFeignService = Feign.builder().encoder(encoder).decoder(decoder) + .requestInterceptor(requestInterceptor).target(Target.EmptyTarget.create(CaCertificateFeignService.class)); + ENTITY_URI = "/ca_certificates"; + ENTITY_URI_ID = "/ca_certificates/%s"; + CACHE_KEY = "LISTS"; + } + + @Override + protected String prefix() { + return "CaCertificates"; + } + + @Override + protected CacheResults> loadFromClient(KongCacheKey key) throws URISyntaxException { + log.info("Loading Services {} from kong client!", key); + KongEntity kongEntity = this.kongFeignService.findAll(uri(key.getSystemProfile(), ENTITY_URI)); + Collections.sort(kongEntity.getData()); + return new CacheResults<>(kongEntity); + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/CertificateService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/CertificateService.java new file mode 100644 index 0000000..9b89be4 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/CertificateService.java @@ -0,0 +1,47 @@ +package com.kongx.serve.service.gateway; + +import com.kongx.common.cache.CacheResults; +import com.kongx.serve.entity.gateway.Certificate; +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.feign.CertificateFeignService; +import com.kongx.serve.service.GatewayService; +import feign.Feign; +import feign.RequestInterceptor; +import feign.Target; +import feign.codec.Decoder; +import feign.codec.Encoder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.openfeign.FeignClientsConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Service; + +import java.net.URISyntaxException; +import java.util.Collections; + +@Service("certificateService") +@Import(FeignClientsConfiguration.class) +@Slf4j +public class CertificateService extends GatewayService { + @Autowired + public CertificateService(Decoder decoder, Encoder encoder, RequestInterceptor requestInterceptor) { + kongFeignService = Feign.builder().encoder(encoder).decoder(decoder) + .requestInterceptor(requestInterceptor).target(Target.EmptyTarget.create(CertificateFeignService.class)); + ENTITY_URI = "/certificates"; + ENTITY_URI_ID = "/certificates/%s"; + CACHE_KEY = "LISTS"; + } + + @Override + protected String prefix() { + return "Certificates"; + } + + @Override + protected CacheResults> loadFromClient(KongCacheKey key) throws URISyntaxException { + log.info("Loading Services {} from kong client!", key); + KongEntity kongEntity = this.kongFeignService.findAll(uri(key.getSystemProfile(), ENTITY_URI)); + Collections.sort(kongEntity.getData()); + return new CacheResults<>(kongEntity); + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ConsumerService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ConsumerService.java index 12bce62..d95be41 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ConsumerService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ConsumerService.java @@ -1,12 +1,14 @@ package com.kongx.serve.service.gateway; +import com.github.pagehelper.util.StringUtil; import com.kongx.common.cache.CacheResults; import com.kongx.serve.entity.gateway.Consumer; import com.kongx.serve.entity.gateway.KongEntity; import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.feign.ConsumerFeignService; +import com.kongx.serve.feign.CredentialsFeignService; import com.kongx.serve.feign.KongFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.RequestInterceptor; import feign.Target; @@ -20,23 +22,29 @@ import org.springframework.stereotype.Service; import java.net.URISyntaxException; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; @Service("ConsumerService") @Import(FeignClientsConfiguration.class) @Slf4j -public class ConsumerService extends AbstractService> { +public class ConsumerService extends AbstractCacheService> { private static final String CONSUMER_URI = "/consumers"; private static final String CONSUMER_URI_ID = "/consumers/%s"; + private static final String CREDENTIALS_URI = "/consumers/%s/%s"; + private static final String CREDENTIALS_URI_ID = "/consumers/%s/%s/%s"; private static final String CACHE_CONSUMERS_KEY = "LISTS"; private KongFeignService kongFeignService; + private KongFeignService credentialsFeignService; @Autowired public ConsumerService(Decoder decoder, Encoder encoder, RequestInterceptor requestInterceptor) { kongFeignService = Feign.builder().encoder(encoder).decoder(decoder) - .requestInterceptor(requestInterceptor).target(Target.EmptyTarget.create(ConsumerFeignService.class)) - ; + .requestInterceptor(requestInterceptor).target(Target.EmptyTarget.create(ConsumerFeignService.class)); + credentialsFeignService = Feign.builder().encoder(encoder).decoder(decoder) + .requestInterceptor(requestInterceptor).target(Target.EmptyTarget.create(CredentialsFeignService.class)); } /** @@ -48,6 +56,31 @@ public class ConsumerService extends AbstractService> { return this.get(systemProfile, CACHE_CONSUMERS_KEY).getData(); } + public KongEntity findAllCredentials(SystemProfile systemProfile, String customerId, String credentials) throws URISyntaxException { + return this.credentialsFeignService.findAll(uri(systemProfile, String.format(CREDENTIALS_URI, customerId, credentials))); + } + + public Map addCredentials(SystemProfile systemProfile, Map map, String customerId, String credentials) throws URISyntaxException { + return this.credentialsFeignService.add(uri(systemProfile, String.format(CREDENTIALS_URI, customerId, credentials)), trim(map)); + } + + private Map trim(Map map) { + Map results = new HashMap(); + + map.keySet().stream().forEach((key) -> { + Object value = map.get(key); + if (value != null && !StringUtil.isEmpty(value.toString())) { + results.put(key, value); + } + }); + return results; + } + + public KongEntity removeCredentials(SystemProfile systemProfile, String customerId, String credentials, String id) throws Exception { + this.credentialsFeignService.remove(uri(systemProfile, String.format(CREDENTIALS_URI_ID, customerId, credentials, id))); + return this.findAllCredentials(systemProfile, customerId, credentials); + } + /** * 新增upstream * diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/KongInfoService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/KongInfoService.java index 8396a26..fbfd539 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/KongInfoService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/KongInfoService.java @@ -2,7 +2,7 @@ package com.kongx.serve.service.gateway; import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.feign.KongInfoFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.Target; import feign.codec.Decoder; @@ -19,7 +19,7 @@ import java.util.Map; @Slf4j @Service("kongInfoService") @Import(FeignClientsConfiguration.class) -public class KongInfoService extends AbstractService { +public class KongInfoService extends AbstractCacheService { private static final String INFO_URI = "/"; private static final String STATUS_URI = "/status"; diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/PluginService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/PluginService.java index ff832ad..34ec465 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/PluginService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/PluginService.java @@ -4,7 +4,7 @@ import com.kongx.serve.entity.gateway.*; import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.feign.PluginFeignService; import com.kongx.serve.feign.PluginVOFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.Target; import feign.codec.Decoder; @@ -23,10 +23,11 @@ import java.util.Map; @Slf4j @Component("pluginService") @Import(FeignClientsConfiguration.class) -public class PluginService extends AbstractService { +public class PluginService extends AbstractCacheService { private static final String PLUGIN_URI = "/plugins"; private static final String PLUGIN_ROUTE_URI = "/routes/%s/plugins"; private static final String PLUGIN_SERVICE_URI = "/services/%s/plugins"; + private static final String PLUGIN_CONSUMER_URI = "/consumers/%s/plugins"; private static final String PLUGIN_URI_ID = "/plugins/%s"; private static final String PLUGIN_URI_SCHEMA_NAME = "/plugins/schema/%s"; @@ -101,6 +102,12 @@ public class PluginService extends AbstractService { return routeKongEntity; } + public KongEntity findAllByConsumer(SystemProfile systemProfile, String serviceId) throws URISyntaxException { + KongEntity routeKongEntity = this.pluginVOFeignService.findAll(uri(systemProfile, String.format(PLUGIN_CONSUMER_URI, serviceId))); + Collections.sort(routeKongEntity.getData()); + return routeKongEntity; + } + public Plugin add(SystemProfile systemProfile, Plugin plugin) throws URISyntaxException { return this.kongFeignService.add(uri(systemProfile, PLUGIN_URI), plugin); } @@ -113,6 +120,10 @@ public class PluginService extends AbstractService { return this.kongFeignService.add(uri(systemProfile, String.format(PLUGIN_SERVICE_URI, serviceId)), plugin); } + public Plugin addByConsumer(SystemProfile systemProfile, String consumerId, Plugin plugin) throws URISyntaxException { + return this.kongFeignService.add(uri(systemProfile, String.format(PLUGIN_CONSUMER_URI, consumerId)), plugin); + } + public Plugin update(SystemProfile systemProfile, String id, Plugin plugin) throws URISyntaxException { //先删除,再更新 try { diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/RouteService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/RouteService.java index 4fe3aa6..88587b2 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/RouteService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/RouteService.java @@ -7,7 +7,7 @@ import com.kongx.serve.entity.gateway.KongEntity; import com.kongx.serve.entity.gateway.Route; import com.kongx.serve.feign.KongFeignService; import com.kongx.serve.feign.RouteFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.Target; import feign.codec.Decoder; @@ -24,7 +24,7 @@ import java.util.Collections; @Slf4j @Component("routeService") @Import(FeignClientsConfiguration.class) -public class RouteService extends AbstractService> { +public class RouteService extends AbstractCacheService> { private static final String CACHE_ROUTES_KEY = "LISTS"; private static final String ROUTE_URI = "/routes"; private static final String ROUTE_URI_ID = "/routes/%s"; diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ServiceService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ServiceService.java index ef42885..abd71ca 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ServiceService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/ServiceService.java @@ -6,7 +6,7 @@ import com.kongx.serve.entity.gateway.KongEntity; import com.kongx.serve.entity.gateway.Service; import com.kongx.serve.feign.KongFeignService; import com.kongx.serve.feign.ServiceFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.Target; import feign.codec.Decoder; @@ -22,7 +22,7 @@ import java.util.Collections; @Slf4j @org.springframework.stereotype.Service("serviceService") @Import(FeignClientsConfiguration.class) -public class ServiceService extends AbstractService> { +public class ServiceService extends AbstractCacheService> { private static final String CACHE_SERVICES_KEY = "LISTS"; private static final String SERVICE_URI = "/services"; private static final String SERVICE_URI_ID = "/services/%s"; diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/SniService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/SniService.java new file mode 100644 index 0000000..c797a95 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/SniService.java @@ -0,0 +1,47 @@ +package com.kongx.serve.service.gateway; + +import com.kongx.common.cache.CacheResults; +import com.kongx.serve.entity.gateway.KongEntity; +import com.kongx.serve.entity.gateway.Sni; +import com.kongx.serve.feign.SniFeignService; +import com.kongx.serve.service.GatewayService; +import feign.Feign; +import feign.RequestInterceptor; +import feign.Target; +import feign.codec.Decoder; +import feign.codec.Encoder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.openfeign.FeignClientsConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Service; + +import java.net.URISyntaxException; +import java.util.Collections; + +@Service("sniService") +@Import(FeignClientsConfiguration.class) +@Slf4j +public class SniService extends GatewayService { + @Autowired + public SniService(Decoder decoder, Encoder encoder, RequestInterceptor requestInterceptor) { + kongFeignService = Feign.builder().encoder(encoder).decoder(decoder) + .requestInterceptor(requestInterceptor).target(Target.EmptyTarget.create(SniFeignService.class)); + ENTITY_URI = "/snis"; + ENTITY_URI_ID = "/snis/%s"; + CACHE_KEY = "LISTS"; + } + + @Override + protected String prefix() { + return "SNIS"; + } + + @Override + protected CacheResults> loadFromClient(KongCacheKey key) throws URISyntaxException { + log.info("Loading Services {} from kong client!", key); + KongEntity kongEntity = this.kongFeignService.findAll(uri(key.getSystemProfile(), ENTITY_URI)); + Collections.sort(kongEntity.getData()); + return new CacheResults<>(kongEntity); + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/TargetService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/TargetService.java index 54f7bf9..7949f75 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/TargetService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/TargetService.java @@ -7,7 +7,7 @@ import com.kongx.serve.entity.gateway.TargetHealth; import com.kongx.serve.feign.KongFeignService; import com.kongx.serve.feign.TargetFeignService; import com.kongx.serve.feign.TargetHealthFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.codec.Decoder; import feign.codec.Encoder; @@ -22,7 +22,7 @@ import java.net.URISyntaxException; @Service("targetService") @Import(FeignClientsConfiguration.class) @Slf4j -public class TargetService extends AbstractService { +public class TargetService extends AbstractCacheService { private static final String TARGET_URI = "/upstreams/%s/targets"; private static final String TARGET_URI_HEALTH = "/upstreams/%s/health/"; private static final String TARGET_URI_ID = "/upstreams/%s/targets/%s"; diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/UpstreamService.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/UpstreamService.java index 2237350..ccbfc6b 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/UpstreamService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/UpstreamService.java @@ -2,11 +2,11 @@ package com.kongx.serve.service.gateway; import com.kongx.common.cache.CacheResults; import com.kongx.serve.entity.gateway.KongEntity; -import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.entity.gateway.Upstream; +import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.feign.KongFeignService; import com.kongx.serve.feign.UpstreamFeignService; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import feign.Feign; import feign.RequestInterceptor; import feign.Target; @@ -24,7 +24,7 @@ import java.util.Collections; @Service("upstreamService") @Import(FeignClientsConfiguration.class) @Slf4j -public class UpstreamService extends AbstractService> { +public class UpstreamService extends AbstractCacheService> { private static final String UPSTREAM_URI = "/upstreams"; private static final String UPSTREAM_URI_ID = "/upstreams/%s"; diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/AbstractSyncHandler.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/AbstractSyncHandler.java index bc0cf08..0e86445 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/AbstractSyncHandler.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/AbstractSyncHandler.java @@ -38,11 +38,35 @@ public abstract class AbstractSyncHandler implements ISyncHandler { @Autowired protected SyncLogService syncLogService; + @Autowired + protected SniService sniService; + + @Autowired + protected ConsumerService consumerService; + + @Autowired + protected CertificateService certificateService; + + @Autowired + protected CaCertificateService caCertificateService; + + + protected SyncLog syncLog(SyncConfig syncConfig, Object content, SystemProfile src, SystemProfile dest, String comment) { + SyncLog syncLog = new SyncLog(); + syncLog.setContent(content); + syncLog.setSyncNo(syncConfig.getSyncNo()); + syncLog.setSrc_client(src.getUrl()); + syncLog.setDest_client(dest.getUrl()); + syncLog.setComment(comment); + return syncLog; + } protected SyncLog syncLog(SyncConfig syncConfig, Object content, Service service, SystemProfile src, SystemProfile dest) { SyncLog syncLog = new SyncLog(); syncLog.setContent(content); - syncLog.setService(service.getName()); + if (service != null) { + syncLog.setService(service.getName()); + } syncLog.setSyncNo(syncConfig.getSyncNo()); syncLog.setSrc_client(src.getUrl()); syncLog.setDest_client(dest.getUrl()); diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/DefaultSyncHandler.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/DefaultSyncHandler.java index 8261773..3ec1b39 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/DefaultSyncHandler.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/DefaultSyncHandler.java @@ -1,10 +1,12 @@ package com.kongx.serve.service.gateway.handler; -import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.entity.gateway.Service; import com.kongx.serve.entity.gateway.SyncConfig; +import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.service.gateway.ISyncHandler; +import org.springframework.stereotype.Component; +@Component("defaultSyncHandler") public class DefaultSyncHandler extends AbstractSyncHandler { @Override public ISyncHandler handler(SystemProfile srcClient, SystemProfile destClient, Service service, SyncConfig syncConfig, Object... values) throws Exception { diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/SyncConsumersHandler.java b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/SyncConsumersHandler.java new file mode 100644 index 0000000..15ebfa8 --- /dev/null +++ b/kongx-serve/src/main/java/com/kongx/serve/service/gateway/handler/SyncConsumersHandler.java @@ -0,0 +1,46 @@ +package com.kongx.serve.service.gateway.handler; + +import com.kongx.serve.entity.gateway.*; +import com.kongx.serve.entity.system.SystemProfile; +import com.kongx.serve.service.gateway.ISyncHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component("syncConsumersHandler") +public class SyncConsumersHandler extends SyncPluginsHandler { + + + @Override + public ISyncHandler handler(SystemProfile srcClient, SystemProfile destClient, Service service, SyncConfig syncConfig, Object... values) throws Exception { + KongEntity consumerKongEntity = this.consumerService.findAll(srcClient); + consumerKongEntity.getData().forEach((consumer -> { + try { + this.syncEntity(syncConfig, consumer, srcClient, destClient); + } catch (Exception e) { + e.printStackTrace(); + } + })); + return null; + } + + private void syncEntity(SyncConfig syncConfig, Consumer consumer, SystemProfile srcClient, SystemProfile destClient) throws Exception { + KongEntity plugins = pluginService.findAllByConsumer(srcClient, consumer.getId()); + this.consumerService.update(destClient, consumer.getId(), consumer); + for (PluginVO plugin : plugins.getData()) { + EntityId entityId = new EntityId(); + entityId.setId(consumer.getId()); + plugin.setService(entityId); + if (consumer != null) { + plugin.setScope("global"); + Map map = new HashMap(); + map.put("name", consumer.getId()); + plugin.setApplyObject(map); + } + this.syncPlugin(syncConfig, plugin, null, srcClient, destClient); + } + } +} diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/system/ServerConfigService.java b/kongx-serve/src/main/java/com/kongx/serve/service/system/ServerConfigService.java index aafb956..c0c58a5 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/system/ServerConfigService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/system/ServerConfigService.java @@ -4,7 +4,7 @@ import com.kongx.common.cache.CacheResults; import com.kongx.serve.entity.system.ServerConfig; import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.mapper.ServerConfigMapper; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,7 +15,7 @@ import java.util.List; @Slf4j @Service("ServerConfigService") -public class ServerConfigService extends AbstractService> { +public class ServerConfigService extends AbstractCacheService> { private static final String SERVERS_CONFIGS_KEY = "LISTS"; @Autowired private ServerConfigMapper serverConfigMapper; @@ -48,7 +48,7 @@ public class ServerConfigService extends AbstractService> { public URI findUriByCode(SystemProfile systemProfile, String code) throws Exception { ServerConfig serverConfig = serverConfigService.findByKey(code); - SystemProfile.System system = systemProfile.to(serverConfig.getConfigValue()); + SystemProfile.System system = systemProfile.to(serverConfig.getConfigValue().toString()); if (system == null) throw new Exception("Please set Hot config url"); String url = system.getUrl(); if (url.endsWith("/")) { diff --git a/kongx-serve/src/main/java/com/kongx/serve/service/system/SystemProfileService.java b/kongx-serve/src/main/java/com/kongx/serve/service/system/SystemProfileService.java index a2c6df9..045c5cb 100644 --- a/kongx-serve/src/main/java/com/kongx/serve/service/system/SystemProfileService.java +++ b/kongx-serve/src/main/java/com/kongx/serve/service/system/SystemProfileService.java @@ -4,7 +4,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.kongx.serve.entity.system.SystemProfile; import com.kongx.serve.mapper.SystemProfileMapper; -import com.kongx.serve.service.AbstractService; +import com.kongx.serve.service.AbstractCacheService; import com.kongx.serve.service.gateway.KongInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,7 +15,7 @@ import java.util.List; import java.util.Map; @Service("SystemProfileService") -public class SystemProfileService extends AbstractService { +public class SystemProfileService extends AbstractCacheService { @Autowired private SystemProfileMapper systemProfileMapper; diff --git a/kongx-serve/src/main/resources/static/cdn/vue/2.5.2/vue.min.js b/kongx-serve/src/main/resources/static/cdn/vue/2.5.2/vue.min.js deleted file mode 100644 index cdceac0..0000000 --- a/kongx-serve/src/main/resources/static/cdn/vue/2.5.2/vue.min.js +++ /dev/null @@ -1,10552 +0,0 @@ -/*! - * Vue.js v2.5.2 - * (c) 2014-2017 Evan You - * Released under the MIT License. - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.Vue = factory()); -}(this, (function () { 'use strict'; - -/* */ - -// these helpers produces better vm code in JS engines due to their -// explicitness and function inlining -function isUndef (v) { - return v === undefined || v === null -} - -function isDef (v) { - return v !== undefined && v !== null -} - -function isTrue (v) { - return v === true -} - -function isFalse (v) { - return v === false -} - -/** - * Check if value is primitive - */ -function isPrimitive (value) { - return ( - typeof value === 'string' || - typeof value === 'number' || - typeof value === 'boolean' - ) -} - -/** - * Quick object check - this is primarily used to tell - * Objects from primitive values when we know the value - * is a JSON-compliant type. - */ -function isObject (obj) { - return obj !== null && typeof obj === 'object' -} - -/** - * Get the raw type string of a value e.g. [object Object] - */ -var _toString = Object.prototype.toString; - -function toRawType (value) { - return _toString.call(value).slice(8, -1) -} - -/** - * Strict object type check. Only returns true - * for plain JavaScript objects. - */ -function isPlainObject (obj) { - return _toString.call(obj) === '[object Object]' -} - -function isRegExp (v) { - return _toString.call(v) === '[object RegExp]' -} - -/** - * Check if val is a valid array index. - */ -function isValidArrayIndex (val) { - var n = parseFloat(String(val)); - return n >= 0 && Math.floor(n) === n && isFinite(val) -} - -/** - * Convert a value to a string that is actually rendered. - */ -function toString (val) { - return val == null - ? '' - : typeof val === 'object' - ? JSON.stringify(val, null, 2) - : String(val) -} - -/** - * Convert a input value to a number for persistence. - * If the conversion fails, return original string. - */ -function toNumber (val) { - var n = parseFloat(val); - return isNaN(n) ? val : n -} - -/** - * Make a map and return a function for checking if a key - * is in that map. - */ -function makeMap ( - str, - expectsLowerCase -) { - var map = Object.create(null); - var list = str.split(','); - for (var i = 0; i < list.length; i++) { - map[list[i]] = true; - } - return expectsLowerCase - ? function (val) { return map[val.toLowerCase()]; } - : function (val) { return map[val]; } -} - -/** - * Check if a tag is a built-in tag. - */ -var isBuiltInTag = makeMap('slot,component', true); - -/** - * Check if a attribute is a reserved attribute. - */ -var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); - -/** - * Remove an item from an array - */ -function remove (arr, item) { - if (arr.length) { - var index = arr.indexOf(item); - if (index > -1) { - return arr.splice(index, 1) - } - } -} - -/** - * Check whether the object has the property. - */ -var hasOwnProperty = Object.prototype.hasOwnProperty; -function hasOwn (obj, key) { - return hasOwnProperty.call(obj, key) -} - -/** - * Create a cached version of a pure function. - */ -function cached (fn) { - var cache = Object.create(null); - return (function cachedFn (str) { - var hit = cache[str]; - return hit || (cache[str] = fn(str)) - }) -} - -/** - * Camelize a hyphen-delimited string. - */ -var camelizeRE = /-(\w)/g; -var camelize = cached(function (str) { - return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) -}); - -/** - * Capitalize a string. - */ -var capitalize = cached(function (str) { - return str.charAt(0).toUpperCase() + str.slice(1) -}); - -/** - * Hyphenate a camelCase string. - */ -var hyphenateRE = /\B([A-Z])/g; -var hyphenate = cached(function (str) { - return str.replace(hyphenateRE, '-$1').toLowerCase() -}); - -/** - * Simple bind, faster than native - */ -function bind (fn, ctx) { - function boundFn (a) { - var l = arguments.length; - return l - ? l > 1 - ? fn.apply(ctx, arguments) - : fn.call(ctx, a) - : fn.call(ctx) - } - // record original fn length - boundFn._length = fn.length; - return boundFn -} - -/** - * Convert an Array-like object to a real Array. - */ -function toArray (list, start) { - start = start || 0; - var i = list.length - start; - var ret = new Array(i); - while (i--) { - ret[i] = list[i + start]; - } - return ret -} - -/** - * Mix properties into target object. - */ -function extend (to, _from) { - for (var key in _from) { - to[key] = _from[key]; - } - return to -} - -/** - * Merge an Array of Objects into a single Object. - */ -function toObject (arr) { - var res = {}; - for (var i = 0; i < arr.length; i++) { - if (arr[i]) { - extend(res, arr[i]); - } - } - return res -} - -/** - * Perform no operation. - * Stubbing args to make Flow happy without leaving useless transpiled code - * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/) - */ -function noop (a, b, c) {} - -/** - * Always return false. - */ -var no = function (a, b, c) { return false; }; - -/** - * Return same value - */ -var identity = function (_) { return _; }; - -/** - * Generate a static keys string from compiler modules. - */ -function genStaticKeys (modules) { - return modules.reduce(function (keys, m) { - return keys.concat(m.staticKeys || []) - }, []).join(',') -} - -/** - * Check if two values are loosely equal - that is, - * if they are plain objects, do they have the same shape? - */ -function looseEqual (a, b) { - if (a === b) { return true } - var isObjectA = isObject(a); - var isObjectB = isObject(b); - if (isObjectA && isObjectB) { - try { - var isArrayA = Array.isArray(a); - var isArrayB = Array.isArray(b); - if (isArrayA && isArrayB) { - return a.length === b.length && a.every(function (e, i) { - return looseEqual(e, b[i]) - }) - } else if (!isArrayA && !isArrayB) { - var keysA = Object.keys(a); - var keysB = Object.keys(b); - return keysA.length === keysB.length && keysA.every(function (key) { - return looseEqual(a[key], b[key]) - }) - } else { - /* istanbul ignore next */ - return false - } - } catch (e) { - /* istanbul ignore next */ - return false - } - } else if (!isObjectA && !isObjectB) { - return String(a) === String(b) - } else { - return false - } -} - -function looseIndexOf (arr, val) { - for (var i = 0; i < arr.length; i++) { - if (looseEqual(arr[i], val)) { return i } - } - return -1 -} - -/** - * Ensure a function is called only once. - */ -function once (fn) { - var called = false; - return function () { - if (!called) { - called = true; - fn.apply(this, arguments); - } - } -} - -var SSR_ATTR = 'data-server-rendered'; - -var ASSET_TYPES = [ - 'component', - 'directive', - 'filter' -]; - -var LIFECYCLE_HOOKS = [ - 'beforeCreate', - 'created', - 'beforeMount', - 'mounted', - 'beforeUpdate', - 'updated', - 'beforeDestroy', - 'destroyed', - 'activated', - 'deactivated', - 'errorCaptured' -]; - -/* */ - -var config = ({ - /** - * Option merge strategies (used in core/util/options) - */ - optionMergeStrategies: Object.create(null), - - /** - * Whether to suppress warnings. - */ - silent: false, - - /** - * Show production mode tip message on boot? - */ - productionTip: "development" !== 'production', - - /** - * Whether to enable devtools - */ - devtools: "development" !== 'production', - - /** - * Whether to record perf - */ - performance: false, - - /** - * Error handler for watcher errors - */ - errorHandler: null, - - /** - * Warn handler for watcher warns - */ - warnHandler: null, - - /** - * Ignore certain custom elements - */ - ignoredElements: [], - - /** - * Custom user key aliases for v-on - */ - keyCodes: Object.create(null), - - /** - * Check if a tag is reserved so that it cannot be registered as a - * component. This is platform-dependent and may be overwritten. - */ - isReservedTag: no, - - /** - * Check if an attribute is reserved so that it cannot be used as a component - * prop. This is platform-dependent and may be overwritten. - */ - isReservedAttr: no, - - /** - * Check if a tag is an unknown element. - * Platform-dependent. - */ - isUnknownElement: no, - - /** - * Get the namespace of an element - */ - getTagNamespace: noop, - - /** - * Parse the real tag name for the specific platform. - */ - parsePlatformTagName: identity, - - /** - * Check if an attribute must be bound using property, e.g. value - * Platform-dependent. - */ - mustUseProp: no, - - /** - * Exposed for legacy reasons - */ - _lifecycleHooks: LIFECYCLE_HOOKS -}); - -/* */ - -var emptyObject = Object.freeze({}); - -/** - * Check if a string starts with $ or _ - */ -function isReserved (str) { - var c = (str + '').charCodeAt(0); - return c === 0x24 || c === 0x5F -} - -/** - * Define a property. - */ -function def (obj, key, val, enumerable) { - Object.defineProperty(obj, key, { - value: val, - enumerable: !!enumerable, - writable: true, - configurable: true - }); -} - -/** - * Parse simple path. - */ -var bailRE = /[^\w.$]/; -function parsePath (path) { - if (bailRE.test(path)) { - return - } - var segments = path.split('.'); - return function (obj) { - for (var i = 0; i < segments.length; i++) { - if (!obj) { return } - obj = obj[segments[i]]; - } - return obj - } -} - -/* */ - -// can we use __proto__? -var hasProto = '__proto__' in {}; - -// Browser environment sniffing -var inBrowser = typeof window !== 'undefined'; -var UA = inBrowser && window.navigator.userAgent.toLowerCase(); -var isIE = UA && /msie|trident/.test(UA); -var isIE9 = UA && UA.indexOf('msie 9.0') > 0; -var isEdge = UA && UA.indexOf('edge/') > 0; -var isAndroid = UA && UA.indexOf('android') > 0; -var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); -var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; - -// Firefox has a "watch" function on Object.prototype... -var nativeWatch = ({}).watch; - -var supportsPassive = false; -if (inBrowser) { - try { - var opts = {}; - Object.defineProperty(opts, 'passive', ({ - get: function get () { - /* istanbul ignore next */ - supportsPassive = true; - } - })); // https://github.com/facebook/flow/issues/285 - window.addEventListener('test-passive', null, opts); - } catch (e) {} -} - -// this needs to be lazy-evaled because vue may be required before -// vue-server-renderer can set VUE_ENV -var _isServer; -var isServerRendering = function () { - if (_isServer === undefined) { - /* istanbul ignore if */ - if (!inBrowser && typeof global !== 'undefined') { - // detect presence of vue-server-renderer and avoid - // Webpack shimming the process - _isServer = global['process'].env.VUE_ENV === 'server'; - } else { - _isServer = false; - } - } - return _isServer -}; - -// detect devtools -var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; - -/* istanbul ignore next */ -function isNative (Ctor) { - return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) -} - -var hasSymbol = - typeof Symbol !== 'undefined' && isNative(Symbol) && - typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys); - -var _Set; -/* istanbul ignore if */ // $flow-disable-line -if (typeof Set !== 'undefined' && isNative(Set)) { - // use native Set when available. - _Set = Set; -} else { - // a non-standard Set polyfill that only works with primitive keys. - _Set = (function () { - function Set () { - this.set = Object.create(null); - } - Set.prototype.has = function has (key) { - return this.set[key] === true - }; - Set.prototype.add = function add (key) { - this.set[key] = true; - }; - Set.prototype.clear = function clear () { - this.set = Object.create(null); - }; - - return Set; - }()); -} - -/* */ - -var warn = noop; -var tip = noop; -var generateComponentTrace = (noop); // work around flow check -var formatComponentName = (noop); - -{ - var hasConsole = typeof console !== 'undefined'; - var classifyRE = /(?:^|[-_])(\w)/g; - var classify = function (str) { return str - .replace(classifyRE, function (c) { return c.toUpperCase(); }) - .replace(/[-_]/g, ''); }; - - warn = function (msg, vm) { - var trace = vm ? generateComponentTrace(vm) : ''; - - if (config.warnHandler) { - config.warnHandler.call(null, msg, vm, trace); - } else if (hasConsole && (!config.silent)) { - console.error(("[Vue warn]: " + msg + trace)); - } - }; - - tip = function (msg, vm) { - if (hasConsole && (!config.silent)) { - console.warn("[Vue tip]: " + msg + ( - vm ? generateComponentTrace(vm) : '' - )); - } - }; - - formatComponentName = function (vm, includeFile) { - if (vm.$root === vm) { - return '' - } - var options = typeof vm === 'function' && vm.cid != null - ? vm.options - : vm._isVue - ? vm.$options || vm.constructor.options - : vm || {}; - var name = options.name || options._componentTag; - var file = options.__file; - if (!name && file) { - var match = file.match(/([^/\\]+)\.vue$/); - name = match && match[1]; - } - - return ( - (name ? ("<" + (classify(name)) + ">") : "") + - (file && includeFile !== false ? (" at " + file) : '') - ) - }; - - var repeat = function (str, n) { - var res = ''; - while (n) { - if (n % 2 === 1) { res += str; } - if (n > 1) { str += str; } - n >>= 1; - } - return res - }; - - generateComponentTrace = function (vm) { - if (vm._isVue && vm.$parent) { - var tree = []; - var currentRecursiveSequence = 0; - while (vm) { - if (tree.length > 0) { - var last = tree[tree.length - 1]; - if (last.constructor === vm.constructor) { - currentRecursiveSequence++; - vm = vm.$parent; - continue - } else if (currentRecursiveSequence > 0) { - tree[tree.length - 1] = [last, currentRecursiveSequence]; - currentRecursiveSequence = 0; - } - } - tree.push(vm); - vm = vm.$parent; - } - return '\n\nfound in\n\n' + tree - .map(function (vm, i) { return ("" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm) - ? ((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)") - : formatComponentName(vm))); }) - .join('\n') - } else { - return ("\n\n(found in " + (formatComponentName(vm)) + ")") - } - }; -} - -/* */ - - -var uid = 0; - -/** - * A dep is an observable that can have multiple - * directives subscribing to it. - */ -var Dep = function Dep () { - this.id = uid++; - this.subs = []; -}; - -Dep.prototype.addSub = function addSub (sub) { - this.subs.push(sub); -}; - -Dep.prototype.removeSub = function removeSub (sub) { - remove(this.subs, sub); -}; - -Dep.prototype.depend = function depend () { - if (Dep.target) { - Dep.target.addDep(this); - } -}; - -Dep.prototype.notify = function notify () { - // stabilize the subscriber list first - var subs = this.subs.slice(); - for (var i = 0, l = subs.length; i < l; i++) { - subs[i].update(); - } -}; - -// the current target watcher being evaluated. -// this is globally unique because there could be only one -// watcher being evaluated at any time. -Dep.target = null; -var targetStack = []; - -function pushTarget (_target) { - if (Dep.target) { targetStack.push(Dep.target); } - Dep.target = _target; -} - -function popTarget () { - Dep.target = targetStack.pop(); -} - -/* */ - -var VNode = function VNode ( - tag, - data, - children, - text, - elm, - context, - componentOptions, - asyncFactory -) { - this.tag = tag; - this.data = data; - this.children = children; - this.text = text; - this.elm = elm; - this.ns = undefined; - this.context = context; - this.functionalContext = undefined; - this.functionalOptions = undefined; - this.functionalScopeId = undefined; - this.key = data && data.key; - this.componentOptions = componentOptions; - this.componentInstance = undefined; - this.parent = undefined; - this.raw = false; - this.isStatic = false; - this.isRootInsert = true; - this.isComment = false; - this.isCloned = false; - this.isOnce = false; - this.asyncFactory = asyncFactory; - this.asyncMeta = undefined; - this.isAsyncPlaceholder = false; -}; - -var prototypeAccessors = { child: { configurable: true } }; - -// DEPRECATED: alias for componentInstance for backwards compat. -/* istanbul ignore next */ -prototypeAccessors.child.get = function () { - return this.componentInstance -}; - -Object.defineProperties( VNode.prototype, prototypeAccessors ); - -var createEmptyVNode = function (text) { - if ( text === void 0 ) text = ''; - - var node = new VNode(); - node.text = text; - node.isComment = true; - return node -}; - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} - -// optimized shallow clone -// used for static nodes and slot nodes because they may be reused across -// multiple renders, cloning them avoids errors when DOM manipulations rely -// on their elm reference. -function cloneVNode (vnode, deep) { - var cloned = new VNode( - vnode.tag, - vnode.data, - vnode.children, - vnode.text, - vnode.elm, - vnode.context, - vnode.componentOptions, - vnode.asyncFactory - ); - cloned.ns = vnode.ns; - cloned.isStatic = vnode.isStatic; - cloned.key = vnode.key; - cloned.isComment = vnode.isComment; - cloned.isCloned = true; - if (deep && vnode.children) { - cloned.children = cloneVNodes(vnode.children); - } - return cloned -} - -function cloneVNodes (vnodes, deep) { - var len = vnodes.length; - var res = new Array(len); - for (var i = 0; i < len; i++) { - res[i] = cloneVNode(vnodes[i], deep); - } - return res -} - -/* - * not type checking this file because flow doesn't play well with - * dynamically accessing methods on Array prototype - */ - -var arrayProto = Array.prototype; -var arrayMethods = Object.create(arrayProto);[ - 'push', - 'pop', - 'shift', - 'unshift', - 'splice', - 'sort', - 'reverse' -] -.forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator () { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - case 'unshift': - inserted = args; - break - case 'splice': - inserted = args.slice(2); - break - } - if (inserted) { ob.observeArray(inserted); } - // notify change - ob.dep.notify(); - return result - }); -}); - -/* */ - -var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - -/** - * By default, when a reactive property is set, the new value is - * also converted to become reactive. However when passing down props, - * we don't want to force conversion because the value may be a nested value - * under a frozen data structure. Converting it would defeat the optimization. - */ -var observerState = { - shouldConvert: true -}; - -/** - * Observer class that are attached to each observed - * object. Once attached, the observer converts target - * object's property keys into getter/setters that - * collect dependencies and dispatches updates. - */ -var Observer = function Observer (value) { - this.value = value; - this.dep = new Dep(); - this.vmCount = 0; - def(value, '__ob__', this); - if (Array.isArray(value)) { - var augment = hasProto - ? protoAugment - : copyAugment; - augment(value, arrayMethods, arrayKeys); - this.observeArray(value); - } else { - this.walk(value); - } -}; - -/** - * Walk through each property and convert them into - * getter/setters. This method should only be called when - * value type is Object. - */ -Observer.prototype.walk = function walk (obj) { - var keys = Object.keys(obj); - for (var i = 0; i < keys.length; i++) { - defineReactive(obj, keys[i], obj[keys[i]]); - } -}; - -/** - * Observe a list of Array items. - */ -Observer.prototype.observeArray = function observeArray (items) { - for (var i = 0, l = items.length; i < l; i++) { - observe(items[i]); - } -}; - -// helpers - -/** - * Augment an target Object or Array by intercepting - * the prototype chain using __proto__ - */ -function protoAugment (target, src, keys) { - /* eslint-disable no-proto */ - target.__proto__ = src; - /* eslint-enable no-proto */ -} - -/** - * Augment an target Object or Array by defining - * hidden properties. - */ -/* istanbul ignore next */ -function copyAugment (target, src, keys) { - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - def(target, key, src[key]); - } -} - -/** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - */ -function observe (value, asRootData) { - if (!isObject(value) || value instanceof VNode) { - return - } - var ob; - if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - ob = value.__ob__; - } else if ( - observerState.shouldConvert && - !isServerRendering() && - (Array.isArray(value) || isPlainObject(value)) && - Object.isExtensible(value) && - !value._isVue - ) { - ob = new Observer(value); - } - if (asRootData && ob) { - ob.vmCount++; - } - return ob -} - -/** - * Define a reactive property on an Object. - */ -function defineReactive ( - obj, - key, - val, - customSetter, - shallow -) { - var dep = new Dep(); - - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return - } - - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - - var childOb = !shallow && observe(val); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter () { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - dep.depend(); - if (childOb) { - childOb.dep.depend(); - if (Array.isArray(value)) { - dependArray(value); - } - } - } - return value - }, - set: function reactiveSetter (newVal) { - var value = getter ? getter.call(obj) : val; - /* eslint-disable no-self-compare */ - if (newVal === value || (newVal !== newVal && value !== value)) { - return - } - /* eslint-enable no-self-compare */ - if ("development" !== 'production' && customSetter) { - customSetter(); - } - if (setter) { - setter.call(obj, newVal); - } else { - val = newVal; - } - childOb = !shallow && observe(newVal); - dep.notify(); - } - }); -} - -/** - * Set a property on an object. Adds the new property and - * triggers change notification if the property doesn't - * already exist. - */ -function set (target, key, val) { - if (Array.isArray(target) && isValidArrayIndex(key)) { - target.length = Math.max(target.length, key); - target.splice(key, 1, val); - return val - } - if (hasOwn(target, key)) { - target[key] = val; - return val - } - var ob = (target).__ob__; - if (target._isVue || (ob && ob.vmCount)) { - "development" !== 'production' && warn( - 'Avoid adding reactive properties to a Vue instance or its root $data ' + - 'at runtime - declare it upfront in the data option.' - ); - return val - } - if (!ob) { - target[key] = val; - return val - } - defineReactive(ob.value, key, val); - ob.dep.notify(); - return val -} - -/** - * Delete a property and trigger change if necessary. - */ -function del (target, key) { - if (Array.isArray(target) && isValidArrayIndex(key)) { - target.splice(key, 1); - return - } - var ob = (target).__ob__; - if (target._isVue || (ob && ob.vmCount)) { - "development" !== 'production' && warn( - 'Avoid deleting properties on a Vue instance or its root $data ' + - '- just set it to null.' - ); - return - } - if (!hasOwn(target, key)) { - return - } - delete target[key]; - if (!ob) { - return - } - ob.dep.notify(); -} - -/** - * Collect dependencies on array elements when the array is touched, since - * we cannot intercept array element access like property getters. - */ -function dependArray (value) { - for (var e = (void 0), i = 0, l = value.length; i < l; i++) { - e = value[i]; - e && e.__ob__ && e.__ob__.dep.depend(); - if (Array.isArray(e)) { - dependArray(e); - } - } -} - -/* */ - -/** - * Option overwriting strategies are functions that handle - * how to merge a parent option value and a child option - * value into the final value. - */ -var strats = config.optionMergeStrategies; - -/** - * Options with restrictions - */ -{ - strats.el = strats.propsData = function (parent, child, vm, key) { - if (!vm) { - warn( - "option \"" + key + "\" can only be used during instance " + - 'creation with the `new` keyword.' - ); - } - return defaultStrat(parent, child) - }; -} - -/** - * Helper that recursively merges two data objects together. - */ -function mergeData (to, from) { - if (!from) { return to } - var key, toVal, fromVal; - var keys = Object.keys(from); - for (var i = 0; i < keys.length; i++) { - key = keys[i]; - toVal = to[key]; - fromVal = from[key]; - if (!hasOwn(to, key)) { - set(to, key, fromVal); - } else if (isPlainObject(toVal) && isPlainObject(fromVal)) { - mergeData(toVal, fromVal); - } - } - return to -} - -/** - * Data - */ -function mergeDataOrFn ( - parentVal, - childVal, - vm -) { - if (!vm) { - // in a Vue.extend merge, both should be functions - if (!childVal) { - return parentVal - } - if (!parentVal) { - return childVal - } - // when parentVal & childVal are both present, - // we need to return a function that returns the - // merged result of both functions... no need to - // check if parentVal is a function here because - // it has to be a function to pass previous merges. - return function mergedDataFn () { - return mergeData( - typeof childVal === 'function' ? childVal.call(this) : childVal, - typeof parentVal === 'function' ? parentVal.call(this) : parentVal - ) - } - } else if (parentVal || childVal) { - return function mergedInstanceDataFn () { - // instance merge - var instanceData = typeof childVal === 'function' - ? childVal.call(vm) - : childVal; - var defaultData = typeof parentVal === 'function' - ? parentVal.call(vm) - : parentVal; - if (instanceData) { - return mergeData(instanceData, defaultData) - } else { - return defaultData - } - } - } -} - -strats.data = function ( - parentVal, - childVal, - vm -) { - if (!vm) { - if (childVal && typeof childVal !== 'function') { - "development" !== 'production' && warn( - 'The "data" option should be a function ' + - 'that returns a per-instance value in component ' + - 'definitions.', - vm - ); - - return parentVal - } - return mergeDataOrFn.call(this, parentVal, childVal) - } - - return mergeDataOrFn(parentVal, childVal, vm) -}; - -/** - * Hooks and props are merged as arrays. - */ -function mergeHook ( - parentVal, - childVal -) { - return childVal - ? parentVal - ? parentVal.concat(childVal) - : Array.isArray(childVal) - ? childVal - : [childVal] - : parentVal -} - -LIFECYCLE_HOOKS.forEach(function (hook) { - strats[hook] = mergeHook; -}); - -/** - * Assets - * - * When a vm is present (instance creation), we need to do - * a three-way merge between constructor options, instance - * options and parent options. - */ -function mergeAssets ( - parentVal, - childVal, - vm, - key -) { - var res = Object.create(parentVal || null); - if (childVal) { - "development" !== 'production' && assertObjectType(key, childVal, vm); - return extend(res, childVal) - } else { - return res - } -} - -ASSET_TYPES.forEach(function (type) { - strats[type + 's'] = mergeAssets; -}); - -/** - * Watchers. - * - * Watchers hashes should not overwrite one - * another, so we merge them as arrays. - */ -strats.watch = function ( - parentVal, - childVal, - vm, - key -) { - // work around Firefox's Object.prototype.watch... - if (parentVal === nativeWatch) { parentVal = undefined; } - if (childVal === nativeWatch) { childVal = undefined; } - /* istanbul ignore if */ - if (!childVal) { return Object.create(parentVal || null) } - { - assertObjectType(key, childVal, vm); - } - if (!parentVal) { return childVal } - var ret = {}; - extend(ret, parentVal); - for (var key$1 in childVal) { - var parent = ret[key$1]; - var child = childVal[key$1]; - if (parent && !Array.isArray(parent)) { - parent = [parent]; - } - ret[key$1] = parent - ? parent.concat(child) - : Array.isArray(child) ? child : [child]; - } - return ret -}; - -/** - * Other object hashes. - */ -strats.props = -strats.methods = -strats.inject = -strats.computed = function ( - parentVal, - childVal, - vm, - key -) { - if (childVal && "development" !== 'production') { - assertObjectType(key, childVal, vm); - } - if (!parentVal) { return childVal } - var ret = Object.create(null); - extend(ret, parentVal); - if (childVal) { extend(ret, childVal); } - return ret -}; -strats.provide = mergeDataOrFn; - -/** - * Default strategy. - */ -var defaultStrat = function (parentVal, childVal) { - return childVal === undefined - ? parentVal - : childVal -}; - -/** - * Validate component names - */ -function checkComponents (options) { - for (var key in options.components) { - var lower = key.toLowerCase(); - if (isBuiltInTag(lower) || config.isReservedTag(lower)) { - warn( - 'Do not use built-in or reserved HTML elements as component ' + - 'id: ' + key - ); - } - } -} - -/** - * Ensure all props option syntax are normalized into the - * Object-based format. - */ -function normalizeProps (options, vm) { - var props = options.props; - if (!props) { return } - var res = {}; - var i, val, name; - if (Array.isArray(props)) { - i = props.length; - while (i--) { - val = props[i]; - if (typeof val === 'string') { - name = camelize(val); - res[name] = { type: null }; - } else { - warn('props must be strings when using array syntax.'); - } - } - } else if (isPlainObject(props)) { - for (var key in props) { - val = props[key]; - name = camelize(key); - res[name] = isPlainObject(val) - ? val - : { type: val }; - } - } else { - warn( - "Invalid value for option \"props\": expected an Array or an Object, " + - "but got " + (toRawType(props)) + ".", - vm - ); - } - options.props = res; -} - -/** - * Normalize all injections into Object-based format - */ -function normalizeInject (options, vm) { - var inject = options.inject; - var normalized = options.inject = {}; - if (Array.isArray(inject)) { - for (var i = 0; i < inject.length; i++) { - normalized[inject[i]] = { from: inject[i] }; - } - } else if (isPlainObject(inject)) { - for (var key in inject) { - var val = inject[key]; - normalized[key] = isPlainObject(val) - ? extend({ from: key }, val) - : { from: val }; - } - } else if ("development" !== 'production' && inject) { - warn( - "Invalid value for option \"inject\": expected an Array or an Object, " + - "but got " + (toRawType(inject)) + ".", - vm - ); - } -} - -/** - * Normalize raw function directives into object format. - */ -function normalizeDirectives (options) { - var dirs = options.directives; - if (dirs) { - for (var key in dirs) { - var def = dirs[key]; - if (typeof def === 'function') { - dirs[key] = { bind: def, update: def }; - } - } - } -} - -function assertObjectType (name, value, vm) { - if (!isPlainObject(value)) { - warn( - "Invalid value for option \"" + name + "\": expected an Object, " + - "but got " + (toRawType(value)) + ".", - vm - ); - } -} - -/** - * Merge two option objects into a new one. - * Core utility used in both instantiation and inheritance. - */ -function mergeOptions ( - parent, - child, - vm -) { - { - checkComponents(child); - } - - if (typeof child === 'function') { - child = child.options; - } - - normalizeProps(child, vm); - normalizeInject(child, vm); - normalizeDirectives(child); - var extendsFrom = child.extends; - if (extendsFrom) { - parent = mergeOptions(parent, extendsFrom, vm); - } - if (child.mixins) { - for (var i = 0, l = child.mixins.length; i < l; i++) { - parent = mergeOptions(parent, child.mixins[i], vm); - } - } - var options = {}; - var key; - for (key in parent) { - mergeField(key); - } - for (key in child) { - if (!hasOwn(parent, key)) { - mergeField(key); - } - } - function mergeField (key) { - var strat = strats[key] || defaultStrat; - options[key] = strat(parent[key], child[key], vm, key); - } - return options -} - -/** - * Resolve an asset. - * This function is used because child instances need access - * to assets defined in its ancestor chain. - */ -function resolveAsset ( - options, - type, - id, - warnMissing -) { - /* istanbul ignore if */ - if (typeof id !== 'string') { - return - } - var assets = options[type]; - // check local registration variations first - if (hasOwn(assets, id)) { return assets[id] } - var camelizedId = camelize(id); - if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } - var PascalCaseId = capitalize(camelizedId); - if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } - // fallback to prototype chain - var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; - if ("development" !== 'production' && warnMissing && !res) { - warn( - 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, - options - ); - } - return res -} - -/* */ - -function validateProp ( - key, - propOptions, - propsData, - vm -) { - var prop = propOptions[key]; - var absent = !hasOwn(propsData, key); - var value = propsData[key]; - // handle boolean props - if (isType(Boolean, prop.type)) { - if (absent && !hasOwn(prop, 'default')) { - value = false; - } else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) { - value = true; - } - } - // check default value - if (value === undefined) { - value = getPropDefaultValue(vm, prop, key); - // since the default value is a fresh copy, - // make sure to observe it. - var prevShouldConvert = observerState.shouldConvert; - observerState.shouldConvert = true; - observe(value); - observerState.shouldConvert = prevShouldConvert; - } - { - assertProp(prop, key, value, vm, absent); - } - return value -} - -/** - * Get the default value of a prop. - */ -function getPropDefaultValue (vm, prop, key) { - // no default, return undefined - if (!hasOwn(prop, 'default')) { - return undefined - } - var def = prop.default; - // warn against non-factory defaults for Object & Array - if ("development" !== 'production' && isObject(def)) { - warn( - 'Invalid default value for prop "' + key + '": ' + - 'Props with type Object/Array must use a factory function ' + - 'to return the default value.', - vm - ); - } - // the raw prop value was also undefined from previous render, - // return previous default value to avoid unnecessary watcher trigger - if (vm && vm.$options.propsData && - vm.$options.propsData[key] === undefined && - vm._props[key] !== undefined - ) { - return vm._props[key] - } - // call factory function for non-Function types - // a value is Function if its prototype is function even across different execution context - return typeof def === 'function' && getType(prop.type) !== 'Function' - ? def.call(vm) - : def -} - -/** - * Assert whether a prop is valid. - */ -function assertProp ( - prop, - name, - value, - vm, - absent -) { - if (prop.required && absent) { - warn( - 'Missing required prop: "' + name + '"', - vm - ); - return - } - if (value == null && !prop.required) { - return - } - var type = prop.type; - var valid = !type || type === true; - var expectedTypes = []; - if (type) { - if (!Array.isArray(type)) { - type = [type]; - } - for (var i = 0; i < type.length && !valid; i++) { - var assertedType = assertType(value, type[i]); - expectedTypes.push(assertedType.expectedType || ''); - valid = assertedType.valid; - } - } - if (!valid) { - warn( - "Invalid prop: type check failed for prop \"" + name + "\"." + - " Expected " + (expectedTypes.map(capitalize).join(', ')) + - ", got " + (toRawType(value)) + ".", - vm - ); - return - } - var validator = prop.validator; - if (validator) { - if (!validator(value)) { - warn( - 'Invalid prop: custom validator check failed for prop "' + name + '".', - vm - ); - } - } -} - -var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/; - -function assertType (value, type) { - var valid; - var expectedType = getType(type); - if (simpleCheckRE.test(expectedType)) { - var t = typeof value; - valid = t === expectedType.toLowerCase(); - // for primitive wrapper objects - if (!valid && t === 'object') { - valid = value instanceof type; - } - } else if (expectedType === 'Object') { - valid = isPlainObject(value); - } else if (expectedType === 'Array') { - valid = Array.isArray(value); - } else { - valid = value instanceof type; - } - return { - valid: valid, - expectedType: expectedType - } -} - -/** - * Use function string name to check built-in types, - * because a simple equality check will fail when running - * across different vms / iframes. - */ -function getType (fn) { - var match = fn && fn.toString().match(/^\s*function (\w+)/); - return match ? match[1] : '' -} - -function isType (type, fn) { - if (!Array.isArray(fn)) { - return getType(fn) === getType(type) - } - for (var i = 0, len = fn.length; i < len; i++) { - if (getType(fn[i]) === getType(type)) { - return true - } - } - /* istanbul ignore next */ - return false -} - -/* */ - -function handleError (err, vm, info) { - if (vm) { - var cur = vm; - while ((cur = cur.$parent)) { - var hooks = cur.$options.errorCaptured; - if (hooks) { - for (var i = 0; i < hooks.length; i++) { - try { - var capture = hooks[i].call(cur, err, vm, info) === false; - if (capture) { return } - } catch (e) { - globalHandleError(e, cur, 'errorCaptured hook'); - } - } - } - } - } - globalHandleError(err, vm, info); -} - -function globalHandleError (err, vm, info) { - if (config.errorHandler) { - try { - return config.errorHandler.call(null, err, vm, info) - } catch (e) { - logError(e, null, 'config.errorHandler'); - } - } - logError(err, vm, info); -} - -function logError (err, vm, info) { - { - warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm); - } - /* istanbul ignore else */ - if (inBrowser && typeof console !== 'undefined') { - console.error(err); - } else { - throw err - } -} - -/* */ -/* globals MessageChannel */ - -var callbacks = []; -var pending = false; - -function flushCallbacks () { - pending = false; - var copies = callbacks.slice(0); - callbacks.length = 0; - for (var i = 0; i < copies.length; i++) { - copies[i](); - } -} - -// Here we have async deferring wrappers using both micro and macro tasks. -// In < 2.4 we used micro tasks everywhere, but there are some scenarios where -// micro tasks have too high a priority and fires in between supposedly -// sequential events (e.g. #4521, #6690) or even between bubbling of the same -// event (#6566). However, using macro tasks everywhere also has subtle problems -// when state is changed right before repaint (e.g. #6813, out-in transitions). -// Here we use micro task by default, but expose a way to force macro task when -// needed (e.g. in event handlers attached by v-on). -var microTimerFunc; -var macroTimerFunc; -var useMacroTask = false; - -// Determine (macro) Task defer implementation. -// Technically setImmediate should be the ideal choice, but it's only available -// in IE. The only polyfill that consistently queues the callback after all DOM -// events triggered in the same loop is by using MessageChannel. -/* istanbul ignore if */ -if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { - macroTimerFunc = function () { - setImmediate(flushCallbacks); - }; -} else if (typeof MessageChannel !== 'undefined' && ( - isNative(MessageChannel) || - // PhantomJS - MessageChannel.toString() === '[object MessageChannelConstructor]' -)) { - var channel = new MessageChannel(); - var port = channel.port2; - channel.port1.onmessage = flushCallbacks; - macroTimerFunc = function () { - port.postMessage(1); - }; -} else { - /* istanbul ignore next */ - macroTimerFunc = function () { - setTimeout(flushCallbacks, 0); - }; -} - -// Determine MicroTask defer implementation. -/* istanbul ignore next, $flow-disable-line */ -if (typeof Promise !== 'undefined' && isNative(Promise)) { - var p = Promise.resolve(); - microTimerFunc = function () { - p.then(flushCallbacks); - // in problematic UIWebViews, Promise.then doesn't completely break, but - // it can get stuck in a weird state where callbacks are pushed into the - // microtask queue but the queue isn't being flushed, until the browser - // needs to do some other work, e.g. handle a timer. Therefore we can - // "force" the microtask queue to be flushed by adding an empty timer. - if (isIOS) { setTimeout(noop); } - }; -} else { - // fallback to macro - microTimerFunc = macroTimerFunc; -} - -/** - * Wrap a function so that if any code inside triggers state change, - * the changes are queued using a Task instead of a MicroTask. - */ -function withMacroTask (fn) { - return fn._withTask || (fn._withTask = function () { - useMacroTask = true; - var res = fn.apply(null, arguments); - useMacroTask = false; - return res - }) -} - -function nextTick (cb, ctx) { - var _resolve; - callbacks.push(function () { - if (cb) { - try { - cb.call(ctx); - } catch (e) { - handleError(e, ctx, 'nextTick'); - } - } else if (_resolve) { - _resolve(ctx); - } - }); - if (!pending) { - pending = true; - if (useMacroTask) { - macroTimerFunc(); - } else { - microTimerFunc(); - } - } - // $flow-disable-line - if (!cb && typeof Promise !== 'undefined') { - return new Promise(function (resolve) { - _resolve = resolve; - }) - } -} - -/* */ - -var mark; -var measure; - -{ - var perf = inBrowser && window.performance; - /* istanbul ignore if */ - if ( - perf && - perf.mark && - perf.measure && - perf.clearMarks && - perf.clearMeasures - ) { - mark = function (tag) { return perf.mark(tag); }; - measure = function (name, startTag, endTag) { - perf.measure(name, startTag, endTag); - perf.clearMarks(startTag); - perf.clearMarks(endTag); - perf.clearMeasures(name); - }; - } -} - -/* not type checking this file because flow doesn't play well with Proxy */ - -var initProxy; - -{ - var allowedGlobals = makeMap( - 'Infinity,undefined,NaN,isFinite,isNaN,' + - 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + - 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + - 'require' // for Webpack/Browserify - ); - - var warnNonPresent = function (target, key) { - warn( - "Property or method \"" + key + "\" is not defined on the instance but " + - 'referenced during render. Make sure that this property is reactive, ' + - 'either in the data option, or for class-based components, by ' + - 'initializing the property. ' + - 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', - target - ); - }; - - var hasProxy = - typeof Proxy !== 'undefined' && - Proxy.toString().match(/native code/); - - if (hasProxy) { - var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); - config.keyCodes = new Proxy(config.keyCodes, { - set: function set (target, key, value) { - if (isBuiltInModifier(key)) { - warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); - return false - } else { - target[key] = value; - return true - } - } - }); - } - - var hasHandler = { - has: function has (target, key) { - var has = key in target; - var isAllowed = allowedGlobals(key) || key.charAt(0) === '_'; - if (!has && !isAllowed) { - warnNonPresent(target, key); - } - return has || !isAllowed - } - }; - - var getHandler = { - get: function get (target, key) { - if (typeof key === 'string' && !(key in target)) { - warnNonPresent(target, key); - } - return target[key] - } - }; - - initProxy = function initProxy (vm) { - if (hasProxy) { - // determine which proxy handler to use - var options = vm.$options; - var handlers = options.render && options.render._withStripped - ? getHandler - : hasHandler; - vm._renderProxy = new Proxy(vm, handlers); - } else { - vm._renderProxy = vm; - } - }; -} - -/* */ - -var normalizeEvent = cached(function (name) { - var passive = name.charAt(0) === '&'; - name = passive ? name.slice(1) : name; - var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first - name = once$$1 ? name.slice(1) : name; - var capture = name.charAt(0) === '!'; - name = capture ? name.slice(1) : name; - return { - name: name, - once: once$$1, - capture: capture, - passive: passive - } -}); - -function createFnInvoker (fns) { - function invoker () { - var arguments$1 = arguments; - - var fns = invoker.fns; - if (Array.isArray(fns)) { - var cloned = fns.slice(); - for (var i = 0; i < cloned.length; i++) { - cloned[i].apply(null, arguments$1); - } - } else { - // return handler return value for single handlers - return fns.apply(null, arguments) - } - } - invoker.fns = fns; - return invoker -} - -function updateListeners ( - on, - oldOn, - add, - remove$$1, - vm -) { - var name, cur, old, event; - for (name in on) { - cur = on[name]; - old = oldOn[name]; - event = normalizeEvent(name); - if (isUndef(cur)) { - "development" !== 'production' && warn( - "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), - vm - ); - } else if (isUndef(old)) { - if (isUndef(cur.fns)) { - cur = on[name] = createFnInvoker(cur); - } - add(event.name, cur, event.once, event.capture, event.passive); - } else if (cur !== old) { - old.fns = cur; - on[name] = old; - } - } - for (name in oldOn) { - if (isUndef(on[name])) { - event = normalizeEvent(name); - remove$$1(event.name, oldOn[name], event.capture); - } - } -} - -/* */ - -function mergeVNodeHook (def, hookKey, hook) { - var invoker; - var oldHook = def[hookKey]; - - function wrappedHook () { - hook.apply(this, arguments); - // important: remove merged hook to ensure it's called only once - // and prevent memory leak - remove(invoker.fns, wrappedHook); - } - - if (isUndef(oldHook)) { - // no existing hook - invoker = createFnInvoker([wrappedHook]); - } else { - /* istanbul ignore if */ - if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { - // already a merged invoker - invoker = oldHook; - invoker.fns.push(wrappedHook); - } else { - // existing plain hook - invoker = createFnInvoker([oldHook, wrappedHook]); - } - } - - invoker.merged = true; - def[hookKey] = invoker; -} - -/* */ - -function extractPropsFromVNodeData ( - data, - Ctor, - tag -) { - // we are only extracting raw values here. - // validation and default values are handled in the child - // component itself. - var propOptions = Ctor.options.props; - if (isUndef(propOptions)) { - return - } - var res = {}; - var attrs = data.attrs; - var props = data.props; - if (isDef(attrs) || isDef(props)) { - for (var key in propOptions) { - var altKey = hyphenate(key); - { - var keyInLowerCase = key.toLowerCase(); - if ( - key !== keyInLowerCase && - attrs && hasOwn(attrs, keyInLowerCase) - ) { - tip( - "Prop \"" + keyInLowerCase + "\" is passed to component " + - (formatComponentName(tag || Ctor)) + ", but the declared prop name is" + - " \"" + key + "\". " + - "Note that HTML attributes are case-insensitive and camelCased " + - "props need to use their kebab-case equivalents when using in-DOM " + - "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"." - ); - } - } - checkProp(res, props, key, altKey, true) || - checkProp(res, attrs, key, altKey, false); - } - } - return res -} - -function checkProp ( - res, - hash, - key, - altKey, - preserve -) { - if (isDef(hash)) { - if (hasOwn(hash, key)) { - res[key] = hash[key]; - if (!preserve) { - delete hash[key]; - } - return true - } else if (hasOwn(hash, altKey)) { - res[key] = hash[altKey]; - if (!preserve) { - delete hash[altKey]; - } - return true - } - } - return false -} - -/* */ - -// The template compiler attempts to minimize the need for normalization by -// statically analyzing the template at compile time. -// -// For plain HTML markup, normalization can be completely skipped because the -// generated render function is guaranteed to return Array. There are -// two cases where extra normalization is needed: - -// 1. When the children contains components - because a functional component -// may return an Array instead of a single root. In this case, just a simple -// normalization is needed - if any child is an Array, we flatten the whole -// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep -// because functional components already normalize their own children. -function simpleNormalizeChildren (children) { - for (var i = 0; i < children.length; i++) { - if (Array.isArray(children[i])) { - return Array.prototype.concat.apply([], children) - } - } - return children -} - -// 2. When the children contains constructs that always generated nested Arrays, -// e.g.