mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-11 20:15:44 +08:00
Compare commits
50 Commits
develop
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
4f6b3d2e36 | ||
|
0d87486d7a | ||
|
94d7a4e418 | ||
|
3fbaa3ab92 | ||
|
e6d454301f | ||
|
f5c09ac287 | ||
|
e97072a3b1 | ||
|
6d360509c0 | ||
|
464f57adf8 | ||
|
5d08d3b122 | ||
|
d9fc76d3a3 | ||
|
2bc59db340 | ||
|
d58e13da95 | ||
|
e7cb315050 | ||
|
21dc2acfdc | ||
|
823bce2b8b | ||
|
2fb0fce0b1 | ||
|
6456630324 | ||
|
a25ccd6337 | ||
|
538d1c1c45 | ||
|
86bdb06364 | ||
|
7a54427d9c | ||
|
fc9781e6fc | ||
|
ea8834bacd | ||
|
63d9da7429 | ||
|
daa181ccfd | ||
|
f5b9bbb9a7 | ||
|
6de5d51661 | ||
|
4269879d93 | ||
|
0fc7ca904d | ||
|
636ba51bc3 | ||
|
8c5d8747a7 | ||
|
3f02992e13 | ||
|
78b85ebdb6 | ||
|
653332d488 | ||
|
d2da9ca41f | ||
|
6da21f480e | ||
|
e281b74456 | ||
|
529501c007 | ||
|
560b56e9dc | ||
|
8acd94c89a | ||
|
2d8bf001b3 | ||
|
1caeb4ce31 | ||
|
749e6f15f7 | ||
|
2524ca668a | ||
|
6054c057c8 | ||
|
e660c7d874 | ||
|
a5a3659c04 | ||
|
2160e23b91 | ||
|
ef7b97e96a |
@@ -9,3 +9,10 @@ github:
|
||||
squash: true
|
||||
merge: false
|
||||
rebase: false
|
||||
|
||||
notifications:
|
||||
commits: commits@rocketmq.apache.org
|
||||
issues: commits@rocketmq.apache.org
|
||||
pullrequests: commits@rocketmq.apache.org
|
||||
jobs: commits@rocketmq.apache.org
|
||||
discussions: dev@rocketmq.apache.org
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@
|
||||
.project
|
||||
.factorypath
|
||||
.settings/
|
||||
.vscode
|
@@ -20,3 +20,5 @@ script:
|
||||
# - travis_retry mvn -B package findbugs:findbugs coveralls:report
|
||||
#after_success:
|
||||
# - mvn sonar:sonar
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash) -t 996e4d8e-8a00-49f2-b649-38c03716d690 || echo 'Codecov failed to upload'
|
||||
|
2
LICENSE
2
LICENSE
@@ -15,7 +15,7 @@
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (properties) the power, direct or indirect, to cause the
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
||||
Apache RocketMQ
|
||||
Copyright 2016-2021 The Apache Software Foundation
|
||||
Copyright 2016-2022 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
@@ -1,5 +1,7 @@
|
||||
## [Apache RocketMQ](https://github.com/apache/rocketmq) Dashboard [](https://travis-ci.com/github/apache/rocketmq-dashboard) [](https://coveralls.io/github/apache/rocketmq-dashboard?branch=master)
|
||||
## [Apache RocketMQ](https://github.com/apache/rocketmq) Dashboard
|
||||
[](https://travis-ci.com/github/apache/rocketmq-dashboard) [](https://coveralls.io/github/apache/rocketmq-dashboard?branch=master)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://codecov.io/gh/apache/rocketmq-dashboard)
|
||||
[](http://isitmaintained.com/project/apache/rocketmq-dashboard "Average time to resolve an issue")
|
||||
[](http://isitmaintained.com/project/apache/rocketmq-dashboard "Percentage of issues still open")
|
||||
[](https://twitter.com/intent/follow?screen_name=ApacheRocketMQ)
|
||||
|
@@ -63,6 +63,18 @@
|
||||
* 根据消息主题和消息Id进行消息的查询
|
||||
* 消息详情可以展示这条消息的详细信息,查看消息对应到具体消费组的消费情况(如果异常,可以查看具体的异常信息)。可以向指定的消费组重发消息。
|
||||
|
||||
## RocketMQ-V5.0 仪表盘
|
||||
* 版本切换
|
||||
* RocketMQ右上角可切换不同版本,用户可以自主选择 RocketMQ-5.x 或 RocketMQ-4.x 版本
|
||||
* 主题页面
|
||||
* 支持延迟/顺序/事务消息的筛选
|
||||
* 支持延迟/顺序/事物/普通等多种消息类型主题的新增与更新
|
||||
* 消费页面
|
||||
* 支持顺序消费类型订阅组的过滤
|
||||
* 提供顺序消费类型订阅组的新增与更新,如果需要开启顺序消费,FIFO类型的订阅组一定需要打开consumeOrderlyEnable选项
|
||||
* 代理页面(RocketMQ 5.0新增)
|
||||
* 支持代理节点的新增与查询
|
||||
* 支持代理节点地址配置:在application.yml中可对proxyAddr和proxyAddrs属性进行预配置
|
||||
|
||||
## HTTPS 方式访问Dashboard
|
||||
* HTTPS功能实际上是使用SpringBoot提供的配置功能即可完成,首先,需要有一个SSL KeyStore来存放服务端证书,可以使用本工程所提供的测试密钥库:
|
||||
|
@@ -64,6 +64,18 @@
|
||||
* look over this message's detail info.you can see the message's consume state(each group has one line),show the exception message if has exception.
|
||||
you can send this message to the group you selected
|
||||
|
||||
## RocketMQ-V5.0 dashboard
|
||||
* Version switching
|
||||
* RocketMQ can switch between different versions in the upper right corner, and users can freely choose between RocketMQ-5.X or RocketMQ-4.X versions
|
||||
* Theme page
|
||||
* Support filtering of delayed/sequential/transaction messages
|
||||
* Support the addition and update of multiple message types such as delay, sequence, object, and ordinary themes
|
||||
* Consumption page
|
||||
* Support filtering of subscription groups for fifo consumption types
|
||||
* Provide the addition and update of subscription groups for sequential consumption types. If fifo consumption needs to be enabled, FIFO type subscription groups must have the consumeOrderlyEnable option enabled
|
||||
* Proxy page (Added in RocketMQ 5.0)
|
||||
* Support for adding and querying proxy nodes
|
||||
* Support proxy node address configuration: ProxyAddr and proxyAddrs properties can be pre configured in application.yml
|
||||
|
||||
## Access Dashboard with HTTPS
|
||||
* SpringBoot itself has provided the SSL configuration. You can use the project test Keystore:resources/rmqcngkeystore.jks. The store is generated with the following unix keytool commands:
|
||||
|
220
frontend/package-lock.json
generated
220
frontend/package-lock.json
generated
@@ -3577,6 +3577,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"base16": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
|
||||
"integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -4474,6 +4479,14 @@
|
||||
"sha.js": "2.4.11"
|
||||
}
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
|
||||
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
@@ -6242,42 +6255,42 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
|
||||
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
|
||||
"requires": {
|
||||
"accepts": "1.3.7",
|
||||
"accepts": "~1.3.7",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.19.0",
|
||||
"content-disposition": "0.5.3",
|
||||
"content-type": "1.0.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "1.1.2",
|
||||
"encodeurl": "1.0.2",
|
||||
"escape-html": "1.0.3",
|
||||
"etag": "1.8.1",
|
||||
"finalhandler": "1.1.2",
|
||||
"depd": "~1.1.2",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "~1.1.2",
|
||||
"fresh": "0.5.2",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "1.1.2",
|
||||
"on-finished": "2.3.0",
|
||||
"parseurl": "1.3.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "2.0.7",
|
||||
"proxy-addr": "~2.0.5",
|
||||
"qs": "6.7.0",
|
||||
"range-parser": "1.2.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.1.2",
|
||||
"send": "0.17.1",
|
||||
"serve-static": "1.14.1",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": "1.5.0",
|
||||
"type-is": "1.6.18",
|
||||
"statuses": "~1.5.0",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "1.1.2"
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
@@ -6290,7 +6303,7 @@
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6438,6 +6451,43 @@
|
||||
"bser": "2.1.1"
|
||||
}
|
||||
},
|
||||
"fbemitter": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz",
|
||||
"integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==",
|
||||
"requires": {
|
||||
"fbjs": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fbjs": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
|
||||
"integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
|
||||
"requires": {
|
||||
"cross-fetch": "^3.1.5",
|
||||
"fbjs-css-vars": "^1.0.0",
|
||||
"loose-envify": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"promise": "^7.1.1",
|
||||
"setimmediate": "^1.0.5",
|
||||
"ua-parser-js": "^1.0.35"
|
||||
},
|
||||
"dependencies": {
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"requires": {
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fbjs-css-vars": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
|
||||
"integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="
|
||||
},
|
||||
"figgy-pudding": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
|
||||
@@ -6567,6 +6617,15 @@
|
||||
"readable-stream": "2.3.7"
|
||||
}
|
||||
},
|
||||
"flux": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz",
|
||||
"integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==",
|
||||
"requires": {
|
||||
"fbemitter": "^3.0.0",
|
||||
"fbjs": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
|
||||
@@ -9787,11 +9846,21 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
||||
},
|
||||
"lodash.curry": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
|
||||
"integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA=="
|
||||
},
|
||||
"lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
|
||||
},
|
||||
"lodash.flow": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
|
||||
"integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw=="
|
||||
},
|
||||
"lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
@@ -10291,6 +10360,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
@@ -12209,6 +12307,11 @@
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"pure-color": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
|
||||
"integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA=="
|
||||
},
|
||||
"q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
@@ -12318,6 +12421,17 @@
|
||||
"whatwg-fetch": "3.6.2"
|
||||
}
|
||||
},
|
||||
"react-base16-styling": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz",
|
||||
"integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==",
|
||||
"requires": {
|
||||
"base16": "^1.0.0",
|
||||
"lodash.curry": "^4.0.1",
|
||||
"lodash.flow": "^3.3.0",
|
||||
"pure-color": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"react-dev-utils": {
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
|
||||
@@ -12535,6 +12649,22 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||
},
|
||||
"react-json-view": {
|
||||
"version": "1.21.3",
|
||||
"resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz",
|
||||
"integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==",
|
||||
"requires": {
|
||||
"flux": "^4.0.1",
|
||||
"react-base16-styling": "^0.6.0",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"react-textarea-autosize": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-refresh": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
||||
@@ -12606,6 +12736,31 @@
|
||||
"workbox-webpack-plugin": "5.1.4"
|
||||
}
|
||||
},
|
||||
"react-textarea-autosize": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.4.tgz",
|
||||
"integrity": "sha512-eSSjVtRLcLfFwFcariT77t9hcbVJHQV76b51QjQGarQIHml2+gM2lms0n3XrhnDmgK5B+/Z7TmQk5OHNzqYm/A==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"use-composed-ref": "^1.3.0",
|
||||
"use-latest": "^1.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
@@ -14709,6 +14864,11 @@
|
||||
"is-typedarray": "1.0.0"
|
||||
}
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "1.0.39",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.39.tgz",
|
||||
"integrity": "sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw=="
|
||||
},
|
||||
"unbox-primitive": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
|
||||
@@ -14915,6 +15075,24 @@
|
||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
||||
},
|
||||
"use-composed-ref": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz",
|
||||
"integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ=="
|
||||
},
|
||||
"use-isomorphic-layout-effect": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
||||
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
|
||||
},
|
||||
"use-latest": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz",
|
||||
"integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==",
|
||||
"requires": {
|
||||
"use-isomorphic-layout-effect": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"util": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
|
||||
@@ -15083,6 +15261,7 @@
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
|
||||
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"arr-flatten": "1.1.0",
|
||||
"array-unique": "0.3.2",
|
||||
@@ -15100,6 +15279,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extendable": "0.1.1"
|
||||
}
|
||||
@@ -15130,6 +15310,7 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"extend-shallow": "2.0.1",
|
||||
"is-number": "3.0.0",
|
||||
@@ -15141,6 +15322,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extendable": "0.1.1"
|
||||
}
|
||||
@@ -15191,6 +15373,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"kind-of": "3.2.2"
|
||||
},
|
||||
@@ -15199,6 +15382,7 @@
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-buffer": "1.1.6"
|
||||
}
|
||||
@@ -15209,6 +15393,7 @@
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"arr-diff": "4.0.0",
|
||||
"array-unique": "0.3.2",
|
||||
@@ -15240,6 +15425,7 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
|
||||
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-number": "3.0.0",
|
||||
"repeat-string": "1.6.1"
|
||||
|
@@ -2136,7 +2136,7 @@ abab@^2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
||||
integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
|
||||
|
||||
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||
accepts@~1.3.4, accepts@~1.3.5:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
|
||||
@@ -2144,6 +2144,14 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||
mime-types "~2.1.24"
|
||||
negotiator "0.6.2"
|
||||
|
||||
accepts@~1.3.8:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
|
||||
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
|
||||
dependencies:
|
||||
mime-types "~2.1.34"
|
||||
negotiator "0.6.3"
|
||||
|
||||
acorn-globals@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
|
||||
@@ -2773,21 +2781,23 @@ bn.js@^5.0.0, bn.js@^5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
|
||||
integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
|
||||
|
||||
body-parser@1.19.0:
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
||||
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
|
||||
body-parser@1.20.3:
|
||||
version "1.20.3"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
|
||||
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
|
||||
dependencies:
|
||||
bytes "3.1.0"
|
||||
content-type "~1.0.4"
|
||||
bytes "3.1.2"
|
||||
content-type "~1.0.5"
|
||||
debug "2.6.9"
|
||||
depd "~1.1.2"
|
||||
http-errors "1.7.2"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
on-finished "~2.3.0"
|
||||
qs "6.7.0"
|
||||
raw-body "2.4.0"
|
||||
type-is "~1.6.17"
|
||||
on-finished "2.4.1"
|
||||
qs "6.13.0"
|
||||
raw-body "2.5.2"
|
||||
type-is "~1.6.18"
|
||||
unpipe "1.0.0"
|
||||
|
||||
bonjour@^3.5.0:
|
||||
version "3.5.0"
|
||||
@@ -2975,10 +2985,10 @@ bytes@3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||
|
||||
bytes@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
cacache@^12.0.2:
|
||||
version "12.0.4"
|
||||
@@ -3047,6 +3057,17 @@ call-bind@^1.0.0, call-bind@^1.0.2:
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.2"
|
||||
|
||||
call-bind@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
set-function-length "^1.2.1"
|
||||
|
||||
caller-callsite@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
|
||||
@@ -3444,18 +3465,23 @@ contains-path@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
|
||||
integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
|
||||
|
||||
content-disposition@0.5.3:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
||||
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
|
||||
content-disposition@0.5.4:
|
||||
version "0.5.4"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
|
||||
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
|
||||
dependencies:
|
||||
safe-buffer "5.1.2"
|
||||
safe-buffer "5.2.1"
|
||||
|
||||
content-type@~1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||
|
||||
content-type@~1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
|
||||
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
|
||||
|
||||
convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
|
||||
@@ -3473,10 +3499,10 @@ cookie-signature@1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
|
||||
|
||||
cookie@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
|
||||
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
|
||||
cookie@0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
|
||||
integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
|
||||
|
||||
copy-concurrently@^1.0.0:
|
||||
version "1.0.5"
|
||||
@@ -3960,6 +3986,15 @@ default-gateway@^4.2.0:
|
||||
execa "^1.0.0"
|
||||
ip-regex "^2.1.0"
|
||||
|
||||
define-data-property@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
|
||||
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
gopd "^1.0.1"
|
||||
|
||||
define-properties@^1.1.2, define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
@@ -4007,6 +4042,11 @@ delayed-stream@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
depd@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
@@ -4020,10 +4060,10 @@ des.js@^1.0.0:
|
||||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
destroy@~1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||
destroy@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
|
||||
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
|
||||
|
||||
detect-newline@^3.0.0:
|
||||
version "3.1.0"
|
||||
@@ -4279,6 +4319,11 @@ encodeurl@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||
|
||||
encodeurl@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
|
||||
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
|
||||
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
@@ -4370,6 +4415,18 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2:
|
||||
string.prototype.trimend "^1.0.3"
|
||||
string.prototype.trimstart "^1.0.3"
|
||||
|
||||
es-define-property@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
|
||||
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
|
||||
dependencies:
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
es-errors@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
||||
|
||||
es-to-primitive@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
||||
@@ -4774,37 +4831,38 @@ expect@^26.6.0, expect@^26.6.2:
|
||||
jest-regex-util "^26.0.0"
|
||||
|
||||
express@^4.17.1:
|
||||
version "4.17.1"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
|
||||
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
|
||||
version "4.21.1"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281"
|
||||
integrity sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==
|
||||
dependencies:
|
||||
accepts "~1.3.7"
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.19.0"
|
||||
content-disposition "0.5.3"
|
||||
body-parser "1.20.3"
|
||||
content-disposition "0.5.4"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.4.0"
|
||||
cookie "0.7.1"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "~1.1.2"
|
||||
encodeurl "~1.0.2"
|
||||
depd "2.0.0"
|
||||
encodeurl "~2.0.0"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
finalhandler "~1.1.2"
|
||||
finalhandler "1.3.1"
|
||||
fresh "0.5.2"
|
||||
merge-descriptors "1.0.1"
|
||||
http-errors "2.0.0"
|
||||
merge-descriptors "1.0.3"
|
||||
methods "~1.1.2"
|
||||
on-finished "~2.3.0"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
path-to-regexp "0.1.7"
|
||||
proxy-addr "~2.0.5"
|
||||
qs "6.7.0"
|
||||
path-to-regexp "0.1.10"
|
||||
proxy-addr "~2.0.7"
|
||||
qs "6.13.0"
|
||||
range-parser "~1.2.1"
|
||||
safe-buffer "5.1.2"
|
||||
send "0.17.1"
|
||||
serve-static "1.14.1"
|
||||
setprototypeof "1.1.1"
|
||||
statuses "~1.5.0"
|
||||
safe-buffer "5.2.1"
|
||||
send "0.19.0"
|
||||
serve-static "1.16.2"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
type-is "~1.6.18"
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
@@ -4980,17 +5038,17 @@ fill-range@^7.0.1:
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
finalhandler@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
|
||||
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
|
||||
finalhandler@1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
|
||||
integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
encodeurl "~1.0.2"
|
||||
encodeurl "~2.0.0"
|
||||
escape-html "~1.0.3"
|
||||
on-finished "~2.3.0"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
statuses "~1.5.0"
|
||||
statuses "2.0.1"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
find-cache-dir@^2.1.0:
|
||||
@@ -5104,10 +5162,10 @@ form-data@~2.3.2:
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||
|
||||
fragment-cache@^0.2.1:
|
||||
version "0.2.1"
|
||||
@@ -5197,6 +5255,11 @@ function-bind@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
functional-red-black-tree@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
||||
@@ -5221,6 +5284,17 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
|
||||
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
has-proto "^1.0.1"
|
||||
has-symbols "^1.0.3"
|
||||
hasown "^2.0.0"
|
||||
|
||||
get-own-enumerable-property-symbols@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
|
||||
@@ -5347,6 +5421,13 @@ globby@^6.1.0:
|
||||
pify "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
gopd@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
|
||||
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
|
||||
dependencies:
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
|
||||
version "4.2.6"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
|
||||
@@ -5398,11 +5479,28 @@ has-flag@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
|
||||
has-property-descriptors@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
|
||||
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
|
||||
has-proto@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
|
||||
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
|
||||
|
||||
has-symbols@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
|
||||
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
|
||||
|
||||
has-symbols@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||
|
||||
has-value@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
|
||||
@@ -5458,6 +5556,13 @@ hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
inherits "^2.0.3"
|
||||
minimalistic-assert "^1.0.1"
|
||||
|
||||
hasown@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
he@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
@@ -5574,16 +5679,16 @@ http-deceiver@^1.2.7:
|
||||
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
|
||||
integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
|
||||
|
||||
http-errors@1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
|
||||
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
|
||||
http-errors@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
|
||||
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
|
||||
dependencies:
|
||||
depd "~1.1.2"
|
||||
inherits "2.0.3"
|
||||
setprototypeof "1.1.1"
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
depd "2.0.0"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
http-errors@~1.6.2:
|
||||
version "1.6.3"
|
||||
@@ -5595,17 +5700,6 @@ http-errors@~1.6.2:
|
||||
setprototypeof "1.1.0"
|
||||
statuses ">= 1.4.0 < 2"
|
||||
|
||||
http-errors@~1.7.2:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
|
||||
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
|
||||
dependencies:
|
||||
depd "~1.1.2"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.1.1"
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
http-parser-js@>=0.5.1:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9"
|
||||
@@ -7132,10 +7226,10 @@ memory-fs@^0.5.0:
|
||||
errno "^0.1.3"
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
|
||||
merge-descriptors@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
|
||||
integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -7197,6 +7291,11 @@ mime-db@1.46.0, "mime-db@>= 1.43.0 < 2":
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee"
|
||||
integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
|
||||
version "2.1.29"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2"
|
||||
@@ -7204,6 +7303,13 @@ mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19,
|
||||
dependencies:
|
||||
mime-db "1.46.0"
|
||||
|
||||
mime-types@~2.1.34:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
@@ -7345,17 +7451,12 @@ ms@2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
ms@^2.1.1:
|
||||
ms@2.1.3, ms@^2.1.1:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
@@ -7417,6 +7518,11 @@ negotiator@0.6.2:
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
|
||||
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
|
||||
neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||
@@ -7598,6 +7704,11 @@ object-copy@^0.1.0:
|
||||
define-property "^0.2.5"
|
||||
kind-of "^3.0.3"
|
||||
|
||||
object-inspect@^1.13.1:
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
|
||||
integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
|
||||
|
||||
object-inspect@^1.8.0, object-inspect@^1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
|
||||
@@ -7684,10 +7795,10 @@ obuf@^1.0.0, obuf@^1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
|
||||
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
|
||||
|
||||
on-finished@~2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
|
||||
on-finished@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
|
||||
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
@@ -7983,10 +8094,10 @@ path-parse@^1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||
path-to-regexp@0.1.10:
|
||||
version "0.1.10"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
|
||||
integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
|
||||
|
||||
path-type@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -8869,12 +8980,12 @@ prop-types@^15.7.2:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.8.1"
|
||||
|
||||
proxy-addr@~2.0.5:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
||||
integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
|
||||
proxy-addr@~2.0.7:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
||||
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
|
||||
dependencies:
|
||||
forwarded "~0.1.2"
|
||||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
prr@~1.0.1:
|
||||
@@ -8949,10 +9060,12 @@ q@^1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
||||
|
||||
qs@6.7.0:
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||
qs@6.13.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
|
||||
integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
|
||||
dependencies:
|
||||
side-channel "^1.0.6"
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
@@ -9019,13 +9132,13 @@ range-parser@^1.2.1, range-parser@~1.2.1:
|
||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
|
||||
|
||||
raw-body@2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
|
||||
integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
|
||||
raw-body@2.5.2:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
|
||||
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
|
||||
dependencies:
|
||||
bytes "3.1.0"
|
||||
http-errors "1.7.2"
|
||||
bytes "3.1.2"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
@@ -9654,7 +9767,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
||||
safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
@@ -9788,24 +9901,24 @@ semver@^7.2.1, semver@^7.3.2:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
send@0.17.1:
|
||||
version "0.17.1"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
|
||||
integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
|
||||
send@0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
|
||||
integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
depd "~1.1.2"
|
||||
destroy "~1.0.4"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
fresh "0.5.2"
|
||||
http-errors "~1.7.2"
|
||||
http-errors "2.0.0"
|
||||
mime "1.6.0"
|
||||
ms "2.1.1"
|
||||
on-finished "~2.3.0"
|
||||
ms "2.1.3"
|
||||
on-finished "2.4.1"
|
||||
range-parser "~1.2.1"
|
||||
statuses "~1.5.0"
|
||||
statuses "2.0.1"
|
||||
|
||||
serialize-javascript@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -9834,21 +9947,33 @@ serve-index@^1.9.1:
|
||||
mime-types "~2.1.17"
|
||||
parseurl "~1.3.2"
|
||||
|
||||
serve-static@1.14.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
|
||||
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
|
||||
serve-static@1.16.2:
|
||||
version "1.16.2"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
|
||||
integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
|
||||
dependencies:
|
||||
encodeurl "~1.0.2"
|
||||
encodeurl "~2.0.0"
|
||||
escape-html "~1.0.3"
|
||||
parseurl "~1.3.3"
|
||||
send "0.17.1"
|
||||
send "0.19.0"
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
set-function-length@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
||||
dependencies:
|
||||
define-data-property "^1.1.4"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
gopd "^1.0.1"
|
||||
has-property-descriptors "^1.0.2"
|
||||
|
||||
set-value@^2.0.0, set-value@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
|
||||
@@ -9869,10 +9994,10 @@ setprototypeof@1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
||||
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
|
||||
|
||||
setprototypeof@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
||||
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
|
||||
setprototypeof@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||
|
||||
sha.js@^2.4.0, sha.js@^2.4.8:
|
||||
version "2.4.11"
|
||||
@@ -9925,6 +10050,16 @@ side-channel@^1.0.4:
|
||||
get-intrinsic "^1.0.2"
|
||||
object-inspect "^1.9.0"
|
||||
|
||||
side-channel@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
||||
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
object-inspect "^1.13.1"
|
||||
|
||||
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
@@ -10186,7 +10321,12 @@ static-extend@^0.1.1:
|
||||
define-property "^0.2.5"
|
||||
object-copy "^0.1.0"
|
||||
|
||||
"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
|
||||
statuses@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
"statuses@>= 1.4.0 < 2":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
|
||||
@@ -10640,10 +10780,10 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
||||
regex-not "^1.0.2"
|
||||
safe-regex "^1.1.0"
|
||||
|
||||
toidentifier@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
toidentifier@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
@@ -10767,7 +10907,7 @@ type-fest@^0.8.1:
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||
|
||||
type-is@~1.6.17, type-is@~1.6.18:
|
||||
type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
|
47
pom.xml
47
pom.xml
@@ -28,7 +28,7 @@
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-dashboard</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<version>2.0.1-SNAPSHOT</version>
|
||||
<name>rocketmq-dashboard</name>
|
||||
|
||||
<scm>
|
||||
@@ -90,18 +90,24 @@
|
||||
<commons-lang.version>2.6</commons-lang.version>
|
||||
<commons-io.version>2.4</commons-io.version>
|
||||
<commons-cli.version>1.2</commons-cli.version>
|
||||
<rocketmq.version>4.9.0</rocketmq.version>
|
||||
<commons-collections.version>3.2.2</commons-collections.version>
|
||||
<rocketmq.version>5.1.0</rocketmq.version>
|
||||
<surefire.version>2.19.1</surefire.version>
|
||||
<aspectj.version>1.9.6</aspectj.version>
|
||||
<lombok.version>1.18.12</lombok.version>
|
||||
<lombok.version>1.18.22</lombok.version>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<docker.image.prefix>apacherocketmq</docker.image.prefix>
|
||||
<spring.boot.version>2.2.2.RELEASE</spring.boot.version>
|
||||
<spring.boot.version>2.6.0</spring.boot.version>
|
||||
<mockito-inline.version>3.3.3</mockito-inline.version>
|
||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||
<commons-pool2.version>2.4.3</commons-pool2.version>
|
||||
<easyexcel.version>2.2.10</easyexcel.version>
|
||||
<asm.version>4.2</asm.version>
|
||||
<junit.version>4.12</junit.version>
|
||||
<snakeyaml.version>1.32</snakeyaml.version>
|
||||
<cglib.version>2.2.2</cglib.version>
|
||||
<joor.version>0.9.6</joor.version>
|
||||
<bcpkix-jdk15on.version>1.68</bcpkix-jdk15on.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -125,11 +131,22 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<version>${commons-collections.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
@@ -169,6 +186,7 @@
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-broker</artifactId>
|
||||
<version>${rocketmq.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
@@ -203,17 +221,17 @@
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<version>${cglib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jooq</groupId>
|
||||
<artifactId>joor</artifactId>
|
||||
<version>0.9.6</version>
|
||||
<version>${joor.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.68</version>
|
||||
<version>${bcpkix-jdk15on.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
@@ -246,6 +264,17 @@
|
||||
<artifactId>asm</artifactId>
|
||||
<version>${asm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
@@ -431,7 +460,7 @@
|
||||
<configuration>
|
||||
<target>
|
||||
<copy todir="${project.build.directory}/classes/public">
|
||||
<fileset dir="${project.basedir}/frontend/build"/>
|
||||
<fileset dir="${project.basedir}/frontend/build" />
|
||||
</copy>
|
||||
</target>
|
||||
</configuration>
|
||||
|
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.admin;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||
@@ -33,6 +34,8 @@ public class MQAdminFactory {
|
||||
this.rmqConfigure = rmqConfigure;
|
||||
}
|
||||
|
||||
private final AtomicLong adminIndex = new AtomicLong(0);
|
||||
|
||||
public MQAdminExt getInstance() throws Exception {
|
||||
RPCHook rpcHook = null;
|
||||
final String accessKey = rmqConfigure.getAccessKey();
|
||||
@@ -47,6 +50,7 @@ public class MQAdminFactory {
|
||||
} else {
|
||||
mqAdminExt = new DefaultMQAdminExt(rpcHook, rmqConfigure.getTimeoutMillis());
|
||||
}
|
||||
mqAdminExt.setAdminExtGroup(mqAdminExt.getAdminExtGroup() + "_" + adminIndex.getAndIncrement());
|
||||
mqAdminExt.setVipChannelEnabled(Boolean.parseBoolean(rmqConfigure.getIsVIPChannel()));
|
||||
mqAdminExt.setUseTLS(rmqConfigure.isUseTLS());
|
||||
mqAdminExt.setInstanceName(Long.toString(System.currentTimeMillis()));
|
||||
|
@@ -21,7 +21,7 @@ import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.PooledObjectFactory;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
|
||||
@Slf4j
|
||||
|
@@ -50,17 +50,19 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
if (configure.isLoginRequired()) {
|
||||
registry.addInterceptor(authInterceptor).addPathPatterns(
|
||||
"/cluster/**",
|
||||
"/consumer/**",
|
||||
"/dashboard/**",
|
||||
"/message/**",
|
||||
"/messageTrace/**",
|
||||
"/monitor/**",
|
||||
"/rocketmq/**",
|
||||
"/ops/**",
|
||||
"/producer/**",
|
||||
"/test/**",
|
||||
"/topic/**");
|
||||
"/cluster/**",
|
||||
"/consumer/**",
|
||||
"/dashboard/**",
|
||||
"/dlqMessage/**",
|
||||
"/message/**",
|
||||
"/messageTrace/**",
|
||||
"/monitor/**",
|
||||
"/rocketmq/**",
|
||||
"/ops/**",
|
||||
"/producer/**",
|
||||
"/test/**",
|
||||
"/topic/**",
|
||||
"/acl/**");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,9 +77,9 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
|
||||
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
|
||||
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
|
||||
UserInfo userInfo = (UserInfo) WebUtil.getValueFromSession((HttpServletRequest) nativeWebRequest.getNativeRequest(),
|
||||
UserInfo.USER_INFO);
|
||||
UserInfo.USER_INFO);
|
||||
if (userInfo != null) {
|
||||
return userInfo;
|
||||
}
|
||||
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "threadpool.config")
|
||||
@Data
|
||||
public class CollectExecutorConfig {
|
||||
private int coreSize = 20;
|
||||
private int maxSize = 20;
|
||||
private long keepAliveTime = 3000L;
|
||||
private int queueSize = 1000;
|
||||
|
||||
@Bean(name = "collectExecutor")
|
||||
public ExecutorService collectExecutor(CollectExecutorConfig collectExecutorConfig) {
|
||||
ExecutorService collectExecutor = new ThreadPoolExecutor(
|
||||
collectExecutorConfig.getCoreSize(),
|
||||
collectExecutorConfig.getMaxSize(),
|
||||
collectExecutorConfig.getKeepAliveTime(),
|
||||
TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingDeque<>(collectExecutorConfig.getQueueSize()),
|
||||
new ThreadFactory() {
|
||||
private final AtomicLong threadIndex = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "collectTopicThread_" + this.threadIndex.incrementAndGet());
|
||||
}
|
||||
},
|
||||
new ThreadPoolExecutor.DiscardOldestPolicy()
|
||||
);
|
||||
return collectExecutor;
|
||||
}
|
||||
}
|
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.slf4j.Logger;
|
||||
@@ -29,6 +31,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
|
||||
|
||||
@@ -40,6 +43,8 @@ public class RMQConfigure {
|
||||
//use rocketmq.namesrv.addr first,if it is empty,than use system proerty or system env
|
||||
private volatile String namesrvAddr = System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY, System.getenv(MixAll.NAMESRV_ADDR_ENV));
|
||||
|
||||
private volatile String proxyAddr;
|
||||
|
||||
private volatile String isVIPChannel = System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true");
|
||||
|
||||
|
||||
@@ -57,6 +62,10 @@ public class RMQConfigure {
|
||||
|
||||
private Long timeoutMillis;
|
||||
|
||||
private List<String> namesrvAddrs = new ArrayList<>();
|
||||
|
||||
private List<String> proxyAddrs = new ArrayList<>();
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
@@ -77,6 +86,36 @@ public class RMQConfigure {
|
||||
return namesrvAddr;
|
||||
}
|
||||
|
||||
public List<String> getNamesrvAddrs() {
|
||||
return namesrvAddrs;
|
||||
}
|
||||
|
||||
public List<String> getProxyAddrs() {
|
||||
return this.proxyAddrs;
|
||||
}
|
||||
|
||||
public void setProxyAddrs(List<String> proxyAddrs) {
|
||||
this.proxyAddrs = proxyAddrs;
|
||||
if (CollectionUtils.isNotEmpty(proxyAddrs)) {
|
||||
this.setProxyAddr(proxyAddrs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public String getProxyAddr() {
|
||||
return proxyAddr;
|
||||
}
|
||||
|
||||
public void setProxyAddr(String proxyAddr) {
|
||||
this.proxyAddr = proxyAddr;
|
||||
}
|
||||
|
||||
public void setNamesrvAddrs(List<String> namesrvAddrs) {
|
||||
this.namesrvAddrs = namesrvAddrs;
|
||||
if (CollectionUtils.isNotEmpty(namesrvAddrs)) {
|
||||
this.setNamesrvAddr(namesrvAddrs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void setNamesrvAddr(String namesrvAddr) {
|
||||
if (StringUtils.isNotBlank(namesrvAddr)) {
|
||||
this.namesrvAddr = namesrvAddr;
|
||||
|
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.User;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.AclService;
|
||||
import org.apache.rocketmq.dashboard.support.JsonResult;
|
||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/acl")
|
||||
@Permission
|
||||
public class AclController {
|
||||
|
||||
@Resource
|
||||
private AclService aclService;
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@GetMapping("/enable.query")
|
||||
public Object isEnableAcl() {
|
||||
return new JsonResult<>(configure.isACLEnabled());
|
||||
}
|
||||
|
||||
@GetMapping("/config.query")
|
||||
public AclConfig getAclConfig(HttpServletRequest request) {
|
||||
if (!configure.isLoginRequired()) {
|
||||
return aclService.getAclConfig(false);
|
||||
}
|
||||
UserInfo userInfo = (UserInfo) WebUtil.getValueFromSession(request, WebUtil.USER_INFO);
|
||||
// if user info is null but reach here, must exclude secret key for safety.
|
||||
return aclService.getAclConfig(userInfo == null || userInfo.getUser().getType() != User.ADMIN);
|
||||
}
|
||||
|
||||
@PostMapping("/add.do")
|
||||
public Object addAclConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getSecretKey()), "secretKey is null");
|
||||
aclService.addAclConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/delete.do")
|
||||
public Object deleteAclConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getAccessKey()), "accessKey is null");
|
||||
aclService.deleteAclConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/update.do")
|
||||
public Object updateAclConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getSecretKey()), "secretKey is null");
|
||||
aclService.updateAclConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/topic/add.do")
|
||||
public Object addAclTopicConfig(@RequestBody AclRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getSecretKey()), "secretKey is null");
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(request.getConfig().getTopicPerms()), "topic perms is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getTopicPerm()), "topic perm is null");
|
||||
aclService.addOrUpdateAclTopicConfig(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/group/add.do")
|
||||
public Object addAclGroupConfig(@RequestBody AclRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getSecretKey()), "secretKey is null");
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(request.getConfig().getGroupPerms()), "group perms is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getGroupPerm()), "group perm is null");
|
||||
aclService.addOrUpdateAclGroupConfig(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/perm/delete.do")
|
||||
public Object deletePermConfig(@RequestBody AclRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getSecretKey()), "secretKey is null");
|
||||
aclService.deletePermConfig(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/sync.do")
|
||||
public Object syncConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getSecretKey()), "secretKey is null");
|
||||
aclService.syncData(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/white/list/add.do")
|
||||
public Object addWhiteList(@RequestBody List<String> whiteList) {
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(whiteList), "white list is null");
|
||||
aclService.addWhiteList(whiteList);
|
||||
return true;
|
||||
}
|
||||
|
||||
@DeleteMapping("/white/list/delete.do")
|
||||
public Object deleteWhiteAddr(@RequestParam String request) {
|
||||
aclService.deleteWhiteAddr(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/white/list/sync.do")
|
||||
public Object synchronizeWhiteList(@RequestBody List<String> whiteList) {
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(whiteList), "white list is null");
|
||||
aclService.synchronizeWhiteList(whiteList);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -19,7 +19,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
import com.google.common.base.Preconditions;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
|
||||
@@ -47,14 +47,14 @@ public class ConsumerController {
|
||||
|
||||
@RequestMapping(value = "/groupList.query")
|
||||
@ResponseBody
|
||||
public Object list(@RequestParam(value = "skipSysGroup", required = false) boolean skipSysGroup) {
|
||||
return consumerService.queryGroupList(skipSysGroup);
|
||||
public Object list(@RequestParam(value = "skipSysGroup", required = false) boolean skipSysGroup, String address) {
|
||||
return consumerService.queryGroupList(skipSysGroup, address);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/group.query")
|
||||
@ResponseBody
|
||||
public Object groupQuery(@RequestParam String consumerGroup) {
|
||||
return consumerService.queryGroup(consumerGroup);
|
||||
public Object groupQuery(@RequestParam String consumerGroup, String address) {
|
||||
return consumerService.queryGroup(consumerGroup, address);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/resetOffset.do", method = {RequestMethod.POST})
|
||||
@@ -99,14 +99,14 @@ public class ConsumerController {
|
||||
|
||||
@RequestMapping(value = "/queryTopicByConsumer.query")
|
||||
@ResponseBody
|
||||
public Object queryConsumerByTopic(@RequestParam String consumerGroup) {
|
||||
return consumerService.queryConsumeStatsListByGroupName(consumerGroup);
|
||||
public Object queryConsumerByTopic(@RequestParam String consumerGroup, String address) {
|
||||
return consumerService.queryConsumeStatsListByGroupName(consumerGroup, address);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/consumerConnection.query")
|
||||
@ResponseBody
|
||||
public Object consumerConnection(@RequestParam(required = false) String consumerGroup) {
|
||||
ConsumerConnection consumerConnection = consumerService.getConsumerConnection(consumerGroup);
|
||||
public Object consumerConnection(@RequestParam(required = false) String consumerGroup, String address) {
|
||||
ConsumerConnection consumerConnection = consumerService.getConsumerConnection(consumerGroup, address);
|
||||
consumerConnection.setConnectionSet(ConnectionInfo.buildConnectionInfoHashSet(consumerConnection.getConnectionSet()));
|
||||
return consumerConnection;
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ public class DashboardController {
|
||||
return dashboardService.queryTopicData(date,topicName);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/topicCurrent", method = RequestMethod.GET)
|
||||
@RequestMapping(value = "/topicCurrent.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object topicCurrent() {
|
||||
return dashboardService.queryTopicCurrentData();
|
||||
|
@@ -17,12 +17,16 @@
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageExcelModel;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.DlqMessageService;
|
||||
@@ -30,6 +34,7 @@ import org.apache.rocketmq.dashboard.util.ExcelUtil;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@@ -39,6 +44,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@Controller
|
||||
@RequestMapping("/dlqMessage")
|
||||
@Permission
|
||||
@Slf4j
|
||||
public class DlqMessageController {
|
||||
|
||||
@Resource
|
||||
@@ -70,4 +76,33 @@ public class DlqMessageController {
|
||||
throw new ServiceException(-1, String.format("export dlq message failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/batchResendDlqMessage.do")
|
||||
@ResponseBody
|
||||
public Object batchResendDlqMessage(@RequestBody List<DlqMessageRequest> dlqMessages) {
|
||||
return dlqMessageService.batchResendDlqMessage(dlqMessages);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/batchExportDlqMessage.do")
|
||||
public void batchExportDlqMessage(HttpServletResponse response, @RequestBody List<DlqMessageRequest> dlqMessages) {
|
||||
List<DlqMessageExcelModel> dlqMessageExcelModelList = new ArrayList<>(dlqMessages.size());
|
||||
for (DlqMessageRequest dlqMessage : dlqMessages) {
|
||||
DlqMessageExcelModel excelModel = new DlqMessageExcelModel();
|
||||
try {
|
||||
String topic = MixAll.DLQ_GROUP_TOPIC_PREFIX + dlqMessage.getConsumerGroup();
|
||||
MessageExt messageExt = mqAdminExt.viewMessage(topic, dlqMessage.getMsgId());
|
||||
excelModel = new DlqMessageExcelModel(messageExt);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to query message by Id:{}", dlqMessage.getMsgId(), e);
|
||||
excelModel.setMsgId(dlqMessage.getMsgId());
|
||||
excelModel.setException(e.getMessage());
|
||||
}
|
||||
dlqMessageExcelModelList.add(excelModel);
|
||||
}
|
||||
try {
|
||||
ExcelUtil.writeExcel(response, dlqMessageExcelModelList, "dlqs", "dlqs", DlqMessageExcelModel.class);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(-1, String.format("export dlq message failed!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
|
@@ -32,7 +32,7 @@ public class NamesvrController {
|
||||
@Resource
|
||||
private OpsService opsService;
|
||||
|
||||
@RequestMapping(value = "/nsaddr", method = RequestMethod.GET)
|
||||
@RequestMapping(value = "/nsaddr.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
@OriginalControllerReturnValue
|
||||
public Object nsaddr() {
|
||||
|
@@ -16,7 +16,9 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.OpsService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@@ -46,6 +48,15 @@ public class OpsController {
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addNameSvrAddr.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object addNameSvrAddr(@RequestParam String newNamesrvAddr) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(newNamesrvAddr),
|
||||
"namesrvAddr can not be blank");
|
||||
opsService.addNameSvrAddr(newNamesrvAddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updateIsVIPChannel.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object updateIsVIPChannel(@RequestParam String useVIPChannel) {
|
||||
@@ -53,14 +64,12 @@ public class OpsController {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/rocketMqStatus.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object clusterStatus() {
|
||||
return opsService.rocketMqStatusCheck();
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/updateUseTLS.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object updateUseTLS(@RequestParam String useTLS) {
|
||||
|
@@ -17,7 +17,7 @@
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ProducerService;
|
||||
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ProxyService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/proxy")
|
||||
@Permission
|
||||
public class ProxyController {
|
||||
@Resource
|
||||
private ProxyService proxyService;
|
||||
@RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object homePage() {
|
||||
return proxyService.getProxyHomePage();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addProxyAddr.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object addProxyAddr(@RequestParam String newProxyAddr) {
|
||||
proxyService.addProxyAddrList(newProxyAddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updateProxyAddr.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object updateProxyAddr(@RequestParam String proxyAddr) {
|
||||
proxyService.updateProxyAddrList(proxyAddr);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -56,6 +56,12 @@ public class TopicController {
|
||||
return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/list.queryTopicType", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object listTopicType() {
|
||||
return topicService.examineAllTopicType();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/stats.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object stats(@RequestParam String topic) {
|
||||
|
@@ -20,7 +20,7 @@ import com.google.common.collect.Sets;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import org.apache.rocketmq.common.MQVersion;
|
||||
import org.apache.rocketmq.common.protocol.body.Connection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||
|
||||
public class ConnectionInfo extends Connection {
|
||||
private String versionDesc;
|
||||
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
@@ -25,9 +25,11 @@ import com.google.common.base.Charsets;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DlqMessageExcelModel extends BaseRowModel implements Serializable {
|
||||
|
||||
@ExcelProperty(value = "topic", index = 0)
|
||||
@@ -66,6 +68,10 @@ public class DlqMessageExcelModel extends BaseRowModel implements Serializable {
|
||||
@ColumnWidth(value = 15)
|
||||
private int bodyCRC;
|
||||
|
||||
@ExcelProperty(value = "exception", index = 9)
|
||||
@ColumnWidth(value = 30)
|
||||
private String exception;
|
||||
|
||||
public DlqMessageExcelModel(MessageExt messageExt) {
|
||||
this.topic = messageExt.getTopic();
|
||||
this.msgId = messageExt.getMsgId();
|
||||
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DlqMessageRequest {
|
||||
|
||||
private String topicName;
|
||||
|
||||
private String consumerGroup;
|
||||
|
||||
private String msgId;
|
||||
|
||||
private String clientId;
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.rocketmq.remoting.protocol.body.CMResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
|
||||
@Data
|
||||
public class DlqMessageResendResult {
|
||||
private CMResult consumeResult;
|
||||
private String remark;
|
||||
private String msgId;
|
||||
|
||||
public DlqMessageResendResult(ConsumeMessageDirectlyResult consumeMessageDirectlyResult, String msgId) {
|
||||
this.consumeResult = consumeMessageDirectlyResult.getConsumeResult();
|
||||
this.remark = consumeMessageDirectlyResult.getRemark();
|
||||
this.msgId = msgId;
|
||||
}
|
||||
}
|
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
|
||||
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
|
||||
private String group;
|
||||
@@ -25,8 +27,11 @@ public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
|
||||
private int count;
|
||||
private ConsumeType consumeType;
|
||||
private MessageModel messageModel;
|
||||
private List<String> address;
|
||||
private int consumeTps;
|
||||
private long diffTotal = -1;
|
||||
private String subGroupType = "NORMAL";
|
||||
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
@@ -68,6 +73,22 @@ public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
|
||||
this.diffTotal = diffTotal;
|
||||
}
|
||||
|
||||
public List<String> getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(List<String> address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getSubGroupType() {
|
||||
return subGroupType;
|
||||
}
|
||||
|
||||
public void setSubGroupType(String subGroupType) {
|
||||
this.subGroupType = subGroupType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(GroupConsumeInfo o) {
|
||||
if (this.count != o.count) {
|
||||
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import org.apache.rocketmq.common.admin.OffsetWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
|
||||
@Data
|
||||
public class AclRequest {
|
||||
|
||||
private PlainAccessConfig config;
|
||||
|
||||
private String topicPerm;
|
||||
|
||||
private String groupPerm;
|
||||
}
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import java.util.List;
|
||||
@@ -32,6 +31,7 @@ public class TopicConfigInfo {
|
||||
private int perm;
|
||||
private boolean order;
|
||||
|
||||
private String messageType;
|
||||
public List<String> getClusterNameList() {
|
||||
return clusterNameList;
|
||||
}
|
||||
@@ -92,6 +92,18 @@ public class TopicConfigInfo {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
|
||||
public String getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public void setMessageType(String messageType) {
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
@@ -103,12 +115,13 @@ public class TopicConfigInfo {
|
||||
readQueueNums == that.readQueueNums &&
|
||||
perm == that.perm &&
|
||||
order == that.order &&
|
||||
Objects.equal(topicName, that.topicName);
|
||||
Objects.equal(topicName, that.topicName) &&
|
||||
Objects.equal(messageType, that.messageType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order);
|
||||
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order,messageType);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TopicTypeList {
|
||||
private List<String> topicNameList;
|
||||
private List<String> messageTypeList;
|
||||
|
||||
public List<String> getTopicNameList() {
|
||||
return topicNameList;
|
||||
}
|
||||
|
||||
public void setTopicNameList(List<String> topicNameList) {
|
||||
this.topicNameList = topicNameList;
|
||||
}
|
||||
|
||||
public List<String> getMessageTypeList() {
|
||||
return messageTypeList;
|
||||
}
|
||||
|
||||
public void setMessageTypeList(List<String> messageTypeList) {
|
||||
this.messageTypeList = messageTypeList;
|
||||
}
|
||||
|
||||
public TopicTypeList(List<String> topicNameList, List<String> messageTypeList) {
|
||||
this.topicNameList = topicNameList;
|
||||
this.messageTypeList = messageTypeList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
public class TopicTypeMeta {
|
||||
private String topicName;
|
||||
private String messageType;
|
||||
|
||||
public String getTopicName() {
|
||||
return topicName;
|
||||
}
|
||||
|
||||
public void setTopicName(String topicName) {
|
||||
this.topicName = topicName;
|
||||
}
|
||||
|
||||
public String getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public void setMessageType(String messageType) {
|
||||
this.messageType = messageType;
|
||||
}
|
||||
}
|
@@ -19,8 +19,8 @@ package org.apache.rocketmq.dashboard.service;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
@@ -28,7 +28,7 @@ import org.apache.commons.collections.CollectionUtils;
|
||||
public abstract class AbstractCommonService {
|
||||
@Resource
|
||||
protected MQAdminExt mqAdminExt;
|
||||
protected final Set<String> changeToBrokerNameSet(HashMap<String, Set<String>> clusterAddrTable,
|
||||
protected final Set<String> changeToBrokerNameSet(Map<String, Set<String>> clusterAddrTable,
|
||||
List<String> clusterNameList, List<String> brokerNameList) {
|
||||
Set<String> finalBrokerNameList = Sets.newHashSet();
|
||||
if (CollectionUtils.isNotEmpty(clusterNameList)) {
|
||||
@@ -38,7 +38,8 @@ public abstract class AbstractCommonService {
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(brokerNameList)) {
|
||||
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
|
||||
public interface AclService {
|
||||
|
||||
AclConfig getAclConfig(boolean excludeSecretKey);
|
||||
|
||||
void addAclConfig(PlainAccessConfig config);
|
||||
|
||||
void deleteAclConfig(PlainAccessConfig config);
|
||||
|
||||
void updateAclConfig(PlainAccessConfig config);
|
||||
|
||||
void addOrUpdateAclTopicConfig(AclRequest request);
|
||||
|
||||
void addOrUpdateAclGroupConfig(AclRequest request);
|
||||
|
||||
void deletePermConfig(AclRequest request);
|
||||
|
||||
void syncData(PlainAccessConfig config);
|
||||
|
||||
void addWhiteList(List<String> whiteList);
|
||||
|
||||
void deleteWhiteAddr(String addr);
|
||||
|
||||
void synchronizeWhiteList(List<String> whiteList);
|
||||
}
|
@@ -17,8 +17,8 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
|
||||
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
|
||||
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
|
||||
@@ -31,12 +31,12 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ConsumerService {
|
||||
List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup);
|
||||
List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup,String address);
|
||||
|
||||
GroupConsumeInfo queryGroup(String consumerGroup);
|
||||
GroupConsumeInfo queryGroup(String consumerGroup, String address);
|
||||
|
||||
|
||||
List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName);
|
||||
List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName, String address);
|
||||
|
||||
List<TopicConsumerInfo> queryConsumeStatsList(String topic, String groupName);
|
||||
|
||||
@@ -52,7 +52,7 @@ public interface ConsumerService {
|
||||
|
||||
Set<String> fetchBrokerNameSetBySubscriptionGroup(String group);
|
||||
|
||||
ConsumerConnection getConsumerConnection(String consumerGroup);
|
||||
ConsumerConnection getConsumerConnection(String consumerGroup, String address);
|
||||
|
||||
ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack);
|
||||
}
|
||||
|
@@ -17,10 +17,15 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageResendResult;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
|
||||
public interface DlqMessageService {
|
||||
|
||||
MessagePage queryDlqMessageByPage(MessageQuery query);
|
||||
|
||||
List<DlqMessageResendResult> batchResendDlqMessage(List<DlqMessageRequest> dlqMessages);
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
|
@@ -31,4 +31,6 @@ public interface OpsService {
|
||||
boolean updateIsVIPChannel(String useVIPChannel);
|
||||
|
||||
boolean updateUseTLS(boolean useTLS);
|
||||
|
||||
void addNameSvrAddr(String namesrvAddr);
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
|
||||
public interface ProducerService {
|
||||
ProducerConnection getProducerConnection(String producerGroup, String topic);
|
||||
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ProxyService {
|
||||
|
||||
void addProxyAddrList(String proxyAddr);
|
||||
|
||||
void updateProxyAddrList(String proxyAddr);
|
||||
|
||||
Map<String, Object> getProxyHomePage();
|
||||
}
|
@@ -19,10 +19,11 @@ package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||
|
||||
@@ -31,6 +32,8 @@ import java.util.List;
|
||||
public interface TopicService {
|
||||
TopicList fetchAllTopicList(boolean skipSysProcess, boolean skipRetryAndDlq);
|
||||
|
||||
TopicTypeList examineAllTopicType();
|
||||
|
||||
TopicStatsTable stats(String topic);
|
||||
|
||||
TopicRouteData route(String topic);
|
||||
|
@@ -17,43 +17,16 @@
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import org.apache.rocketmq.client.QueryResult;
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.client.impl.MQAdminImpl;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.RequestCode;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterAclVersionInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeStatsList;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
|
||||
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
|
||||
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.common.message.MessageRequestMode;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.apache.rocketmq.remoting.RemotingClient;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
|
||||
@@ -62,13 +35,51 @@ import org.apache.rocketmq.remoting.exception.RemotingException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
|
||||
import org.apache.rocketmq.remoting.protocol.RequestCode;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerReplicasInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterAclVersionInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeStatsList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.EpochEntryCache;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.HARuntimeInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerTableInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.QueryConsumeQueueResponseBody;
|
||||
import org.apache.rocketmq.remoting.protocol.body.QueueTimeSpan;
|
||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
|
||||
import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingDetail;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.GroupForbidden;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.tools.admin.api.BrokerOperatorResult;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
import org.joor.Reflect;
|
||||
import org.apache.rocketmq.tools.admin.common.AdminToolResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.rocketmq.remoting.protocol.RemotingSerializable.decode;
|
||||
|
||||
@Service
|
||||
@@ -81,7 +92,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
@Override
|
||||
public void updateBrokerConfig(String brokerAddr, Properties properties)
|
||||
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
|
||||
UnsupportedEncodingException, InterruptedException, MQBrokerException {
|
||||
UnsupportedEncodingException, InterruptedException, MQBrokerException, MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().updateBrokerConfig(brokerAddr, properties);
|
||||
}
|
||||
|
||||
@@ -91,29 +102,34 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateTopicConfig(addr, config);
|
||||
}
|
||||
|
||||
@Override public void createAndUpdatePlainAccessConfig(String addr,
|
||||
@Override
|
||||
public void createAndUpdatePlainAccessConfig(String addr,
|
||||
PlainAccessConfig plainAccessConfig) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
|
||||
MQAdminInstance.threadLocalMQAdminExt().createAndUpdatePlainAccessConfig(addr, plainAccessConfig);
|
||||
}
|
||||
|
||||
@Override public void deletePlainAccessConfig(String addr,
|
||||
@Override
|
||||
public void deletePlainAccessConfig(String addr,
|
||||
String accessKey) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
|
||||
MQAdminInstance.threadLocalMQAdminExt().deletePlainAccessConfig(addr, accessKey);
|
||||
}
|
||||
|
||||
@Override public void updateGlobalWhiteAddrConfig(String addr,
|
||||
@Override
|
||||
public void updateGlobalWhiteAddrConfig(String addr,
|
||||
String globalWhiteAddrs) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
|
||||
MQAdminInstance.threadLocalMQAdminExt().updateGlobalWhiteAddrConfig(addr, globalWhiteAddrs);
|
||||
}
|
||||
|
||||
@Override public ClusterAclVersionInfo examineBrokerClusterAclVersionInfo(
|
||||
@Override
|
||||
public ClusterAclVersionInfo examineBrokerClusterAclVersionInfo(
|
||||
String addr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public AclConfig examineBrokerClusterAclConfig(
|
||||
@Override
|
||||
public AclConfig examineBrokerClusterAclConfig(
|
||||
String addr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
return null;
|
||||
return MQAdminInstance.threadLocalMQAdminExt().examineBrokerClusterAclConfig(addr);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +139,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionGroupConfig examineSubscriptionGroupConfig(String addr, String group) {
|
||||
public SubscriptionGroupConfig examineSubscriptionGroupConfig(String addr, String group) throws MQBrokerException {
|
||||
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
|
||||
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_SUBSCRIPTIONGROUP_CONFIG, null);
|
||||
RemotingCommand response = null;
|
||||
@@ -131,7 +147,8 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
response = remotingClient.invokeSync(addr, request, 3000);
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
assert response != null;
|
||||
switch (response.getCode()) {
|
||||
@@ -140,12 +157,12 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
return subscriptionGroupWrapper.getSubscriptionGroupTable().get(group);
|
||||
}
|
||||
default:
|
||||
throw Throwables.propagate(new MQBrokerException(response.getCode(), response.getRemark()));
|
||||
throw new MQBrokerException(response.getCode(), response.getRemark());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfig examineTopicConfig(String addr, String topic) {
|
||||
public TopicConfig examineTopicConfig(String addr, String topic) throws MQBrokerException {
|
||||
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
|
||||
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_TOPIC_CONFIG, null);
|
||||
RemotingCommand response = null;
|
||||
@@ -153,7 +170,8 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
response = remotingClient.invokeSync(addr, request, 3000);
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
switch (response.getCode()) {
|
||||
case ResponseCode.SUCCESS: {
|
||||
@@ -161,7 +179,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
return topicConfigSerializeWrapper.getTopicConfigTable().get(topic);
|
||||
}
|
||||
default:
|
||||
throw Throwables.propagate(new MQBrokerException(response.getCode(), response.getRemark()));
|
||||
throw new MQBrokerException(response.getCode(), response.getRemark());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +253,12 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().wipeWritePermOfBroker(namesrvAddr, brokerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addWritePermOfBroker(String namesrvAddr,
|
||||
String brokerName) throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQClientException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().addWritePermOfBroker(namesrvAddr, brokerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putKVConfig(String namespace, String key, String value) {
|
||||
MQAdminInstance.threadLocalMQAdminExt().putKVConfig(namespace, key, value);
|
||||
@@ -272,8 +296,9 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
throw new UnsupportedOperationException();
|
||||
public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName, removeOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -364,14 +389,14 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTopic(String key, String newTopic, int queueNum) throws MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum);
|
||||
public void createTopic(String key, String newTopic, int queueNum, Map<String, String> attributes) throws MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag)
|
||||
public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag, Map<String, String> attributes)
|
||||
throws MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag);
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -439,15 +464,18 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
MQAdminImpl mqAdminImpl = MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl();
|
||||
QueryResult qr = Reflect.on(mqAdminImpl).call("queryMessage", topic, msgId, 32,
|
||||
MessageClientIDSetter.getNearlyTimeFromID(msgId).getTime() - 1000 * 60 * 60 * 13L, Long.MAX_VALUE, true).get();
|
||||
if (qr != null && qr.getMessageList() != null && qr.getMessageList().size() > 0) {
|
||||
return qr.getMessageList().get(0);
|
||||
|
||||
Set<String> clusterList = MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
|
||||
if (clusterList == null || clusterList.isEmpty()) {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().queryMessage("", topic, msgId);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
for (String name : clusterList) {
|
||||
MessageExt messageExt = MQAdminInstance.threadLocalMQAdminExt().queryMessage(name, topic, msgId);
|
||||
if (messageExt != null) {
|
||||
return messageExt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -511,9 +539,21 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfigSerializeWrapper getAllTopicGroup(String brokerAddr,
|
||||
public SubscriptionGroupWrapper getUserSubscriptionGroup(String brokerAddr,
|
||||
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getAllTopicGroup(brokerAddr, timeoutMillis);
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getUserSubscriptionGroup(brokerAddr, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfigSerializeWrapper getAllTopicConfig(String brokerAddr,
|
||||
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getAllTopicConfig(brokerAddr, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfigSerializeWrapper getUserTopicConfig(String brokerAddr, boolean specialTopic,
|
||||
long timeoutMillis) throws InterruptedException, RemotingException, MQBrokerException, MQClientException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getUserTopicConfig(brokerAddr, specialTopic, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -548,4 +588,256 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBrokerToContainer(String brokerContainerAddr, String brokerConfig) throws InterruptedException,
|
||||
MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'addBrokerToContainer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBrokerFromContainer(String brokerContainerAddr, String clusterName, String brokerName,
|
||||
long brokerId) throws InterruptedException, MQBrokerException, RemotingTimeoutException,
|
||||
RemotingSendRequestException, RemotingConnectException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'removeBrokerFromContainer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateGlobalWhiteAddrConfig(String addr, String globalWhiteAddrs, String aclFileFullPath)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'updateGlobalWhiteAddrConfig'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicStatsTable examineTopicStats(String brokerAddr, String topic)
|
||||
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'examineTopicStats'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<TopicStatsTable> examineTopicStatsConcurrent(String topic) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'examineTopicStatsConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumeStats examineConsumeStats(String brokerAddr, String consumerGroup, String topicName,
|
||||
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
|
||||
RemotingConnectException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(brokerAddr, consumerGroup, topicName, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<ConsumeStats> examineConsumeStatsConcurrent(String consumerGroup, String topic) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'examineConsumeStatsConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumerConnection examineConsumerConnectionInfo(String consumerGroup, String brokerAddr)
|
||||
throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().examineConsumerConnectionInfo(consumerGroup, brokerAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProducerTableInfo getAllProducerInfo(String brokerAddr)
|
||||
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getAllProducerInfo'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTopic(String topicName, String clusterName)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteTopic'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<BrokerOperatorResult> deleteTopicInBrokerConcurrent(Set<String> addrs, String topic) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteTopicInBrokerConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTopicInNameServer(Set<String> addrs, String clusterName, String topic)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteTopicInNameServer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<BrokerOperatorResult> resetOffsetNewConcurrent(String group, String topic, long timestamp) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'resetOffsetNewConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicList queryTopicsByConsumer(String group)
|
||||
throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryTopicsByConsumer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<TopicList> queryTopicsByConsumerConcurrent(String group) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryTopicsByConsumerConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionData querySubscription(String group, String topic)
|
||||
throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'querySubscription'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<List<QueueTimeSpan>> queryConsumeTimeSpanConcurrent(String topic, String group) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryConsumeTimeSpanConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteExpiredCommitLog(String cluster) throws RemotingConnectException, RemotingSendRequestException,
|
||||
RemotingTimeoutException, MQClientException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteExpiredCommitLog'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteExpiredCommitLogByAddr(String addr) throws RemotingConnectException,
|
||||
RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteExpiredCommitLogByAddr'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack,
|
||||
boolean metrics) throws RemotingException, MQClientException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getConsumerRunningInfo'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MessageTrack> messageTrackDetailConcurrent(MessageExt msg)
|
||||
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'messageTrackDetailConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageRequestMode(String brokerAddr, String topic, String consumerGroup, MessageRequestMode mode,
|
||||
int popWorkGroupSize, long timeoutMillis) throws InterruptedException, RemotingTimeoutException,
|
||||
RemotingSendRequestException, RemotingConnectException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setMessageRequestMode'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long searchOffset(String brokerAddr, String topicName, int queueId, long timestamp, long timeoutMillis)
|
||||
throws RemotingException, MQBrokerException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'searchOffset'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetOffsetByQueueId(String brokerAddr, String consumerGroup, String topicName, int queueId,
|
||||
long resetOffset) throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'resetOffsetByQueueId'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createStaticTopic(String addr, String defaultTopic, TopicConfig topicConfig,
|
||||
TopicQueueMappingDetail mappingDetail, boolean force)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'createStaticTopic'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupForbidden updateAndGetGroupReadForbidden(String brokerAddr, String groupName, String topicName,
|
||||
Boolean readable) throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'updateAndGetGroupReadForbidden'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageExt queryMessage(String clusterName, String topic, String msgId)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryMessage'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HARuntimeInfo getBrokerHAStatus(String brokerAddr) throws RemotingConnectException,
|
||||
RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getBrokerHAStatus'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrokerReplicasInfo getInSyncStateData(String controllerAddress, List<String> brokers)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getInSyncStateData'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EpochEntryCache getBrokerEpochCache(String brokerAddr)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getBrokerEpochCache'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetMetaDataResponseHeader getControllerMetaData(String controllerAddr)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getControllerMetaData'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMasterFlushOffset(String brokerAddr, long masterFlushOffset) throws InterruptedException,
|
||||
MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'resetMasterFlushOffset'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Properties> getControllerConfig(List<String> controllerServers)
|
||||
throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
|
||||
RemotingConnectException, MQClientException, UnsupportedEncodingException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getControllerConfig'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateControllerConfig(Properties properties, List<String> controllers)
|
||||
throws InterruptedException, RemotingConnectException, UnsupportedEncodingException,
|
||||
RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'updateControllerConfig'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElectMasterResponseHeader electMaster(String controllerAddr, String clusterName, String brokerName,
|
||||
String brokerAddr) throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'electMaster'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanControllerBrokerData(String controllerAddr, String clusterName, String brokerName,
|
||||
String brokerAddr, boolean isCleanLivingBroker)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'cleanControllerBrokerData'");
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
|
||||
public interface ProxyAdmin {
|
||||
|
||||
ConsumerConnection examineConsumerConnectionInfo(String addr, String consumerGroup) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQBrokerException;
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.remoting.RemotingClient;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.header.GetConsumerConnectionListRequestHeader;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static org.apache.rocketmq.remoting.protocol.RequestCode.GET_CONSUMER_CONNECTION_LIST;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ProxyAdminImpl implements ProxyAdmin {
|
||||
@Autowired
|
||||
private GenericObjectPool<MQAdminExt> mqAdminExtPool;
|
||||
|
||||
@Override
|
||||
public ConsumerConnection examineConsumerConnectionInfo(String addr, String consumerGroup) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQBrokerException {
|
||||
try {
|
||||
MQAdminInstance.createMQAdmin(mqAdminExtPool);
|
||||
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
|
||||
GetConsumerConnectionListRequestHeader requestHeader = new GetConsumerConnectionListRequestHeader();
|
||||
requestHeader.setConsumerGroup(consumerGroup);
|
||||
RemotingCommand request = RemotingCommand.createRequestCommand(GET_CONSUMER_CONNECTION_LIST, requestHeader);
|
||||
RemotingCommand response = remotingClient.invokeSync(addr, request, 3000);
|
||||
switch (response.getCode()) {
|
||||
case 0:
|
||||
return ConsumerConnection.decode(response.getBody(), ConsumerConnection.class);
|
||||
default:
|
||||
throw new MQBrokerException(response.getCode(), response.getRemark(), addr);
|
||||
}
|
||||
} finally {
|
||||
MQAdminInstance.returnMQAdmin(mqAdminExtPool);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.AclService;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AclServiceImpl extends AbstractCommonService implements AclService {
|
||||
|
||||
@Override
|
||||
public AclConfig getAclConfig(boolean excludeSecretKey) {
|
||||
try {
|
||||
Optional<String> addr = getMasterSet().stream().findFirst();
|
||||
if (addr.isPresent()) {
|
||||
if (!excludeSecretKey) {
|
||||
return mqAdminExt.examineBrokerClusterAclConfig(addr.get());
|
||||
} else {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr.get());
|
||||
if (CollectionUtils.isNotEmpty(aclConfig.getPlainAccessConfigs())) {
|
||||
aclConfig.getPlainAccessConfigs().forEach(pac -> pac.setSecretKey(null));
|
||||
}
|
||||
return aclConfig;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("getAclConfig error.", e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
AclConfig aclConfig = new AclConfig();
|
||||
aclConfig.setGlobalWhiteAddrs(Collections.emptyList());
|
||||
aclConfig.setPlainAccessConfigs(Collections.emptyList());
|
||||
return aclConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAclConfig(PlainAccessConfig config) {
|
||||
try {
|
||||
Set<String> masterSet = getMasterSet();
|
||||
|
||||
if (masterSet.isEmpty()) {
|
||||
throw new IllegalStateException("broker addr list is empty");
|
||||
}
|
||||
// check to see if account is exists
|
||||
for (String addr : masterSet) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
List<PlainAccessConfig> plainAccessConfigs = aclConfig.getPlainAccessConfigs();
|
||||
for (PlainAccessConfig pac : plainAccessConfigs) {
|
||||
if (pac.getAccessKey().equals(config.getAccessKey())) {
|
||||
throw new IllegalArgumentException(String.format("broker: %s, exist accessKey: %s", addr, config.getAccessKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all broker
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAclConfig(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
log.info("Start to delete acl [{}] from broker [{}]", config.getAccessKey(), addr);
|
||||
if (isExistAccessKey(config.getAccessKey(), addr)) {
|
||||
mqAdminExt.deletePlainAccessConfig(addr, config.getAccessKey());
|
||||
}
|
||||
log.info("Delete acl [{}] from broker [{}] complete", config.getAccessKey(), addr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAclConfig(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
for (PlainAccessConfig pac : aclConfig.getPlainAccessConfigs()) {
|
||||
if (pac.getAccessKey().equals(config.getAccessKey())) {
|
||||
remoteConfig = pac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remoteConfig != null) {
|
||||
remoteConfig.setSecretKey(config.getSecretKey());
|
||||
remoteConfig.setAdmin(config.isAdmin());
|
||||
config = remoteConfig;
|
||||
}
|
||||
}
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOrUpdateAclTopicConfig(AclRequest request) {
|
||||
try {
|
||||
PlainAccessConfig addConfig = request.getConfig();
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
for (PlainAccessConfig config : aclConfig.getPlainAccessConfigs()) {
|
||||
if (config.getAccessKey().equals(addConfig.getAccessKey())) {
|
||||
remoteConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remoteConfig == null) {
|
||||
// Maybe the broker no acl config of the access key, therefore add it;
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, addConfig);
|
||||
} else {
|
||||
if (remoteConfig.getTopicPerms() == null) {
|
||||
remoteConfig.setTopicPerms(new ArrayList<>());
|
||||
}
|
||||
removeExist(remoteConfig.getTopicPerms(), request.getTopicPerm().split("=")[0]);
|
||||
remoteConfig.getTopicPerms().add(request.getTopicPerm());
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, remoteConfig);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOrUpdateAclGroupConfig(AclRequest request) {
|
||||
try {
|
||||
PlainAccessConfig addConfig = request.getConfig();
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
for (PlainAccessConfig config : aclConfig.getPlainAccessConfigs()) {
|
||||
if (config.getAccessKey().equals(addConfig.getAccessKey())) {
|
||||
remoteConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remoteConfig == null) {
|
||||
// May be the broker no acl config of the access key, therefore add it;
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, addConfig);
|
||||
} else {
|
||||
if (remoteConfig.getGroupPerms() == null) {
|
||||
remoteConfig.setGroupPerms(new ArrayList<>());
|
||||
}
|
||||
removeExist(remoteConfig.getGroupPerms(), request.getGroupPerm().split("=")[0]);
|
||||
remoteConfig.getGroupPerms().add(request.getGroupPerm());
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, remoteConfig);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePermConfig(AclRequest request) {
|
||||
try {
|
||||
PlainAccessConfig deleteConfig = request.getConfig();
|
||||
|
||||
String topic = StringUtils.isNotEmpty(request.getTopicPerm()) ? request.getTopicPerm().split("=")[0] : null;
|
||||
String group = StringUtils.isNotEmpty(request.getGroupPerm()) ? request.getGroupPerm().split("=")[0] : null;
|
||||
if (deleteConfig.getTopicPerms() != null && topic != null) {
|
||||
removeExist(deleteConfig.getTopicPerms(), topic);
|
||||
}
|
||||
if (deleteConfig.getGroupPerms() != null && group != null) {
|
||||
removeExist(deleteConfig.getGroupPerms(), group);
|
||||
}
|
||||
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
for (PlainAccessConfig config : aclConfig.getPlainAccessConfigs()) {
|
||||
if (config.getAccessKey().equals(deleteConfig.getAccessKey())) {
|
||||
remoteConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remoteConfig == null) {
|
||||
// Maybe the broker no acl config of the access key, therefore add it;
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, deleteConfig);
|
||||
} else {
|
||||
if (remoteConfig.getTopicPerms() != null && topic != null) {
|
||||
removeExist(remoteConfig.getTopicPerms(), topic);
|
||||
}
|
||||
if (remoteConfig.getGroupPerms() != null && group != null) {
|
||||
removeExist(remoteConfig.getGroupPerms(), group);
|
||||
}
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, remoteConfig);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncData(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWhiteList(List<String> whiteList) {
|
||||
if (whiteList == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
if (aclConfig.getGlobalWhiteAddrs() != null) {
|
||||
aclConfig.setGlobalWhiteAddrs(Stream.of(whiteList, aclConfig.getGlobalWhiteAddrs()).flatMap(Collection::stream).distinct().collect(Collectors.toList()));
|
||||
} else {
|
||||
aclConfig.setGlobalWhiteAddrs(whiteList);
|
||||
}
|
||||
mqAdminExt.updateGlobalWhiteAddrConfig(addr, StringUtils.join(aclConfig.getGlobalWhiteAddrs(), ","));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWhiteAddr(String deleteAddr) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
if (aclConfig.getGlobalWhiteAddrs() == null || aclConfig.getGlobalWhiteAddrs().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
aclConfig.getGlobalWhiteAddrs().remove(deleteAddr);
|
||||
mqAdminExt.updateGlobalWhiteAddrConfig(addr, StringUtils.join(aclConfig.getGlobalWhiteAddrs(), ","));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeWhiteList(List<String> whiteList) {
|
||||
if (whiteList == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.updateGlobalWhiteAddrConfig(addr, StringUtils.join(whiteList, ","));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeExist(List<String> list, String name) {
|
||||
Iterator<String> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String v = iterator.next();
|
||||
String cmp = v.split("=")[0];
|
||||
if (cmp.equals(name)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExistAccessKey(String accessKey,
|
||||
String addr) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
List<PlainAccessConfig> plainAccessConfigs = aclConfig.getPlainAccessConfigs();
|
||||
if (plainAccessConfigs == null || plainAccessConfigs.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (PlainAccessConfig config : plainAccessConfigs) {
|
||||
if (accessKey.equals(config.getAccessKey())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<BrokerData> getBrokerDataSet() throws InterruptedException, RemotingConnectException, RemotingTimeoutException, RemotingSendRequestException, MQBrokerException {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
Map<String, BrokerData> brokerDataMap = clusterInfo.getBrokerAddrTable();
|
||||
return new HashSet<>(brokerDataMap.values());
|
||||
}
|
||||
|
||||
private Set<String> getMasterSet() throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
return getBrokerDataSet().stream().map(data -> data.getBrokerAddrs().get(MixAll.MASTER_ID)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<String> getBrokerAddrs() throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
Set<String> brokerAddrs = new HashSet<>();
|
||||
getBrokerDataSet().forEach(data -> brokerAddrs.addAll(data.getBrokerAddrs().values()));
|
||||
return brokerAddrs;
|
||||
}
|
||||
}
|
@@ -17,9 +17,10 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.attribute.TopicMessageType;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.dashboard.service.ClusterService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
@@ -30,8 +31,10 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class ClusterServiceImpl implements ClusterService {
|
||||
@@ -56,10 +59,14 @@ public class ClusterServiceImpl implements ClusterService {
|
||||
}
|
||||
resultMap.put("clusterInfo", clusterInfo);
|
||||
resultMap.put("brokerServer", brokerServer);
|
||||
// add messageType
|
||||
resultMap.put("messageTypes", Arrays.stream(TopicMessageType.values()).sorted()
|
||||
.collect(Collectors.toMap(TopicMessageType::getValue, messageType ->String.format("MESSAGE_TYPE_%s",messageType.getValue()))));
|
||||
return resultMap;
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +77,8 @@ public class ClusterServiceImpl implements ClusterService {
|
||||
return mqAdminExt.getBrokerConfig(brokerAddr);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,29 +23,44 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MQVersion;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.dashboard.service.client.ProxyAdmin;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.Connection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.common.utils.ThreadUtils;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
|
||||
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
|
||||
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
|
||||
@@ -57,16 +72,46 @@ import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
@Service
|
||||
public class ConsumerServiceImpl extends AbstractCommonService implements ConsumerService {
|
||||
public class ConsumerServiceImpl extends AbstractCommonService implements ConsumerService, InitializingBean, DisposableBean {
|
||||
private Logger logger = LoggerFactory.getLogger(ConsumerServiceImpl.class);
|
||||
|
||||
@Resource
|
||||
protected ProxyAdmin proxyAdmin;
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
private static final Set<String> SYSTEM_GROUP_SET = new HashSet<>();
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
int corePoolSize = Math.max(10, runtime.availableProcessors() * 2);
|
||||
int maximumPoolSize = Math.max(20, runtime.availableProcessors() * 2);
|
||||
ThreadFactory threadFactory = new ThreadFactory() {
|
||||
private final AtomicLong threadIndex = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "QueryGroup_" + this.threadIndex.incrementAndGet());
|
||||
}
|
||||
};
|
||||
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
|
||||
this.executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 60L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(5000), threadFactory, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
ThreadUtils.shutdownGracefully(executorService, 10L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static {
|
||||
SYSTEM_GROUP_SET.add(MixAll.TOOLS_CONSUMER_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.FILTERSRV_CONSUMER_GROUP);
|
||||
@@ -79,22 +124,47 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup) {
|
||||
Set<String> consumerGroupSet = Sets.newHashSet();
|
||||
public List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup, String address) {
|
||||
HashMap<String, List<String>> consumerGroupMap = Maps.newHashMap();
|
||||
try {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
for (BrokerData brokerData : clusterInfo.getBrokerAddrTable().values()) {
|
||||
SubscriptionGroupWrapper subscriptionGroupWrapper = mqAdminExt.getAllSubscriptionGroup(brokerData.selectBrokerAddr(), 3000L);
|
||||
consumerGroupSet.addAll(subscriptionGroupWrapper.getSubscriptionGroupTable().keySet());
|
||||
for (String groupName : subscriptionGroupWrapper.getSubscriptionGroupTable().keySet()) {
|
||||
if (!consumerGroupMap.containsKey(groupName)) {
|
||||
consumerGroupMap.putIfAbsent(groupName, new ArrayList<>());
|
||||
}
|
||||
List<String> addresses = consumerGroupMap.get(groupName);
|
||||
addresses.add(brokerData.selectBrokerAddr());
|
||||
consumerGroupMap.put(groupName, addresses);
|
||||
}
|
||||
}
|
||||
} catch (Exception err) {
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
List<GroupConsumeInfo> groupConsumeInfoList = Collections.synchronizedList(Lists.newArrayList());
|
||||
CountDownLatch countDownLatch = new CountDownLatch(consumerGroupMap.size());
|
||||
for (Map.Entry<String, List<String>> entry : consumerGroupMap.entrySet()) {
|
||||
String consumerGroup = entry.getKey();
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
GroupConsumeInfo consumeInfo = queryGroup(consumerGroup, address);
|
||||
consumeInfo.setAddress(entry.getValue());
|
||||
groupConsumeInfoList.add(consumeInfo);
|
||||
} catch (Exception e) {
|
||||
logger.error("queryGroup exception, consumerGroup: {}", consumerGroup, e);
|
||||
} finally {
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
List<GroupConsumeInfo> groupConsumeInfoList = Lists.newArrayList();
|
||||
for (String consumerGroup : consumerGroupSet) {
|
||||
groupConsumeInfoList.add(queryGroup(consumerGroup));
|
||||
try {
|
||||
countDownLatch.await(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("query consumerGroup countDownLatch await Exception", e);
|
||||
}
|
||||
|
||||
if (!skipSysGroup) {
|
||||
groupConsumeInfoList.stream().map(group -> {
|
||||
if (SYSTEM_GROUP_SET.contains(group.getGroup())) {
|
||||
@@ -108,7 +178,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupConsumeInfo queryGroup(String consumerGroup) {
|
||||
public GroupConsumeInfo queryGroup(String consumerGroup, String address) {
|
||||
GroupConsumeInfo groupConsumeInfo = new GroupConsumeInfo();
|
||||
try {
|
||||
ConsumeStats consumeStats = null;
|
||||
@@ -120,14 +190,28 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
ConsumerConnection consumerConnection = null;
|
||||
boolean isFifoType = examineSubscriptionGroupConfig(consumerGroup)
|
||||
.stream().map(ConsumerConfigInfo::getSubscriptionGroupConfig)
|
||||
.allMatch(SubscriptionGroupConfig::isConsumeMessageOrderly);
|
||||
|
||||
try {
|
||||
consumerConnection = mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (StringUtils.isNotEmpty(address)) {
|
||||
consumerConnection = proxyAdmin.examineConsumerConnectionInfo(address, consumerGroup);
|
||||
} else {
|
||||
consumerConnection = mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("examineConsumeStats exception to consumerGroup {}, response [{}]", consumerGroup, e.getMessage());
|
||||
}
|
||||
|
||||
groupConsumeInfo.setGroup(consumerGroup);
|
||||
if (SYSTEM_GROUP_SET.contains(consumerGroup)) {
|
||||
groupConsumeInfo.setSubGroupType("SYSTEM");
|
||||
} else if (isFifoType) {
|
||||
groupConsumeInfo.setSubGroupType("FIFO");
|
||||
} else {
|
||||
groupConsumeInfo.setSubGroupType("NORMAL");
|
||||
}
|
||||
|
||||
if (consumeStats != null) {
|
||||
groupConsumeInfo.setConsumeTps((int)consumeStats.getConsumeTps());
|
||||
@@ -149,8 +233,18 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName) {
|
||||
return queryConsumeStatsList(null, groupName);
|
||||
public List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName, String address) {
|
||||
ConsumeStats consumeStats;
|
||||
String topic = null;
|
||||
try {
|
||||
String[] addresses = address.split(",");
|
||||
String addr = addresses[0];
|
||||
consumeStats = mqAdminExt.examineConsumeStats(addr, groupName, null, 3000);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return toTopicConsumerInfoList(topic, consumeStats, groupName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,8 +254,13 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
consumeStats = mqAdminExt.examineConsumeStats(groupName, topic);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return toTopicConsumerInfoList(topic, consumeStats, groupName);
|
||||
}
|
||||
|
||||
private List<TopicConsumerInfo> toTopicConsumerInfoList(String topic, ConsumeStats consumeStats, String groupName) {
|
||||
List<MessageQueue> mqList = Lists.newArrayList(Iterables.filter(consumeStats.getOffsetTable().keySet(), new Predicate<MessageQueue>() {
|
||||
@Override
|
||||
public boolean apply(MessageQueue o) {
|
||||
@@ -220,7 +319,8 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
return group2ConsumerInfoMap;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,26 +383,50 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return consumerConfigInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSubGroup(DeleteSubGroupRequest deleteSubGroupRequest) {
|
||||
Set<String> brokerSet = this.fetchBrokerNameSetBySubscriptionGroup(deleteSubGroupRequest.getGroupName());
|
||||
List<String> brokerList = deleteSubGroupRequest.getBrokerNameList();
|
||||
boolean deleteInNsFlag = false;
|
||||
// If the list of brokers passed in by the request contains the list of brokers that the consumer is in, delete RETRY and DLQ topic in namesrv
|
||||
if (brokerList.containsAll(brokerSet)) {
|
||||
deleteInNsFlag = true;
|
||||
}
|
||||
try {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
for (String brokerName : deleteSubGroupRequest.getBrokerNameList()) {
|
||||
logger.info("addr={} groupName={}", clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName());
|
||||
mqAdminExt.deleteSubscriptionGroup(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName());
|
||||
mqAdminExt.deleteSubscriptionGroup(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName(), true);
|
||||
// Delete %RETRY%+Group and %DLQ%+Group in broker and namesrv
|
||||
deleteResources(MixAll.RETRY_GROUP_TOPIC_PREFIX + deleteSubGroupRequest.getGroupName(), brokerName, clusterInfo, deleteInNsFlag);
|
||||
deleteResources(MixAll.DLQ_GROUP_TOPIC_PREFIX + deleteSubGroupRequest.getGroupName(), brokerName, clusterInfo, deleteInNsFlag);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void deleteResources(String topic, String brokerName, ClusterInfo clusterInfo, boolean deleteInNsFlag) throws Exception {
|
||||
mqAdminExt.deleteTopicInBroker(Sets.newHashSet(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr()), topic);
|
||||
Set<String> nameServerSet = null;
|
||||
if (StringUtils.isNotBlank(configure.getNamesrvAddr())) {
|
||||
String[] ns = configure.getNamesrvAddr().split(";");
|
||||
nameServerSet = new HashSet<>(Arrays.asList(ns));
|
||||
}
|
||||
if (deleteInNsFlag) {
|
||||
mqAdminExt.deleteTopicInNameServer(nameServerSet, topic);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAndUpdateSubscriptionGroupConfig(ConsumerConfigInfo consumerConfigInfo) {
|
||||
try {
|
||||
@@ -313,7 +437,8 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -328,19 +453,22 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return brokerNameSet;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumerConnection getConsumerConnection(String consumerGroup) {
|
||||
public ConsumerConnection getConsumerConnection(String consumerGroup, String address) {
|
||||
try {
|
||||
return mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
String[] addresses = address.split(",");
|
||||
String addr = addresses[0];
|
||||
return mqAdminExt.examineConsumerConnectionInfo(consumerGroup, addr);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +478,8 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
return mqAdminExt.getConsumerRunningInfo(consumerGroup, clientId, jstack);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -107,7 +107,8 @@ public class DashboardCollectServiceImpl implements DashboardCollectService {
|
||||
strings = Files.readLines(file, Charsets.UTF_8);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (String string : strings) {
|
||||
|
@@ -19,12 +19,16 @@ package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageResendResult;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
@@ -58,11 +62,26 @@ public class DlqMessageServiceImpl implements DlqMessageService {
|
||||
&& e.getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) {
|
||||
return new MessagePage(new PageImpl<>(messageViews, page, 0), query.getTaskId());
|
||||
} else {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return messageService.queryMessageByPage(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DlqMessageResendResult> batchResendDlqMessage(List<DlqMessageRequest> dlqMessages) {
|
||||
List<DlqMessageResendResult> batchResendResults = new LinkedList<>();
|
||||
for (DlqMessageRequest dlqMessage : dlqMessages) {
|
||||
ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(dlqMessage.getTopicName(),
|
||||
dlqMessage.getMsgId(), dlqMessage.getConsumerGroup(),
|
||||
dlqMessage.getClientId());
|
||||
DlqMessageResendResult resendResult = new DlqMessageResendResult(result, dlqMessage.getMsgId());
|
||||
batchResendResults.add(resendResult);
|
||||
}
|
||||
return batchResendResults;
|
||||
}
|
||||
}
|
||||
|
@@ -31,14 +31,15 @@ import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
||||
import org.apache.rocketmq.client.consumer.PullResult;
|
||||
import org.apache.rocketmq.client.consumer.PullStatus;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.body.Connection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
|
||||
@@ -111,7 +112,11 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
});
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
if (err instanceof MQClientException) {
|
||||
throw new ServiceException(-1, ((MQClientException) err).getErrorMessage());
|
||||
}
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +186,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
});
|
||||
return messageViewList;
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
consumer.shutdown();
|
||||
}
|
||||
@@ -205,7 +211,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
try {
|
||||
return mqAdminExt.consumeMessageDirectly(consumerGroup, clientId, topic, msgId);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +226,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
return mqAdminExt.consumeMessageDirectly(consumerGroup, connection.getClientId(), topic, msgId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
throw new IllegalStateException("NO CONSUMER");
|
||||
|
||||
@@ -268,7 +276,7 @@ public class MessageServiceImpl implements MessageService {
|
||||
int idx = 0;
|
||||
for (MessageQueue messageQueue : messageQueues) {
|
||||
Long minOffset = consumer.searchOffset(messageQueue, query.getBegin());
|
||||
Long maxOffset = consumer.searchOffset(messageQueue, query.getEnd()) + 1;
|
||||
Long maxOffset = consumer.searchOffset(messageQueue, query.getEnd());
|
||||
queueOffsetInfos.add(new QueueOffsetInfo(idx++, minOffset, maxOffset, minOffset, minOffset, messageQueue));
|
||||
}
|
||||
|
||||
@@ -325,7 +333,7 @@ public class MessageServiceImpl implements MessageService {
|
||||
List<MessageExt> msgFoundList = pullResult.getMsgFoundList();
|
||||
for (int i = msgFoundList.size() - 1; i >= 0; i--) {
|
||||
MessageExt messageExt = msgFoundList.get(i);
|
||||
if (messageExt.getStoreTimestamp() < query.getBegin()) {
|
||||
if (messageExt.getStoreTimestamp() > query.getEnd()) {
|
||||
end--;
|
||||
} else {
|
||||
hasIllegalOffset = false;
|
||||
@@ -384,7 +392,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
PageImpl<MessageView> page = new PageImpl<>(messageViews, query.page(), total);
|
||||
return new MessagePageTask(page, queueOffsetInfos);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
consumer.shutdown();
|
||||
}
|
||||
@@ -451,7 +460,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
return new PageImpl<>(messageViews, query.page(), total);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
consumer.shutdown();
|
||||
}
|
||||
|
@@ -20,8 +20,6 @@ package org.apache.rocketmq.dashboard.service.impl;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -35,6 +33,7 @@ import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.MessageTraceView;
|
||||
import org.apache.rocketmq.dashboard.model.trace.ProducerNode;
|
||||
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
|
||||
@@ -82,7 +81,7 @@ public class MessageTraceServiceImpl implements MessageTraceService {
|
||||
}
|
||||
return messageTraceViews;
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
throw new ServiceException(-1, String.format("Failed to query message trace by msgId %s", key));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,8 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
MixAll.string2File(dataStr, path);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -46,7 +45,8 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
@Override
|
||||
public Map<String, Object> homePageInfo() {
|
||||
Map<String, Object> homePageInfoMap = Maps.newHashMap();
|
||||
homePageInfoMap.put("namesvrAddrList", Splitter.on(";").splitToList(configure.getNamesrvAddr()));
|
||||
homePageInfoMap.put("currentNamesrv", configure.getNamesrvAddr());
|
||||
homePageInfoMap.put("namesvrAddrList", configure.getNamesrvAddrs());
|
||||
homePageInfoMap.put("useVIPChannel", Boolean.valueOf(configure.getIsVIPChannel()));
|
||||
homePageInfoMap.put("useTLS", configure.isUseTLS());
|
||||
return homePageInfoMap;
|
||||
@@ -73,7 +73,8 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
return checkResultMap;
|
||||
}
|
||||
|
||||
@Override public boolean updateIsVIPChannel(String useVIPChannel) {
|
||||
@Override
|
||||
public boolean updateIsVIPChannel(String useVIPChannel) {
|
||||
configure.setIsVIPChannel(useVIPChannel);
|
||||
mqAdminExtPool.clear();
|
||||
return true;
|
||||
@@ -85,4 +86,13 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
mqAdminExtPool.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNameSvrAddr(String namesrvAddr) {
|
||||
List<String> namesrvAddrs = configure.getNamesrvAddrs();
|
||||
if (namesrvAddrs != null && !namesrvAddrs.contains(namesrvAddr)) {
|
||||
namesrvAddrs.add(namesrvAddr);
|
||||
}
|
||||
configure.setNamesrvAddrs(namesrvAddrs);
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.dashboard.service.ProducerService;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -35,7 +35,8 @@ public class ProducerServiceImpl implements ProducerService {
|
||||
return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.ProxyService;
|
||||
import org.apache.rocketmq.dashboard.service.client.ProxyAdmin;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ProxyServiceImpl implements ProxyService {
|
||||
@Resource
|
||||
protected ProxyAdmin proxyAdmin;
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Override
|
||||
public void addProxyAddrList(String proxyAddr) {
|
||||
List<String> proxyAddrs = configure.getProxyAddrs();
|
||||
if (proxyAddrs != null && !proxyAddrs.contains(proxyAddr)) {
|
||||
proxyAddrs.add(proxyAddr);
|
||||
}
|
||||
configure.setProxyAddrs(proxyAddrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProxyAddrList(String proxyAddr) {
|
||||
configure.setProxyAddr(proxyAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getProxyHomePage() {
|
||||
Map<String, Object> homePageInfoMap = Maps.newHashMap();
|
||||
homePageInfoMap.put("currentProxyAddr", configure.getProxyAddr());
|
||||
homePageInfoMap.put("proxyAddrList", configure.getProxyAddrs());
|
||||
return homePageInfoMap;
|
||||
}
|
||||
}
|
@@ -18,43 +18,57 @@
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||
import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.apache.rocketmq.client.producer.TransactionListener;
|
||||
import org.apache.rocketmq.client.producer.TransactionMQProducer;
|
||||
import org.apache.rocketmq.client.producer.LocalTransactionState;
|
||||
import org.apache.rocketmq.client.trace.TraceContext;
|
||||
import org.apache.rocketmq.client.trace.TraceDispatcher;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.attribute.TopicMessageType;
|
||||
import org.apache.rocketmq.common.message.Message;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeMeta;
|
||||
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.TopicService;
|
||||
import org.apache.rocketmq.remoting.RPCHook;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.tools.command.CommandUtil;
|
||||
import org.joor.Reflect;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE;
|
||||
|
||||
@Service
|
||||
public class TopicServiceImpl extends AbstractCommonService implements TopicService {
|
||||
@@ -68,23 +82,59 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
TopicList allTopics = mqAdminExt.fetchAllTopicList();
|
||||
TopicList sysTopics = getSystemTopicList();
|
||||
Set<String> topics =
|
||||
allTopics.getTopicList().stream().map(topic -> {
|
||||
if (!skipSysProcess && sysTopics.getTopicList().contains(topic)) {
|
||||
topic = String.format("%s%s", "%SYS%", topic);
|
||||
}
|
||||
return topic;
|
||||
}).filter(topic -> {
|
||||
if (skipRetryAndDlq) {
|
||||
return !(topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
|
||||
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX));
|
||||
}
|
||||
return true;
|
||||
}).collect(Collectors.toSet());
|
||||
allTopics.getTopicList().stream().map(topic -> {
|
||||
if (!skipSysProcess && sysTopics.getTopicList().contains(topic)) {
|
||||
topic = String.format("%s%s", "%SYS%", topic);
|
||||
}
|
||||
return topic;
|
||||
}).filter(topic -> {
|
||||
if (skipRetryAndDlq) {
|
||||
return !(topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
|
||||
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX));
|
||||
}
|
||||
return true;
|
||||
}).collect(Collectors.toSet());
|
||||
allTopics.getTopicList().clear();
|
||||
allTopics.getTopicList().addAll(topics);
|
||||
return allTopics;
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicTypeList examineAllTopicType() {
|
||||
ArrayList<TopicTypeMeta> topicTypes = new ArrayList<>();
|
||||
ArrayList<String> names = new ArrayList<>();
|
||||
ArrayList<String> messageTypes = new ArrayList<>();
|
||||
TopicList topicList = fetchAllTopicList(false, false);
|
||||
checkTopicType(topicList, topicTypes);
|
||||
topicTypes.sort((t1, t2) -> t1.getTopicName().compareTo(t2.getTopicName()));
|
||||
for (TopicTypeMeta topicTypeMeta : topicTypes) {
|
||||
names.add(topicTypeMeta.getTopicName());
|
||||
messageTypes.add(topicTypeMeta.getMessageType());
|
||||
}
|
||||
return new TopicTypeList(names, messageTypes);
|
||||
}
|
||||
|
||||
private void checkTopicType(TopicList topicList, ArrayList<TopicTypeMeta> topicTypes) {
|
||||
for (String topicName : topicList.getTopicList()) {
|
||||
TopicTypeMeta topicType = new TopicTypeMeta();
|
||||
topicType.setTopicName(topicName);
|
||||
if (topicName.startsWith("%R")) {
|
||||
topicType.setMessageType("RETRY");
|
||||
} else if (topicName.startsWith("%D")) {
|
||||
topicType.setMessageType("DELAY");
|
||||
} else if (topicName.startsWith("%S")) {
|
||||
topicType.setMessageType("SYSTEM");
|
||||
} else {
|
||||
List<TopicConfigInfo> topicConfigInfos = examineTopicConfig(topicName);
|
||||
if (!CollectionUtils.isEmpty(topicConfigInfos)) {
|
||||
topicType.setMessageType(topicConfigInfos.get(0).getMessageType());
|
||||
}
|
||||
}
|
||||
topicTypes.add(topicType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +143,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
return mqAdminExt.examineTopicStats(topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +153,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
return mqAdminExt.examineTopicRouteInfo(topic);
|
||||
} catch (Exception ex) {
|
||||
throw Throwables.propagate(ex);
|
||||
Throwables.throwIfUnchecked(ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +163,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
return mqAdminExt.queryTopicConsumeByWho(topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,14 +172,20 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
public void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest) {
|
||||
TopicConfig topicConfig = new TopicConfig();
|
||||
BeanUtils.copyProperties(topicCreateOrUpdateRequest, topicConfig);
|
||||
String messageType = topicCreateOrUpdateRequest.getMessageType();
|
||||
if (StringUtils.isBlank(messageType)) {
|
||||
messageType = TopicMessageType.NORMAL.name();
|
||||
}
|
||||
topicConfig.setAttributes(ImmutableMap.of("+".concat(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName()), messageType));
|
||||
try {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
for (String brokerName : changeToBrokerNameSet(clusterInfo.getClusterAddrTable(),
|
||||
topicCreateOrUpdateRequest.getClusterNameList(), topicCreateOrUpdateRequest.getBrokerNameList())) {
|
||||
topicCreateOrUpdateRequest.getClusterNameList(), topicCreateOrUpdateRequest.getBrokerNameList())) {
|
||||
mqAdminExt.createAndUpdateTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topicConfig);
|
||||
}
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +194,11 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
ClusterInfo clusterInfo = null;
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
return mqAdminExt.examineTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return mqAdminExt.examineTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topic);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,6 +210,11 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
TopicConfig topicConfig = examineTopicConfig(topic, brokerData.getBrokerName());
|
||||
BeanUtils.copyProperties(topicConfig, topicConfigInfo);
|
||||
topicConfigInfo.setBrokerNameList(Lists.newArrayList(brokerData.getBrokerName()));
|
||||
String messageType = topicConfig.getAttributes().get(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName());
|
||||
if (StringUtils.isBlank(messageType)) {
|
||||
messageType = TopicMessageType.UNSPECIFIED.name();
|
||||
}
|
||||
topicConfigInfo.setMessageType(messageType);
|
||||
topicConfigInfoList.add(topicConfigInfo);
|
||||
}
|
||||
return topicConfigInfoList;
|
||||
@@ -170,7 +235,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
}
|
||||
mqAdminExt.deleteTopicInNameServer(nameServerSet, topic);
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -181,7 +247,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
for (String clusterName : clusterInfo.getClusterAddrTable().keySet()) {
|
||||
deleteTopic(topic, clusterName);
|
||||
@@ -197,11 +264,13 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mqAdminExt.deleteTopicInBroker(Sets.newHashSet(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr()), topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -216,6 +285,12 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
return defaultMQProducer;
|
||||
}
|
||||
|
||||
public TransactionMQProducer buildTransactionMQProducer(String producerGroup, RPCHook rpcHook, boolean traceEnabled) {
|
||||
TransactionMQProducer defaultMQProducer = new TransactionMQProducer(null, producerGroup, rpcHook, traceEnabled, TopicValidator.RMQ_SYS_TRACE_TOPIC);
|
||||
defaultMQProducer.setUseTLS(configure.isUseTLS());
|
||||
return defaultMQProducer;
|
||||
}
|
||||
|
||||
private TopicList getSystemTopicList() {
|
||||
RPCHook rpcHook = null;
|
||||
boolean isEnableAcl = !StringUtils.isEmpty(configure.getAccessKey()) && !StringUtils.isEmpty(configure.getSecretKey());
|
||||
@@ -230,7 +305,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
producer.start();
|
||||
return producer.getDefaultMQProducerImpl().getmQClientFactory().getMQClientAPIImpl().getSystemTopicList(20000L);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
producer.shutdown();
|
||||
}
|
||||
@@ -238,31 +314,61 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
|
||||
@Override
|
||||
public SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest) {
|
||||
DefaultMQProducer producer = null;
|
||||
List<TopicConfigInfo> topicConfigInfos = examineTopicConfig(sendTopicMessageRequest.getTopic());
|
||||
String messageType = topicConfigInfos.get(0).getMessageType();
|
||||
AclClientRPCHook rpcHook = null;
|
||||
if (configure.isACLEnabled()) {
|
||||
rpcHook = new AclClientRPCHook(new SessionCredentials(
|
||||
configure.getAccessKey(),
|
||||
configure.getSecretKey()
|
||||
configure.getAccessKey(),
|
||||
configure.getSecretKey()
|
||||
));
|
||||
}
|
||||
producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
||||
producer.setNamesrvAddr(configure.getNamesrvAddr());
|
||||
try {
|
||||
producer.start();
|
||||
Message msg = new Message(sendTopicMessageRequest.getTopic(),
|
||||
sendTopicMessageRequest.getTag(),
|
||||
sendTopicMessageRequest.getKey(),
|
||||
sendTopicMessageRequest.getMessageBody().getBytes()
|
||||
);
|
||||
return producer.send(msg);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
} finally {
|
||||
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.shutdown();
|
||||
if (TopicMessageType.TRANSACTION.getValue().equals(messageType)) {
|
||||
// transaction message
|
||||
TransactionListener transactionListener = new TransactionListenerImpl();
|
||||
|
||||
TransactionMQProducer producer = buildTransactionMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
||||
producer.setNamesrvAddr(configure.getNamesrvAddr());
|
||||
producer.setTransactionListener(transactionListener);
|
||||
try {
|
||||
producer.start();
|
||||
Message msg = new Message(sendTopicMessageRequest.getTopic(),
|
||||
sendTopicMessageRequest.getTag(),
|
||||
sendTopicMessageRequest.getKey(),
|
||||
sendTopicMessageRequest.getMessageBody().getBytes()
|
||||
);
|
||||
return producer.sendMessageInTransaction(msg, null);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.shutdown();
|
||||
}
|
||||
} else {
|
||||
// no transaction message
|
||||
DefaultMQProducer producer = null;
|
||||
producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
||||
producer.setNamesrvAddr(configure.getNamesrvAddr());
|
||||
try {
|
||||
producer.start();
|
||||
Message msg = new Message(sendTopicMessageRequest.getTopic(),
|
||||
sendTopicMessageRequest.getTag(),
|
||||
sendTopicMessageRequest.getKey(),
|
||||
sendTopicMessageRequest.getMessageBody().getBytes()
|
||||
);
|
||||
return producer.send(msg);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnabled) {
|
||||
@@ -284,4 +390,20 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
static class TransactionListenerImpl implements TransactionListener {
|
||||
private AtomicInteger transactionIndex = new AtomicInteger(0);
|
||||
|
||||
private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.task;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.stats.Stats;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
|
||||
|
||||
@Slf4j
|
||||
public class CollectTaskRunnble implements Runnable {
|
||||
|
||||
private String topic;
|
||||
|
||||
private MQAdminExt mqAdminExt;
|
||||
|
||||
private DashboardCollectService dashboardCollectService;
|
||||
|
||||
public CollectTaskRunnble(String topic, MQAdminExt mqAdminExt,
|
||||
DashboardCollectService dashboardCollectService) {
|
||||
this.topic = topic;
|
||||
this.mqAdminExt = mqAdminExt;
|
||||
this.dashboardCollectService = dashboardCollectService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Date date = new Date();
|
||||
try {
|
||||
TopicRouteData topicRouteData = mqAdminExt.examineTopicRouteInfo(topic);
|
||||
GroupList groupList = mqAdminExt.queryTopicConsumeByWho(topic);
|
||||
double inTPS = 0;
|
||||
long inMsgCntToday = 0;
|
||||
double outTPS = 0;
|
||||
long outMsgCntToday = 0;
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, Stats.TOPIC_PUT_NUMS, topic);
|
||||
inTPS += bsd.getStatsMinute().getTps();
|
||||
inMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
} catch (Exception e) {
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data TOPIC_PUT_NUMS failed, topic [{}]", topic, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (groupList != null && !groupList.getGroupList().isEmpty()) {
|
||||
for (String group : groupList.getGroupList()) {
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
String statsKey = String.format("%s@%s", topic, group);
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, Stats.GROUP_GET_NUMS, statsKey);
|
||||
outTPS += bsd.getStatsMinute().getTps();
|
||||
outMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
} catch (Exception e) {
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data GROUP_GET_NUMS failed, topic [{}], group [{}]", topic, group, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> list;
|
||||
try {
|
||||
list = dashboardCollectService.getTopicMap().get(topic);
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (null == list) {
|
||||
list = Lists.newArrayList();
|
||||
}
|
||||
|
||||
list.add(date.getTime() + "," + new BigDecimal(inTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + inMsgCntToday + "," + new BigDecimal(outTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + outMsgCntToday);
|
||||
dashboardCollectService.getTopicMap().put(topic, list);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to collect topic: {} data", topic, e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,17 +16,6 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.task;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.store.stats.BrokerStatsManager;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -42,13 +31,18 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -67,14 +61,14 @@ public class DashboardCollectTask {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(DashboardCollectTask.class);
|
||||
|
||||
@Resource
|
||||
private ExecutorService collectExecutor;
|
||||
|
||||
@Scheduled(cron = "30 0/1 * * * ?")
|
||||
public void collectTopic() {
|
||||
if (!rmqConfigure.isEnableDashBoardCollect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
Stopwatch stopwatch = Stopwatch.createUnstarted();
|
||||
try {
|
||||
TopicList topicList = mqAdminExt.fetchAllTopicList();
|
||||
Set<String> topicSet = topicList.getTopicList();
|
||||
@@ -85,80 +79,13 @@ public class DashboardCollectTask {
|
||||
|| TopicValidator.isSystemTopic(topic)) {
|
||||
continue;
|
||||
}
|
||||
TopicRouteData topicRouteData = mqAdminExt.examineTopicRouteInfo(topic);
|
||||
|
||||
GroupList groupList = mqAdminExt.queryTopicConsumeByWho(topic);
|
||||
|
||||
double inTPS = 0;
|
||||
|
||||
long inMsgCntToday = 0;
|
||||
|
||||
double outTPS = 0;
|
||||
|
||||
long outMsgCntToday = 0;
|
||||
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
stopwatch.start();
|
||||
log.info("start time: {}", stopwatch.toString());
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, BrokerStatsManager.TOPIC_PUT_NUMS, topic);
|
||||
stopwatch.stop();
|
||||
log.info("stop time : {}", stopwatch.toString());
|
||||
|
||||
inTPS += bsd.getStatsMinute().getTps();
|
||||
inMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
}
|
||||
catch (Exception e) {
|
||||
stopwatch.reset();
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data TOPIC_PUT_NUMS failed");
|
||||
log.warn("Response [{}] ", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupList != null && !groupList.getGroupList().isEmpty()) {
|
||||
|
||||
for (String group : groupList.getGroupList()) {
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
String statsKey = String.format("%s@%s", topic, group);
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, BrokerStatsManager.GROUP_GET_NUMS, statsKey);
|
||||
outTPS += bsd.getStatsMinute().getTps();
|
||||
outMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data GROUP_GET_NUMS failed");
|
||||
log.warn("Response [{}] ", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> list;
|
||||
try {
|
||||
list = dashboardCollectService.getTopicMap().get(topic);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
if (null == list) {
|
||||
list = Lists.newArrayList();
|
||||
}
|
||||
|
||||
list.add(date.getTime() + "," + new BigDecimal(inTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + inMsgCntToday + "," + new BigDecimal(outTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + outMsgCntToday);
|
||||
dashboardCollectService.getTopicMap().put(topic, list);
|
||||
|
||||
CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService);
|
||||
collectExecutor.submit(collectTask);
|
||||
}
|
||||
|
||||
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +129,8 @@ public class DashboardCollectTask {
|
||||
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,10 +146,12 @@ public class DashboardCollectTask {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException e1) {
|
||||
throw Throwables.propagate(e1);
|
||||
Throwables.throwIfUnchecked(e1);
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
fetchBrokerRuntimeStats(brokerAddr, retryTime - 1);
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +201,8 @@ public class DashboardCollectTask {
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,10 +255,11 @@ public class DashboardCollectTask {
|
||||
|
||||
private void addSystemTopic() throws Exception {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
HashMap<String, Set<String>> clusterTable = clusterInfo.getClusterAddrTable();
|
||||
Map<String, Set<String>> clusterTable = clusterInfo.getClusterAddrTable();
|
||||
for (Map.Entry<String, Set<String>> entry : clusterTable.entrySet()) {
|
||||
String clusterName = entry.getKey();
|
||||
TopicValidator.addSystemTopic(clusterName);
|
||||
TopicValidator.addSystemTopic(MixAll.getReplyTopic(clusterName));
|
||||
Set<String> brokerNames = entry.getValue();
|
||||
for (String brokerName : brokerNames) {
|
||||
TopicValidator.addSystemTopic(brokerName);
|
||||
|
@@ -40,7 +40,7 @@ public class MonitorTask {
|
||||
// @Scheduled(cron = "* * * * * ?")
|
||||
public void scanProblemConsumeGroup() {
|
||||
for (Map.Entry<String, ConsumerMonitorConfig> configEntry : monitorService.queryConsumerMonitorConfig().entrySet()) {
|
||||
GroupConsumeInfo consumeInfo = consumerService.queryGroup(configEntry.getKey());
|
||||
GroupConsumeInfo consumeInfo = consumerService.queryGroup(configEntry.getKey(), null);
|
||||
if (consumeInfo.getCount() < configEntry.getValue().getMinCount() || consumeInfo.getDiffTotal() > configEntry.getValue().getMaxDiffTotal()) {
|
||||
logger.info("op=look consumeInfo {}", JsonUtil.obj2String(consumeInfo)); // notify the alert system
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
server.address=0.0.0.0
|
||||
server.port=8080
|
||||
|
||||
### SSL setting
|
||||
#server.ssl.key-store=classpath:rmqcngkeystore.jks
|
||||
#server.ssl.key-store-password=rocketmq
|
||||
#server.ssl.keyStoreType=PKCS12
|
||||
#server.ssl.keyAlias=rmqcngkey
|
||||
|
||||
#spring.application.index=true
|
||||
spring.application.name=rocketmq-dashboard
|
||||
spring.http.encoding.charset=UTF-8
|
||||
spring.http.encoding.enabled=true
|
||||
spring.http.encoding.force=true
|
||||
logging.level.root=INFO
|
||||
logging.config=classpath:logback.xml
|
||||
#if this value is empty,use env value rocketmq.config.namesrvAddr NAMESRV_ADDR | now, you can set it in ops page.default localhost:9876
|
||||
rocketmq.config.namesrvAddr=
|
||||
#if you use rocketmq version < 3.5.8, rocketmq.config.isVIPChannel should be false.default true
|
||||
rocketmq.config.isVIPChannel=
|
||||
#timeout for mqadminExt, default 5000ms
|
||||
rocketmq.config.timeoutMillis=
|
||||
#rocketmq-console's data path:dashboard/monitor
|
||||
rocketmq.config.dataPath=/tmp/rocketmq-console/data
|
||||
#set it false if you don't want use dashboard.default true
|
||||
rocketmq.config.enableDashBoardCollect=true
|
||||
#set the message track trace topic if you don't want use the default one
|
||||
rocketmq.config.msgTrackTopicName=
|
||||
rocketmq.config.ticketKey=ticket
|
||||
|
||||
#Must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||
rocketmq.config.loginRequired=false
|
||||
|
||||
#set the accessKey and secretKey if you used acl
|
||||
#rocketmq.config.accessKey=
|
||||
#rocketmq.config.secretKey=
|
||||
rocketmq.config.useTLS=false
|
74
src/main/resources/application.yml
Normal file
74
src/main/resources/application.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
servlet:
|
||||
encoding:
|
||||
charset: UTF-8
|
||||
enabled: true
|
||||
force: true
|
||||
## SSL setting
|
||||
# ssl:
|
||||
# key-store: classpath:rmqcngkeystore.jks
|
||||
# key-store-password: rocketmq
|
||||
# key-store-type: PKCS12
|
||||
# key-alias: rmqcngkey
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: rocketmq-dashboard
|
||||
|
||||
logging:
|
||||
config: classpath:logback.xml
|
||||
|
||||
rocketmq:
|
||||
config:
|
||||
# if this value is empty,use env value rocketmq.config.namesrvAddr NAMESRV_ADDR | now, default localhost:9876
|
||||
# configure multiple namesrv addresses to manage multiple different clusters
|
||||
namesrvAddrs:
|
||||
- 127.0.0.1:9876
|
||||
# - 127.0.0.2:9876
|
||||
# - 10.151.47.32:9876;10.151.47.33:9876;10.151.47.34:9876
|
||||
# - 10.151.47.30:9876
|
||||
# if you use rocketmq version < 3.5.8, rocketmq.config.isVIPChannel should be false.default true
|
||||
isVIPChannel:
|
||||
# timeout for mqadminExt, default 5000ms
|
||||
timeoutMillis:
|
||||
# rocketmq-console's data path:dashboard/monitor
|
||||
dataPath: /tmp/rocketmq-console/data
|
||||
# set it false if you don't want use dashboard.default true
|
||||
enableDashBoardCollect: true
|
||||
# set the message track trace topic if you don't want use the default one
|
||||
msgTrackTopicName:
|
||||
ticketKey: ticket
|
||||
# must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||
loginRequired: false
|
||||
useTLS: false
|
||||
proxyAddr: 127.0.0.1:8080
|
||||
proxyAddrs:
|
||||
- 127.0.0.1:8080
|
||||
# set the accessKey and secretKey if you used acl
|
||||
# accessKey: rocketmq2
|
||||
# secretKey: 12345678
|
||||
|
||||
threadpool:
|
||||
config:
|
||||
coreSize: 10
|
||||
maxSize: 10
|
||||
keepAliveTime: 3000
|
||||
queueSize: 5000
|
@@ -19,16 +19,16 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder charset="UTF-8">
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %5p %m%n</pattern>
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${user.home}/logs/consolelogs/rocketmq-console.log</file>
|
||||
<file>${user.home}/logs/dashboardlogs/rocketmq-dashboard.log</file>
|
||||
<append>true</append>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${user.home}/logs/consolelogs/rocketmq-console-%d{yyyy-MM-dd}.%i.log
|
||||
<fileNamePattern>${user.home}/logs/dashboardlogs/rocketmq-dashboard-%d{yyyy-MM-dd}.%i.log
|
||||
</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
@@ -37,7 +37,7 @@
|
||||
<MaxHistory>10</MaxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %5p %m%n</pattern>
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
|
||||
<charset class="java.nio.charset.Charset">UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
@@ -23,13 +23,18 @@
|
||||
|
||||
rolePerms:
|
||||
ordinary:
|
||||
- /rocketmq/nsaddr
|
||||
- /ops/*
|
||||
- /dashboard/**
|
||||
- /rocketmq/*.query
|
||||
- /ops/*.query
|
||||
- /dashboard/*.query
|
||||
- /topic/*.query
|
||||
- /topic/sendTopicMessage.do
|
||||
- /producer/*.query
|
||||
- /message/*
|
||||
- /messageTrace/*
|
||||
- /monitor/*
|
||||
|
||||
- /message/*.query
|
||||
- /messageTrace/*.query
|
||||
- /monitor/*.query
|
||||
- /consumer/*.query
|
||||
- /cluster/*.query
|
||||
- /dlqMessage/*.query
|
||||
- /dlqMessage/exportDlqMessage.do
|
||||
- /dlqMessage/batchResendDlqMessage.do
|
||||
- /acl/*.query
|
||||
|
@@ -104,6 +104,7 @@
|
||||
<script type="text/javascript" src="src/tools/tools.js?v=201703171710"></script>
|
||||
<script type="text/javascript" src="src/cluster.js?timestamp=4"></script>
|
||||
<script type="text/javascript" src="src/topic.js"></script>
|
||||
<script type="text/javascript" src="src/proxy.js"></script>
|
||||
<script type="text/javascript" src="src/consumer.js?timestamp=6"></script>
|
||||
<script type="text/javascript" src="src/producer.js"></script>
|
||||
<script type="text/javascript" src="src/message.js"></script>
|
||||
@@ -113,5 +114,6 @@
|
||||
<script type="text/javascript" src="src/remoteApi/remoteApi.js"></script>
|
||||
<script type="text/javascript" src="vendor/preLoading/main.js"></script>
|
||||
<script type="text/javascript" src="src/login.js"></script>
|
||||
<script type="text/javascript" src="src/acl.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
540
src/main/resources/static/src/acl.js
Normal file
540
src/main/resources/static/src/acl.js
Normal file
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var module = app;
|
||||
|
||||
module.controller('aclController', ['$scope', 'ngDialog', '$http', 'Notification', '$window', function ($scope, ngDialog, $http, Notification, $window) {
|
||||
$scope.paginationConf = {
|
||||
currentPage: 1,
|
||||
totalItems: 0,
|
||||
itemsPerPage: 10,
|
||||
pagesLength: 15,
|
||||
perPageOptions: [10],
|
||||
rememberPerPage: 'perPageItems',
|
||||
onChange: function () {
|
||||
$scope.showPlainAccessConfigs(this.currentPage, this.totalItems);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.plainAccessConfigs = [];
|
||||
$scope.allPlainAccessConfigs = [];
|
||||
$scope.globalWhiteAddrs = [];
|
||||
$scope.allGlobalWhiteAddrs = [];
|
||||
$scope.userRole = $window.sessionStorage.getItem("userrole");
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.showSecretKeyType = {};
|
||||
|
||||
$scope.refreshPlainAccessConfigs = function () {
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "acl/config.query",
|
||||
params: {}
|
||||
}).success(function (resp) {
|
||||
|
||||
// globalWhiteAddrs
|
||||
// plainAccessConfigs
|
||||
if (resp.status == 0) {
|
||||
$scope.allPlainAccessConfigs = resp.data.plainAccessConfigs;
|
||||
$scope.allGlobalWhiteAddrs = resp.data.globalWhiteAddrs;
|
||||
$scope.showSecretKeyType = {};
|
||||
$scope.allPlainAccessConfigs.forEach(e => $scope.showSecretKeyType[e.accessKey] = {
|
||||
type: 'password',
|
||||
action: 'SHOW'
|
||||
});
|
||||
$scope.showPlainAccessConfigs(1, $scope.allPlainAccessConfigs.length);
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
$scope.filterStr = "";
|
||||
$scope.$watch('filterStr', function () {
|
||||
$scope.paginationConf.currentPage = 1;
|
||||
$scope.filterList(1);
|
||||
});
|
||||
|
||||
$scope.filterList = function (currentPage) {
|
||||
var lowExceptStr = $scope.filterStr.toLowerCase();
|
||||
var canShowList = [];
|
||||
|
||||
$scope.allPlainAccessConfigs.forEach(function (element) {
|
||||
if (element.accessKey.toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push(element);
|
||||
}
|
||||
});
|
||||
$scope.paginationConf.totalItems = canShowList.length;
|
||||
var perPage = $scope.paginationConf.itemsPerPage;
|
||||
var from = (currentPage - 1) * perPage;
|
||||
var to = (from + perPage) > canShowList.length ? canShowList.length : from + perPage;
|
||||
$scope.plainAccessConfigs = canShowList.slice(from, to);
|
||||
};
|
||||
|
||||
$scope.showPlainAccessConfigs = function (currentPage, totalItem) {
|
||||
var perPage = $scope.paginationConf.itemsPerPage;
|
||||
var from = (currentPage - 1) * perPage;
|
||||
var to = (from + perPage) > totalItem ? totalItem : from + perPage;
|
||||
$scope.plainAccessConfigs = $scope.allPlainAccessConfigs.slice(from, to);
|
||||
$scope.paginationConf.totalItems = totalItem;
|
||||
$scope.filterList($scope.paginationConf.currentPage)
|
||||
};
|
||||
|
||||
|
||||
// add acl account
|
||||
$scope.openAddDialog = function () {
|
||||
var request = {};
|
||||
request.accessKey = '';
|
||||
request.secretKey = '';
|
||||
request.admin = false;
|
||||
request.defaultTopicPerm = 'DENY';
|
||||
request.defaultGroupPerm = 'SUB';
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addAclAccountDialog',
|
||||
controller: 'addAclAccountDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteAclConfig = function (accessKey) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/delete.do",
|
||||
data: {accessKey: accessKey}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.openUpdateDialog = function (request) {
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'updateAclAccountDialog',
|
||||
controller: 'updateAclAccountDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// add acl topic permission
|
||||
$scope.openAddTopicDialog = function (request) {
|
||||
$.extend(request, {pub: true, sub: true, deny: false})
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addAclTopicDialog',
|
||||
controller: 'addAclTopicDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// update acl topic permission
|
||||
$scope.openUpdateTopicDialog = function (request, topic) {
|
||||
var perm = {pub: false, sub: false, deny: false};
|
||||
var topicInfo = topic.split('=');
|
||||
$.each(topicInfo[1].split('|'), function (i, e) {
|
||||
switch (e) {
|
||||
case 'PUB':
|
||||
perm.pub = true;
|
||||
break;
|
||||
case 'SUB':
|
||||
perm.sub = true;
|
||||
break;
|
||||
case 'DENY':
|
||||
perm.deny = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(request, perm, {topic: topicInfo[0]});
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'updateAclTopicDialog',
|
||||
controller: 'updateAclTopicDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// add acl group permission
|
||||
$scope.openAddGroupDialog = function (request) {
|
||||
$.extend(request, {pub: true, sub: true, deny: false})
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addAclGroupDialog',
|
||||
controller: 'addAclGroupDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// update acl group permission
|
||||
$scope.openUpdateGroupDialog = function (request, group) {
|
||||
var perm = {pub: false, sub: false, deny: false};
|
||||
var groupInfo = group.split('=');
|
||||
$.each(groupInfo[1].split('|'), function (i, e) {
|
||||
switch (e) {
|
||||
case 'PUB':
|
||||
perm.pub = true;
|
||||
break;
|
||||
case 'SUB':
|
||||
perm.sub = true;
|
||||
break;
|
||||
case 'DENY':
|
||||
perm.deny = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(request, perm, {group: groupInfo[0]});
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'updateAclGroupDialog',
|
||||
controller: 'updateAclGroupDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deletePermConfig = function (config, name, type) {
|
||||
var request = {config: config};
|
||||
switch (type) {
|
||||
case 'topic':
|
||||
request.topicPerm = name;
|
||||
break;
|
||||
case 'group':
|
||||
request.groupPerm = name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/perm/delete.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.synchronizeData = function (request) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/sync.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.openAddAddrDialog = function () {
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addWhiteListDialog',
|
||||
controller: 'addWhiteListDialogController'
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteGlobalWhiteAddr = function (request) {
|
||||
$http({
|
||||
method: "DELETE",
|
||||
url: "acl/white/list/delete.do?request=" + request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.synchronizeWhiteList = function (request) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/white/list/sync.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.switchSecretKeyType = function (accessKey) {
|
||||
if ($scope.showSecretKeyType[accessKey].type == 'password') {
|
||||
$scope.showSecretKeyType[accessKey] = {type: 'text', action: 'HIDE'};
|
||||
} else {
|
||||
$scope.showSecretKeyType[accessKey] = {type: 'password', action: 'SHOW'};
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
module.controller('addAclAccountDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.addRequest = function (requestItem) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/add.do",
|
||||
data: requestItem
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('updateAclAccountDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/update.do",
|
||||
data: requestItem
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('addAclTopicDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
if (!requestItem.topic) {
|
||||
alert("topic is null");
|
||||
return false;
|
||||
}
|
||||
//var request = requestItem.originalData;
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.topicPerms) {
|
||||
originalData.topicPerms = new Array();
|
||||
}
|
||||
var topicPerm = concatPerm(requestItem.topic, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
originalData.topicPerms.push(topicPerm);
|
||||
var request = {topicPerm: topicPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/topic/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('updateAclTopicDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.topicPerms) {
|
||||
originalData.topicPerms = new Array();
|
||||
}
|
||||
var topicPerm = concatPerm(requestItem.topic, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
|
||||
for (var i = 0; i < originalData.topicPerms.length; i++) {
|
||||
if (originalData.topicPerms[i].split('=')[0] == requestItem.topic) {
|
||||
originalData.topicPerms[i] = topicPerm;
|
||||
}
|
||||
}
|
||||
var request = {topicPerm: topicPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/topic/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('addAclGroupDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
//var request = requestItem.originalData;
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.groupPerms) {
|
||||
originalData.groupPerms = new Array();
|
||||
}
|
||||
var groupPerm = concatPerm(requestItem.group, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
originalData.groupPerms.push(groupPerm);
|
||||
var request = {groupPerm: groupPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/group/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('updateAclGroupDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.groupPerms) {
|
||||
originalData.groupPerms = new Array();
|
||||
}
|
||||
var groupPerm = concatPerm(requestItem.group, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
|
||||
for (var i = 0; i < originalData.groupPerms.length; i++) {
|
||||
if (originalData.groupPerms[i].split('=')[0] == requestItem.group) {
|
||||
originalData.groupPerms[i] = groupPerm;
|
||||
}
|
||||
}
|
||||
var request = {groupPerm: groupPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/group/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* pub: 0x01, sub: 0x02, deny: 0x04
|
||||
*/
|
||||
function concatPerm(name, pub, sub, deny) {
|
||||
var perm = '';
|
||||
|
||||
switch (pub | sub | deny) {
|
||||
case 0x01:
|
||||
perm = 'PUB';
|
||||
break;
|
||||
case 0x02:
|
||||
perm = 'SUB';
|
||||
break;
|
||||
case 0x03:
|
||||
perm = 'PUB|SUB';
|
||||
break;
|
||||
case 0x04:
|
||||
perm = 'DENY';
|
||||
break;
|
||||
default:
|
||||
perm = 'DENY';
|
||||
break;
|
||||
}
|
||||
|
||||
return name + '=' + perm;
|
||||
}
|
||||
|
||||
module.controller('addWhiteListDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.addWhiteListRequest = function (requestItem) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/white/list/add.do",
|
||||
data: requestItem.split(',')
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('aclBelongItemDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.postBelongItemRequest = function (topicRequestItem) {
|
||||
topicRequestItem.type = 1
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/belong/item/add.do",
|
||||
data: topicRequestItem
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
@@ -49,6 +49,15 @@ var app = angular.module('app', [
|
||||
}
|
||||
console.log('initFlag0='+ initFlag + ' loginFlag0==='+loginFlag);
|
||||
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "acl/enable.query"
|
||||
}).success(function (resp) {
|
||||
if (resp && resp.status == 0) {
|
||||
$rootScope.show = resp.data;
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('$locationChangeStart', function (event, next, current) {
|
||||
// redirect to login page if not logged in and trying to access a restricted page
|
||||
init(function(resp){
|
||||
@@ -204,6 +213,12 @@ app.config(['$routeProvider', '$httpProvider','$cookiesProvider','getDictNamePro
|
||||
}).when('/ops', {
|
||||
templateUrl: 'view/pages/ops.html',
|
||||
controller:'opsController'
|
||||
}).when('/proxy', {
|
||||
templateUrl: 'view/pages/proxy.html',
|
||||
controller:'proxyController'
|
||||
}).when('/acl', {
|
||||
templateUrl: 'view/pages/acl.html',
|
||||
controller: 'aclController'
|
||||
}).when('/404', {
|
||||
templateUrl: 'view/pages/404.html'
|
||||
}).otherwise('/404');
|
||||
|
@@ -45,6 +45,7 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.filterNormal = true;
|
||||
$scope.filterSystem = false;
|
||||
$scope.filterFIFO = false;
|
||||
|
||||
$scope.doSort = function () {// todo how to change this fe's code ? (it's dirty)
|
||||
if ($scope.sortKey == 'diffTotal') {
|
||||
@@ -75,7 +76,11 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "consumer/groupList.query"
|
||||
url: "consumer/groupList.query",
|
||||
params: {
|
||||
skipSysGroup: false,
|
||||
address: localStorage.getItem('isV5') ? localStorage.getItem('proxyAddr') : null
|
||||
}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
$scope.allConsumerGrouopList = resp.data;
|
||||
@@ -135,16 +140,28 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
$scope.filterList(1);
|
||||
});
|
||||
|
||||
$scope.filterByType = function (str) {
|
||||
$scope.$watch('filterFIFO', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
|
||||
$scope.filterByType = function (str, type,version) {
|
||||
if ($scope.filterSystem) {
|
||||
if (str.startsWith("%S")) {
|
||||
if (type === "SYSTEM") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if ($scope.filterNormal) {
|
||||
if (str.startsWith("%") == false) {
|
||||
if (type === "NORMAL") {
|
||||
return true
|
||||
}
|
||||
if(!version && type === "FIFO"){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($scope.filterFIFO) {
|
||||
if (type === "FIFO") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -154,7 +171,7 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
var canShowList = [];
|
||||
$scope.allConsumerGrouopList.forEach(function (element) {
|
||||
console.log(element)
|
||||
if ($scope.filterByType(element.group)) {
|
||||
if ($scope.filterByType(element.group, element.subGroupType, $scope.rmqVersion)) {
|
||||
if (element.group.toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push(element);
|
||||
}
|
||||
@@ -189,6 +206,7 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
subscriptionGroupConfig: {
|
||||
groupName: "",
|
||||
consumeEnable: true,
|
||||
consumeMessageOrderly: false,
|
||||
consumeFromMinEnable: true,
|
||||
consumeBroadcastEnable: true,
|
||||
retryQueueNums: 1,
|
||||
@@ -211,7 +229,7 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
// Refresh topic list
|
||||
$scope.refreshConsumerData();
|
||||
},
|
||||
template: 'consumerModifyDialog',
|
||||
template: $scope.rmqVersion ? 'consumerModifyDialogForV5' : 'consumerModifyDialog',
|
||||
controller: 'consumerModifyDialogController',
|
||||
data: {
|
||||
consumerRequestList: request,
|
||||
@@ -226,11 +244,11 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
}
|
||||
});
|
||||
};
|
||||
$scope.detail = function (consumerGroupName) {
|
||||
$scope.detail = function (consumerGroupName, address) {
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "consumer/queryTopicByConsumer.query",
|
||||
params: {consumerGroup: consumerGroupName}
|
||||
params: {consumerGroup: consumerGroupName, address: address}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
console.log(resp);
|
||||
@@ -245,11 +263,11 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
|
||||
});
|
||||
};
|
||||
|
||||
$scope.client = function (consumerGroupName) {
|
||||
$scope.client = function (consumerGroupName, address) {
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "consumer/consumerConnection.query",
|
||||
params: {consumerGroup: consumerGroupName}
|
||||
params: {consumerGroup: consumerGroupName, address: address}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
console.log(resp);
|
||||
|
@@ -15,10 +15,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
app.controller('AppCtrl', ['$scope','$window','$translate','$http','Notification', function ($scope,$window,$translate, $http, Notification) {
|
||||
$scope.rmqVersion = localStorage.getItem("isV5");
|
||||
|
||||
$scope.changeTranslate = function(langKey){
|
||||
$translate.use(langKey);
|
||||
}
|
||||
|
||||
$scope.changeRMQVersion = function (version) {
|
||||
$scope.rmqVersion = version === 5;
|
||||
var v = version === 5;
|
||||
localStorage.setItem("isV5", v);
|
||||
}
|
||||
|
||||
$scope.logout = function(){
|
||||
$http({
|
||||
method: "POST",
|
||||
|
@@ -82,6 +82,9 @@ module.controller('dlqMessageController', ['$scope', 'ngDialog', '$http', 'Notif
|
||||
if ($scope.messageShowList.length == 0){
|
||||
$("#noMsgTip").removeAttr("style");
|
||||
}
|
||||
for (const message of $scope.messageShowList) {
|
||||
message.checked = false;
|
||||
}
|
||||
console.log($scope.messageShowList);
|
||||
if (resp.data.page.first) {
|
||||
$scope.paginationConf.currentPage = 1;
|
||||
@@ -180,5 +183,115 @@ module.controller('dlqMessageController', ['$scope', 'ngDialog', '$http', 'Notif
|
||||
|
||||
$scope.exportDlqMessage = function (msgId, consumerGroup) {
|
||||
window.location.href = "dlqMessage/exportDlqMessage.do?msgId=" + msgId + "&consumerGroup=" + consumerGroup;
|
||||
};
|
||||
|
||||
$scope.selectedDlqMessage = [];
|
||||
$scope.batchResendDlqMessage = function (consumerGroup) {
|
||||
if ($("#batchResendBtn").hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
for (const message of $scope.messageCheckedList) {
|
||||
const dlqMessage = {};
|
||||
dlqMessage.topic = message.properties.RETRY_TOPIC;
|
||||
dlqMessage.msgId = message.properties.ORIGIN_MESSAGE_ID;
|
||||
dlqMessage.consumerGroup = consumerGroup;
|
||||
$scope.selectedDlqMessage.push(dlqMessage);
|
||||
}
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "dlqMessage/batchResendDlqMessage.do",
|
||||
data: $scope.selectedDlqMessage
|
||||
}).success(function (resp) {
|
||||
$scope.selectedDlqMessage = [];
|
||||
if (resp.status == 0) {
|
||||
ngDialog.open({
|
||||
template: 'operationResultDialog',
|
||||
data: {
|
||||
result: resp.data
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ngDialog.open({
|
||||
template: 'operationResultDialog',
|
||||
data: {
|
||||
result: resp.errMsg
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.batchExportDlqMessage = function (consumerGroup) {
|
||||
if ($("#batchExportBtn").hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
for (const message of $scope.messageCheckedList) {
|
||||
const dlqMessage = {};
|
||||
dlqMessage.msgId = message.msgId;
|
||||
dlqMessage.consumerGroup = consumerGroup;
|
||||
$scope.selectedDlqMessage.push(dlqMessage);
|
||||
}
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "dlqMessage/batchExportDlqMessage.do",
|
||||
data: $scope.selectedDlqMessage,
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
},
|
||||
responseType: "arraybuffer"
|
||||
}).success(function (resp) {
|
||||
$scope.selectedDlqMessage = [];
|
||||
const blob = new Blob([resp], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.download = 'dlqs.xlsx';
|
||||
a.href = objectUrl;
|
||||
a.click();
|
||||
document.body.removeChild(a)
|
||||
});
|
||||
};
|
||||
|
||||
$scope.checkedAll = false;
|
||||
$scope.messageCheckedList = [];
|
||||
$scope.selectAll = function () {
|
||||
$scope.messageCheckedList = [];
|
||||
if ($scope.checkedAll == true) {
|
||||
angular.forEach($scope.messageShowList, function (item, index) {
|
||||
item.checked = true;
|
||||
$scope.messageCheckedList.push(item);
|
||||
});
|
||||
} else {
|
||||
angular.forEach($scope.messageShowList, function (item, index) {
|
||||
item.checked = false;
|
||||
});
|
||||
}
|
||||
checkBtn($scope.messageCheckedList)
|
||||
console.log($scope.messageCheckedList)
|
||||
}
|
||||
|
||||
$scope.selectItem = function () {
|
||||
var flag = true;
|
||||
$scope.messageCheckedList = [];
|
||||
angular.forEach($scope.messageShowList, function (item, index) {
|
||||
if (item.checked) {
|
||||
$scope.messageCheckedList.push(item);
|
||||
} else {
|
||||
flag = false;
|
||||
}
|
||||
})
|
||||
$scope.checkedAll = flag;
|
||||
checkBtn($scope.messageCheckedList)
|
||||
console.log($scope.messageCheckedList);
|
||||
}
|
||||
|
||||
function checkBtn(messageCheckList) {
|
||||
if (messageCheckList.length == 0) {
|
||||
$("#batchResendBtn").addClass("disabled");
|
||||
$("#batchExportBtn").addClass("disabled");
|
||||
} else {
|
||||
$("#batchResendBtn").removeClass("disabled");
|
||||
$("#batchExportBtn").removeClass("disabled");
|
||||
}
|
||||
}
|
||||
}]);
|
@@ -21,8 +21,8 @@ var en = {
|
||||
"NO": "NO.",
|
||||
"ADDRESS": "Address",
|
||||
"VERSION": "Version",
|
||||
"PRO_MSG_TPS": "Produce Massage TPS",
|
||||
"CUS_MSG_TPS": "Consumer Massage TPS",
|
||||
"PRO_MSG_TPS": "Produce Message TPS",
|
||||
"CUS_MSG_TPS": "Consumer Message TPS",
|
||||
"YESTERDAY_PRO_COUNT": "Yesterday Produce Count",
|
||||
"YESTERDAY_CUS_COUNT": "Yesterday Consume Count",
|
||||
"TODAY_PRO_COUNT": "Today Produce Count",
|
||||
@@ -54,9 +54,13 @@ var en = {
|
||||
"RESET_CUS_OFFSET": "Reset Consumer Offset",
|
||||
"DELETE": "Delete",
|
||||
"CHANGE_LANG": "ChangeLanguage",
|
||||
"CHANGE_VERSION": "ChangeVersion",
|
||||
"BROKER": "Broker",
|
||||
"NORMAL": "NORMAL",
|
||||
"RETRY": "RETRY",
|
||||
"FIFO": "FIFO",
|
||||
"TRANSACTION": "TRANSACTION",
|
||||
"UNSPECIFIED": "UNSPECIFIED",
|
||||
"DLQ": "DLQ",
|
||||
"QUANTITY":"Quantity",
|
||||
"TYPE":"Type",
|
||||
@@ -97,6 +101,7 @@ var en = {
|
||||
"RESET_OFFSET":"resetOffset",
|
||||
"CLUSTER_NAME":"clusterName",
|
||||
"OPS":"OPS",
|
||||
"PROXY":"Proxy",
|
||||
"AUTO_REFRESH":"AUTO_REFRESH",
|
||||
"REFRESH":"REFRESH",
|
||||
"LOGOUT":"Logout",
|
||||
@@ -111,5 +116,23 @@ var en = {
|
||||
"TRACE_TOPIC":"TraceTopic",
|
||||
"SELECT_TRACE_TOPIC":"selectTraceTopic",
|
||||
"EXPORT": "export",
|
||||
"NO_MATCH_RESULT": "no match result"
|
||||
}
|
||||
"NO_MATCH_RESULT": "no match result",
|
||||
"BATCH_RESEND": "batchReSend",
|
||||
"BATCH_EXPORT": "batchExport",
|
||||
"WHITE_LIST":"White List",
|
||||
"ACCOUNT_INFO":"Account Info",
|
||||
"IS_ADMIN":"Is Admin",
|
||||
"DEFAULT_TOPIC_PERM":"Default Topic Permission",
|
||||
"DEFAULT_GROUP_PERM":"Default Group Permission",
|
||||
"TOPIC_PERM":"Topic Permission",
|
||||
"GROUP_PERM":"Group Permission",
|
||||
"SYNCHRONIZE":"Synchronize Data",
|
||||
"SHOW":"Show",
|
||||
"HIDE":"Hide",
|
||||
"MESSAGE_TYPE":"messageType",
|
||||
"MESSAGE_TYPE_UNSPECIFIED": "UNSPECIFIED, is NORMAL",
|
||||
"MESSAGE_TYPE_NORMAL": "NORMAL",
|
||||
"MESSAGE_TYPE_FIFO": "FIFO",
|
||||
"MESSAGE_TYPE_DELAY": "DELAY",
|
||||
"MESSAGE_TYPE_TRANSACTION": "TRANSACTION",
|
||||
}
|
||||
|
@@ -55,9 +55,13 @@ var zh = {
|
||||
"SKIP_MESSAGE_ACCUMULATE":"跳过堆积",
|
||||
"DELETE": "删除",
|
||||
"CHANGE_LANG": "更换语言",
|
||||
"CHANGE_VERSION": "更换版本",
|
||||
"BROKER": "Broker",
|
||||
"NORMAL": "普通",
|
||||
"RETRY": "重试",
|
||||
"FIFO": "顺序",
|
||||
"TRANSACTION": "事务",
|
||||
"UNSPECIFIED": "未指定",
|
||||
"DLQ": "死信",
|
||||
"QUANTITY":"数量",
|
||||
"TYPE":"类型",
|
||||
@@ -98,6 +102,7 @@ var zh = {
|
||||
"RESET_OFFSET":"重置位点",
|
||||
"CLUSTER_NAME":"集群名",
|
||||
"OPS":"运维",
|
||||
"PROXY":"代理",
|
||||
"AUTO_REFRESH":"自动刷新",
|
||||
"REFRESH":"刷新",
|
||||
"LOGOUT":"退出",
|
||||
@@ -112,5 +117,23 @@ var zh = {
|
||||
"TRACE_TOPIC":"消息轨迹主题",
|
||||
"SELECT_TRACE_TOPIC":"选择消息轨迹主题",
|
||||
"EXPORT": "导出",
|
||||
"NO_MATCH_RESULT": "没有查到符合条件的结果"
|
||||
"NO_MATCH_RESULT": "没有查到符合条件的结果",
|
||||
"BATCH_RESEND": "批量重发",
|
||||
"BATCH_EXPORT": "批量导出",
|
||||
"WHITE_LIST":"白名单",
|
||||
"ACCOUNT_INFO":"账户信息",
|
||||
"IS_ADMIN":"是否管理员",
|
||||
"DEFAULT_TOPIC_PERM":"topic默认权限",
|
||||
"DEFAULT_GROUP_PERM":"消费组默认权限",
|
||||
"TOPIC_PERM":"topic权限",
|
||||
"GROUP_PERM":"消费组权限",
|
||||
"SYNCHRONIZE":"同步",
|
||||
"SHOW":"显示",
|
||||
"HIDE":"隐藏",
|
||||
"MESSAGE_TYPE":"消息类型",
|
||||
"MESSAGE_TYPE_UNSPECIFIED": "未指定,为普通消息",
|
||||
"MESSAGE_TYPE_NORMAL": "普通消息",
|
||||
"MESSAGE_TYPE_FIFO": "顺序消息",
|
||||
"MESSAGE_TYPE_DELAY": "定时/延时消息",
|
||||
"MESSAGE_TYPE_TRANSACTION": "事务消息",
|
||||
}
|
@@ -58,6 +58,7 @@ module.controller('messageController', ['$scope', 'ngDialog', '$http', 'Notifica
|
||||
};
|
||||
|
||||
$scope.queryMessagePageByTopic = function () {
|
||||
$("#noMsgTip").css("display", "none");
|
||||
if ($scope.timepickerEnd < $scope.timepickerBegin) {
|
||||
Notification.error({message: "endTime is later than beginTime!", delay: 2000});
|
||||
return
|
||||
@@ -80,6 +81,9 @@ module.controller('messageController', ['$scope', 'ngDialog', '$http', 'Notifica
|
||||
if (resp.status === 0) {
|
||||
console.log(resp);
|
||||
$scope.messageShowList = resp.data.page.content;
|
||||
if ($scope.messageShowList.length == 0){
|
||||
$("#noMsgTip").removeAttr("style");
|
||||
}
|
||||
if (resp.data.page.first) {
|
||||
$scope.paginationConf.currentPage = 1;
|
||||
}
|
||||
@@ -206,7 +210,8 @@ module.controller('messageController', ['$scope', 'ngDialog', '$http', 'Notifica
|
||||
}]);
|
||||
|
||||
module.controller('messageDetailViewDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
|
||||
$scope.messageTrackList = $scope.ngDialogData.messageTrackList;
|
||||
$scope.messageTrackShowList = $scope.ngDialogData.messageTrackList;
|
||||
$scope.resendMessage = function (messageView, consumerGroup) {
|
||||
var topic = messageView.topic;
|
||||
var msgId = messageView.msgId;
|
||||
@@ -258,5 +263,18 @@ module.controller('messageDetailViewDialogController', ['$scope', 'ngDialog', '$
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.filterConsumerGroup = "";
|
||||
$scope.$watch('filterConsumerGroup', function () {
|
||||
const lowExceptStr = $scope.filterConsumerGroup.toLowerCase();
|
||||
const canShowList = [];
|
||||
|
||||
$scope.messageTrackList.forEach(function (element) {
|
||||
if (element.consumerGroup.toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push(element);
|
||||
}
|
||||
});
|
||||
$scope.messageTrackShowList = canShowList;
|
||||
});
|
||||
}]
|
||||
);
|
@@ -22,6 +22,7 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
$scope.userRole = $window.sessionStorage.getItem("userrole");
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.inputReadonly = !$scope.writeOperationEnabled;
|
||||
$scope.newNamesrvAddr = "";
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "ops/homePage.query"
|
||||
@@ -30,6 +31,7 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
$scope.namesvrAddrList = resp.data.namesvrAddrList;
|
||||
$scope.useVIPChannel = resp.data.useVIPChannel;
|
||||
$scope.useTLS = resp.data.useTLS;
|
||||
$scope.selectedNamesrv = resp.data.currentNamesrv;
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
@@ -43,7 +45,7 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "ops/updateNameSvrAddr.do",
|
||||
params: {nameSvrAddrList: $scope.namesvrAddrList.join(";")}
|
||||
params: {nameSvrAddrList: $scope.selectedNamesrv}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "SUCCESS", delay: 2000});
|
||||
@@ -52,6 +54,26 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addNameSvrAddr = function () {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "ops/addNameSvrAddr.do",
|
||||
params: {newNamesrvAddr: $scope.newNamesrvAddr}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
if ($scope.namesvrAddrList.indexOf($scope.newNamesrvAddr) == -1) {
|
||||
$scope.namesvrAddrList.push($scope.newNamesrvAddr);
|
||||
}
|
||||
$("#namesrvAddr").val("");
|
||||
$scope.newNamesrvAddr = "";
|
||||
Notification.info({message: "SUCCESS", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateIsVIPChannel = function () {
|
||||
$http({
|
||||
method: "POST",
|
||||
|
97
src/main/resources/static/src/proxy.js
Normal file
97
src/main/resources/static/src/proxy.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
var module = app;
|
||||
module.controller('proxyController', ['$scope', '$location', '$http', 'Notification', 'remoteApi', 'tools', '$window',
|
||||
function ($scope, $location, $http, Notification, remoteApi, tools, $window) {
|
||||
$scope.proxyAddrList = [];
|
||||
$scope.userRole = $window.sessionStorage.getItem("userrole");
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.inputReadonly = !$scope.writeOperationEnabled;
|
||||
$scope.newProxyAddr = "";
|
||||
$scope.allProxyConfig = {};
|
||||
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "proxy/homePage.query"
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
$scope.proxyAddrList = resp.data.proxyAddrList;
|
||||
$scope.selectedProxy = resp.data.currentProxyAddr;
|
||||
$scope.showProxyDetailConfig($scope.selectedProxy);
|
||||
localStorage.setItem('proxyAddr',$scope.selectedProxy);
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
|
||||
$scope.eleChange = function (data) {
|
||||
$scope.proxyAddrList = data;
|
||||
}
|
||||
$scope.showDetailConf = function () {
|
||||
$(".proxyModal").modal();
|
||||
}
|
||||
|
||||
|
||||
$scope.showProxyDetailConfig = function (proxyAddr) {
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "proxy/proxyDetailConfig.query",
|
||||
params: {proxyAddress: proxyAddr}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
$scope.allProxyConfig = resp.data;
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateProxyAddr = function () {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "proxy/updateProxyAddr.do",
|
||||
params: {proxyAddr: $scope.selectedProxy}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
localStorage.setItem('proxyAddr', $scope.selectedProxy);
|
||||
Notification.info({message: "SUCCESS", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
$scope.showProxyDetailConfig($scope.selectedProxy);
|
||||
};
|
||||
|
||||
$scope.addProxyAddr = function () {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "proxy/addProxyAddr.do",
|
||||
params: {newProxyAddr: $scope.newProxyAddr}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
if ($scope.proxyAddrList.indexOf($scope.newProxyAddr) == -1) {
|
||||
$scope.proxyAddrList.push($scope.newProxyAddr);
|
||||
}
|
||||
$("#proxyAddr").val("");
|
||||
$scope.newProxyAddr = "";
|
||||
Notification.info({message: "SUCCESS", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
};
|
||||
}])
|
@@ -54,7 +54,7 @@ app.service('remoteApi', ['$http','tools', function ($http,tools) {
|
||||
}
|
||||
|
||||
var queryTopicCurrentData = function(callback){
|
||||
var url = 'dashboard/topicCurrent';
|
||||
var url = 'dashboard/topicCurrent.query';
|
||||
var setting = {
|
||||
type: "GET",
|
||||
timeout:15000,//data is too large,so master set time out is long enough
|
||||
|
@@ -45,24 +45,31 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
}
|
||||
};
|
||||
$scope.filterNormal = true
|
||||
$scope.filterDelay = false
|
||||
$scope.filterFifo = false
|
||||
$scope.filterTransaction = false
|
||||
$scope.filterUnspecified = false
|
||||
$scope.filterRetry = false
|
||||
$scope.filterDLQ = false
|
||||
$scope.filterSystem = false
|
||||
$scope.allTopicList = [];
|
||||
$scope.allTopicNameList = [];
|
||||
$scope.allMessageTypeList = [];
|
||||
$scope.topicShowList = [];
|
||||
$scope.userRole = $window.sessionStorage.getItem("userrole");
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
|
||||
$scope.refreshTopicList = function () {
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "topic/list.query"
|
||||
url: "topic/list.queryTopicType"
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
$scope.allTopicList = resp.data.topicList.sort();
|
||||
console.log($scope.allTopicList);
|
||||
$scope.allTopicNameList = resp.data.topicNameList;
|
||||
$scope.allMessageTypeList = resp.data.messageTypeList;
|
||||
console.log($scope.allTopicNameList);
|
||||
console.log(JSON.stringify(resp));
|
||||
$scope.showTopicList(1, $scope.allTopicList.length);
|
||||
$scope.showTopicList(1, $scope.allTopicNameList.length);
|
||||
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 5000});
|
||||
@@ -79,6 +86,18 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
$scope.$watch('filterNormal', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
$scope.$watch('filterFifo', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
$scope.$watch('filterTransaction', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
$scope.$watch('filterUnspecified', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
$scope.$watch('filterDelay', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
$scope.$watch('filterRetry', function () {
|
||||
$scope.filterList(1);
|
||||
});
|
||||
@@ -92,13 +111,13 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
var lowExceptStr = $scope.filterStr.toLowerCase();
|
||||
var canShowList = [];
|
||||
|
||||
$scope.allTopicList.forEach(function (element) {
|
||||
if ($scope.filterByType(element)) {
|
||||
if (element.toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push(element);
|
||||
for (let i = 0; i < $scope.allTopicNameList.length; ++i) {
|
||||
if ($scope.filterByType($scope.allTopicNameList[i], $scope.allMessageTypeList[i])) {
|
||||
if ($scope.allTopicNameList[i].toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push($scope.allTopicNameList[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.paginationConf.totalItems = canShowList.length;
|
||||
var perPage = $scope.paginationConf.itemsPerPage;
|
||||
var from = (currentPage - 1) * perPage;
|
||||
@@ -106,7 +125,7 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
$scope.topicShowList = canShowList.slice(from, to);
|
||||
};
|
||||
|
||||
$scope.filterByType = function (str) {
|
||||
$scope.filterByType = function (str, type) {
|
||||
if ($scope.filterRetry) {
|
||||
if (str.startsWith("%R")) {
|
||||
return true
|
||||
@@ -122,8 +141,31 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('isV5') && $scope.filterUnspecified) {
|
||||
if (type.includes("UNSPECIFIED")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if ($scope.filterNormal) {
|
||||
if (str.startsWith("%") == false) {
|
||||
if (type.includes("NORMAL")) {
|
||||
return true
|
||||
}
|
||||
if (!localStorage.getItem('isV5') && type.includes("UNSPECIFIED")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('isV5') && $scope.filterDelay) {
|
||||
if (type.includes("DELAY")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('isV5') && $scope.filterFifo) {
|
||||
if (type.includes("FIFO")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('isV5') && $scope.filterTransaction) {
|
||||
if (type.includes("TRANSACTION")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -138,10 +180,10 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
var perPage = $scope.paginationConf.itemsPerPage;
|
||||
var from = (currentPage - 1) * perPage;
|
||||
var to = (from + perPage) > totalItem ? totalItem : from + perPage;
|
||||
console.log($scope.allTopicList);
|
||||
console.log($scope.allTopicNameList);
|
||||
console.log(from)
|
||||
console.log(to)
|
||||
$scope.topicShowList = $scope.allTopicList.slice(from, to);
|
||||
$scope.topicShowList = $scope.allTopicNameList.slice(from, to);
|
||||
$scope.paginationConf.totalItems = totalItem;
|
||||
console.log($scope.topicShowList)
|
||||
console.log($scope.paginationConf.totalItems)
|
||||
@@ -328,8 +370,8 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
var bIsUpdate = true;
|
||||
if (request == null) {
|
||||
request = [{
|
||||
writeQueueNums: 16,
|
||||
readQueueNums: 16,
|
||||
writeQueueNums: 8,
|
||||
readQueueNums: 8,
|
||||
perm: 6,
|
||||
order: false,
|
||||
topicName: "",
|
||||
@@ -355,6 +397,7 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
|
||||
topicRequestList: request,
|
||||
allClusterNameList: Object.keys(resp.data.clusterInfo.clusterAddrTable),
|
||||
allBrokerNameList: Object.keys(resp.data.brokerServer),
|
||||
allMessageTypeList: resp.data.messageTypes,
|
||||
bIsUpdate: bIsUpdate,
|
||||
writeOperationEnabled: $scope.writeOperationEnabled
|
||||
}
|
||||
|
@@ -289,3 +289,15 @@
|
||||
.table.text-middle>tbody>tr>td,.table.text-middle>tbody>tr>th{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.perm-table{width: 100%;}
|
||||
.perm-table .perm-tg{width: 70%;}
|
||||
.perm-table .center{border-left: 1px solid #e4dddd; border-right: 1px solid #e4dddd;}
|
||||
|
||||
.input-none {
|
||||
border: 0;
|
||||
outline: none;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
cursor: text !important;
|
||||
width: 60%;
|
||||
}
|
@@ -28,6 +28,7 @@
|
||||
<div class="navbar-collapse collapse navbar-warning-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ng-class="path =='ops' ? 'active':''"><a ng-href="#/ops">{{'OPS' | translate}}</a></li>
|
||||
<li ng-show="rmqVersion" ng-class="path =='proxy' ? 'active':''"><a ng-href="#/proxy">{{'PROXY' | translate}}</a></li>
|
||||
<li ng-class="path =='dashboard' || path ==''? 'active':''"><a ng-href="#/">{{'DASHBOARD' | translate}}</a></li>
|
||||
<li ng-class="path =='cluster' ? 'active':''"><a ng-href="#/cluster">{{'CLUSTER' | translate}}</a></li>
|
||||
<li ng-class="path =='topic' ? 'active':''"><a ng-href="#/topic">{{'TOPIC' | translate}}</a></li>
|
||||
@@ -36,6 +37,7 @@
|
||||
<li ng-class="path =='message' ? 'active':''"><a ng-href="#/message">{{'MESSAGE' | translate}}</a></li>
|
||||
<li ng-class="path =='dlqMessage' ? 'active':''"><a ng-href="#/dlqMessage">{{'DLQ_MESSAGE' | translate}}</a></li>
|
||||
<li ng-class="path =='messageTrace' ? 'active':''"><a ng-href="#/messageTrace">{{'MESSAGETRACE' | translate}}</a></li>
|
||||
<li ng-show="{{ show }}" ng-class="path =='acl' ? 'active':''"><a ng-href="#/acl">Acl</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
@@ -46,6 +48,14 @@
|
||||
<li><a href="javascript:void(0)" ng-click="changeTranslate('zh')">Simplified Chinese</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="bootstrap-elements.html" data-target="#" class="dropdown-toggle" data-toggle="dropdown">{{'CHANGE_VERSION' | translate}}
|
||||
<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="javascript:void(0)" ng-click="changeRMQVersion(5)">RocketMQ 5.x</a></li>
|
||||
<li><a href="javascript:void(0)" ng-click="changeRMQVersion(4)">RocketMQ 4.x</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown" ng-show="username != ''">
|
||||
<a href="bootstrap-elements.html" data-target="#" class="dropdown-toggle" data-toggle="dropdown">{{username}}
|
||||
<b class="caret"></b></a>
|
||||
|
483
src/main/resources/static/view/pages/acl.html
Normal file
483
src/main/resources/static/view/pages/acl.html
Normal file
@@ -0,0 +1,483 @@
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<div class="container-fluid" id="deployHistoryList">
|
||||
<div class="modal-body">
|
||||
<div ng-cloak="" class="tabsdemoDynamicHeight">
|
||||
<md-content>
|
||||
<md-tabs md-dynamic-height="" md-border-bottom="">
|
||||
<md-tab label="Account Info">
|
||||
<md-content class="md-padding" style="min-height:600px">
|
||||
<form class="form-inline pull-left col-sm-12">
|
||||
<div class="form-group">
|
||||
<label>Access Key:</label>
|
||||
<input class="form-control" style="width: 450px" type="text" ng-model="filterStr"/>
|
||||
</div>
|
||||
|
||||
<button ng-show="writeOperationEnabled" class="btn btn-raised btn-sm btn-primary"
|
||||
type="button"
|
||||
ng-click="openAddDialog()">{{'ADD' |
|
||||
translate}}
|
||||
</button>
|
||||
</form>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th class="text-center">Access Key</th>
|
||||
<th ng-show="writeOperationEnabled" class="text-center">Secret Key</th>
|
||||
<th class="text-center">{{'IS_ADMIN' | translate}}</th>
|
||||
<th class="text-center">{{'DEFAULT_TOPIC_PERM' | translate}}</th>
|
||||
<th class="text-center">{{'DEFAULT_GROUP_PERM' | translate}}</th>
|
||||
<th class="text-center">{{'TOPIC_PERM' | translate}}</th>
|
||||
<th class="text-center">{{'GROUP_PERM' | translate}}</th>
|
||||
<th ng-show="writeOperationEnabled" class="text-center">
|
||||
{{'OPERATION' | translate}}
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="item in plainAccessConfigs">
|
||||
<td class="text-center">{{item.accessKey}}</td>
|
||||
<td ng-show="writeOperationEnabled" class="text-center">
|
||||
<input type="{{showSecretKeyType[item.accessKey].type}}"
|
||||
value="{{item.secretKey}}" class="input-none" ng-disabled="true"/>
|
||||
<a href="javascript:;"
|
||||
ng-click="switchSecretKeyType(item.accessKey)">{{showSecretKeyType[item.accessKey].action | translate}}</a>
|
||||
</td>
|
||||
<td class="text-center">{{item.admin}}</td>
|
||||
<td class="text-center">{{item.defaultTopicPerm}}</td>
|
||||
<td class="text-center">{{item.defaultGroupPerm}}</td>
|
||||
<td class="text-center">
|
||||
<table ng-repeat="topic in item.topicPerms" class="perm-table">
|
||||
<tr>
|
||||
<td class="perm-tg">{{topic}}</td>
|
||||
<td ng-show="writeOperationEnabled" class="center"><a
|
||||
href="javascript:;"
|
||||
ng-click="openUpdateTopicDialog(item, topic)">
|
||||
{{'UPDATE' | translate}}</a></td>
|
||||
<td ng-show="writeOperationEnabled"><a href="javascript:;"
|
||||
ng-confirm-click="Are you sure to delete {{topic}}?"
|
||||
confirmed-click="deletePermConfig(item, topic, 'topic')">{{'DELETE' | translate}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<table ng-repeat="group in item.groupPerms" class="perm-table">
|
||||
<tr>
|
||||
<td class="perm-tg">{{group}}</td>
|
||||
<td ng-show="writeOperationEnabled" class="center"><a
|
||||
href="javascript:;"
|
||||
ng-click="openUpdateGroupDialog(item, group)">
|
||||
{{'UPDATE' | translate}}</a></td>
|
||||
<td ng-show="writeOperationEnabled"><a href="javascript:;"
|
||||
ng-confirm-click="Are you sure to delete {{group}}?"
|
||||
confirmed-click="deletePermConfig(item, group, 'group')">{{'DELETE' | translate}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td ng-show="writeOperationEnabled" class="text-center">
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openAddTopicDialog(item)">
|
||||
{{'ADD' | translate}}topic
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openAddGroupDialog(item)">
|
||||
{{'ADD' | translate}}group
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openUpdateDialog(item)">
|
||||
{{'UPDATE' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-danger" type="button"
|
||||
ng-confirm-click="Are you sure to delete {{item.accessKey}}?"
|
||||
confirmed-click="deleteAclConfig(item.accessKey)">{{'DELETE' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-danger" type="button"
|
||||
ng-click="synchronizeData(item)">{{'SYNCHRONIZE' | translate}}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<tm-pagination conf="paginationConf"></tm-pagination>
|
||||
</md-content>
|
||||
</md-tab>
|
||||
<md-tab label="Global White List">
|
||||
<md-content class="md-padding" style="min-height:600px">
|
||||
<form class="form-inline pull-left col-sm-12">
|
||||
<button ng-show="writeOperationEnabled" class="btn btn-raised btn-sm btn-primary"
|
||||
type="button"
|
||||
ng-click="openAddAddrDialog()">{{'ADD' |
|
||||
translate}}
|
||||
</button>
|
||||
<button ng-show="writeOperationEnabled" class="btn btn-raised btn-sm btn-danger"
|
||||
type="button"
|
||||
ng-confirm-click="Are you sure to synchronize white list to all broker int the cluster?"
|
||||
confirmed-click="synchronizeWhiteList(allGlobalWhiteAddrs)">
|
||||
{{'SYNCHRONIZE' | translate}}
|
||||
</button>
|
||||
</form>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th class="text-center">{{'WHITE_LIST' | translate}}</th>
|
||||
<th ng-show="writeOperationEnabled" class="text-center">
|
||||
{{'OPERATION' | translate}}
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="item in allGlobalWhiteAddrs">
|
||||
<td class="text-center">{{item}}
|
||||
</td>
|
||||
<td ng-show="writeOperationEnabled" class="text-center">
|
||||
<button class="btn btn-raised btn-sm btn-danger" type="button"
|
||||
ng-confirm-click="Are you sure to delete {{item}}?"
|
||||
confirmed-click="deleteGlobalWhiteAddr(item)">{{'DELETE' | translate}}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</md-content>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="addAclAccountDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addAppForm" name="addAppForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'IS_ADMIN' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-switch class="md-primary" md-no-ink aria-label="Switch No Ink"
|
||||
ng-model="ngDialogData.admin">
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultTopicPerm" type="text" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultGroupPerm" type="text" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="addRequest({'accessKey':ngDialogData.accessKey, 'secretKey': ngDialogData.secretKey, 'admin': ngDialogData.admin, 'defaultTopicPerm': ngDialogData.defaultTopicPerm, 'defaultGroupPerm': ngDialogData.defaultGroupPerm})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="updateAclAccountDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'UPDATE' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="updateAccountForm" name="updateAccountForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'IS_ADMIN' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-switch class="md-primary" md-no-ink aria-label="Switch No Ink"
|
||||
ng-model="ngDialogData.admin">
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultTopicPerm" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultGroupPerm" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'accessKey':ngDialogData.accessKey, 'secretKey': ngDialogData.secretKey, 'admin': ngDialogData.admin, 'defaultTopicPerm': ngDialogData.defaultTopicPerm, 'defaultGroupPerm': ngDialogData.defaultGroupPerm})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addAclTopicDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}{{'TOPIC_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addAclTopicForm" name="addAclTopicForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="topic" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'topic': topic , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="updateAclTopicDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'UPDATE' | translate }}{{'TOPIC_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="updateAclTopicForm" name="updateAclTopicForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.topic" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'topic': ngDialogData.topic , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addAclGroupDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}{{'GROUP_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addAclGroupForm" name="addAclGroupForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'CONSUMER' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="group" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'group': group , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="updateAclGroupDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'UPDATE' | translate }}{{'GROUP_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="updateAclGroupForm" name="updateAclGroupForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'CONSUMER' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.group" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'group': ngDialogData.group , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addWhiteListDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}{{'WHITE_LIST' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addWhiteListForm" name="addWhiteListForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'WHITE_LIST' | translate }}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ip" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="addWhiteListRequest(ip)">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
@@ -50,7 +50,14 @@
|
||||
<td class="text-center">{{instance.address}}</td>
|
||||
<td class="text-center">{{instance.brokerVersionDesc}}</td>
|
||||
<td class="text-center">{{instance.putTps.split(' ')[0]| number:2}}</td>
|
||||
<td class="text-center">{{instance.getTransferedTps.split(' ')[0]| number:2}}</td>
|
||||
<td class="text-center">
|
||||
<span ng-if="!instance.getTransferedTps || !instance.getTransferedTps.trim()">
|
||||
{{instance.getTransferredTps.split(' ')[0] | number:2}}
|
||||
</span>
|
||||
<span ng-if="instance.getTransferedTps && instance.getTransferedTps.trim()">
|
||||
{{instance.getTransferedTps.split(' ')[0] | number:2}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-center">{{instance.msgPutTotalTodayMorning -
|
||||
instance.msgPutTotalYesterdayMorning}}
|
||||
</td>
|
||||
|
@@ -26,6 +26,8 @@
|
||||
</div>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterNormal" class="md-primary">{{'NORMAL' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-show="rmqVersion" ng-model="filterFIFO" class="md-primary">{{'FIFO' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterSystem" class="md-primary">{{'SYSTEM' | translate}}
|
||||
</md-checkbox>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button" ng-show="{{writeOperationEnabled}}"
|
||||
@@ -64,11 +66,11 @@
|
||||
<td class="text-center">{{consumerGroup.consumeTps}}</td>
|
||||
<td class="text-center">{{consumerGroup.diffTotal}}</td>
|
||||
<td class="text-left">
|
||||
<button name="client" ng-click="client(consumerGroup.group)"
|
||||
<button name="client" ng-click="client(consumerGroup.group, consumerGroup.address)"
|
||||
class="btn btn-raised btn-sm btn-primary"
|
||||
type="button">{{'CLIENT' | translate}}
|
||||
</button>
|
||||
<button name="client" ng-click="detail(consumerGroup.group)"
|
||||
<button name="client" ng-click="detail(consumerGroup.group, consumerGroup.address)"
|
||||
class="btn btn-raised btn-sm btn-primary"
|
||||
type="button">{{'CONSUME_DETAIL' | translate}}
|
||||
</button>
|
||||
@@ -274,15 +276,6 @@
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="form-group">-->
|
||||
<!--<label class="control-label col-sm-4">retryMaxTimes:</label>-->
|
||||
<!--<div class="col-sm-8">-->
|
||||
<!--<input class="form-control" ng-model="item.subscriptionGroupConfig.retryMaxTimes"-->
|
||||
<!--type="text"-->
|
||||
<!--required/>-->
|
||||
<!--<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>-->
|
||||
<!--</div>-->
|
||||
<!--</div>-->
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">brokerId:</label>
|
||||
<div class="col-sm-9">
|
||||
@@ -291,6 +284,132 @@
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">retryMaxTimes:</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" ng-model="item.subscriptionGroupConfig.retryMaxTimes" type="text"
|
||||
ng-disabled="{{!ngDialogData.writeOperationEnabled}}" required/>
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">whichBrokerWhenConsumeSlowly:</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control"
|
||||
ng-model="item.subscriptionGroupConfig.whichBrokerWhenConsumeSlowly" type="text"
|
||||
ng-disabled="{{!ngDialogData.writeOperationEnabled}}" required/>
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-disabled="addAppForm.$invalid"
|
||||
ng-show="{{ngDialogData.writeOperationEnabled}}"
|
||||
ng-click="postConsumerRequest(item)">{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="consumerModifyDialogForV5">
|
||||
<div>
|
||||
<div>
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'SUBSCRIPTION_CHANGE'|translate}}</h4>
|
||||
</div>
|
||||
<div class="modal-body " ng-repeat="item in ngDialogData.consumerRequestList">
|
||||
<form id="addAppForm1" name="addAppForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group" ng-hide="ngDialogData.bIsUpdate">
|
||||
<label class="control-label col-sm-3">clusterName:</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="mySelectClusterNameList" multiple chosen
|
||||
ng-model="item.clusterNameList"
|
||||
ng-options="clusterNameItem for clusterNameItem in ngDialogData.allClusterNameList">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">brokerName:</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="mySelectBrokerNameList" multiple chosen
|
||||
ng-disabled="ngDialogData.bIsUpdate"
|
||||
ng-model="item.brokerNameList"
|
||||
ng-options="brokerNameItem for brokerNameItem in ngDialogData.allBrokerNameList">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">groupName:</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" ng-model="item.subscriptionGroupConfig.groupName" type="text"
|
||||
ng-disabled="ngDialogData.bIsUpdate" required/>
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">consumeEnable:</label>
|
||||
<div class="col-sm-9">
|
||||
<md-switch class="md-primary" ng-disabled="{{!ngDialogData.writeOperationEnabled}}" md-no-ink
|
||||
aria-label="Switch No Ink" ng-model="item.subscriptionGroupConfig.consumeEnable">
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">consumeOrderlyEnable:</label>
|
||||
<div class="col-sm-9">
|
||||
<md-switch class="md-primary custom-md-switch" eng-disabled="{{!ngDialogData.writeOperationEnabled}}" md-no-ink
|
||||
aria-label="Switch No Ink" ng-model="item.subscriptionGroupConfig.consumeMessageOrderly">
|
||||
</md-switch>
|
||||
<span style="font-size: 12px;">[Pay Attention: FIFO ConsumerGroup Need Open 'consumeOrderlyEnable' Option]</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">consumeBroadcastEnable:</label>
|
||||
<div class="col-sm-9">
|
||||
<md-switch class="md-primary" ng-disabled="{{!ngDialogData.writeOperationEnabled}}" md-no-ink
|
||||
aria-label="Switch No Ink"
|
||||
ng-model="item.subscriptionGroupConfig.consumeBroadcastEnable">
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">retryQueueNums:</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" ng-model="item.subscriptionGroupConfig.retryQueueNums"
|
||||
type="text" ng-disabled="{{!ngDialogData.writeOperationEnabled}}"
|
||||
required/>
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">brokerId:</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" ng-model="item.subscriptionGroupConfig.brokerId" type="text"
|
||||
ng-disabled="{{!ngDialogData.writeOperationEnabled}}" required/>
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">retryMaxTimes:</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" ng-model="item.subscriptionGroupConfig.retryMaxTimes" type="text"
|
||||
ng-disabled="{{!ngDialogData.writeOperationEnabled}}" required/>
|
||||
<span class="text-danger" ng-show="addAppForm.name.$error.required">编号不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3">whichBrokerWhenConsumeSlowly:</label>
|
||||
<div class="col-sm-9">
|
||||
|
@@ -64,9 +64,22 @@
|
||||
ng-click="queryDlqMessageByConsumerGroup()">
|
||||
<span class="glyphicon glyphicon-search"></span> {{ 'SEARCH' | translate}}
|
||||
</button>
|
||||
<button type="button" id="batchResendBtn"
|
||||
class="btn btn-raised btn-sm btn-primary disabled"
|
||||
data-toggle="modal"
|
||||
ng-click="batchResendDlqMessage(selectedConsumerGroup)">
|
||||
<span class="glyphicon glyphicon-send"></span> {{ 'BATCH_RESEND' | translate}}
|
||||
</button>
|
||||
<button type="button" id="batchExportBtn"
|
||||
class="btn btn-raised btn-sm btn-primary disabled"
|
||||
data-toggle="modal"
|
||||
ng-click="batchExportDlqMessage(selectedConsumerGroup)">
|
||||
<span class="glyphicon glyphicon-export"></span> {{ 'BATCH_EXPORT' | translate}}
|
||||
</button>
|
||||
</form>
|
||||
<table class="table table-bordered text-middle">
|
||||
<tr>
|
||||
<th class="text-center"><input type="checkbox" ng-model='checkedAll' ng-change="selectAll()"/></th>
|
||||
<th class="text-center">Message ID</th>
|
||||
<th class="text-center">Tag</th>
|
||||
<th class="text-center">Key</th>
|
||||
@@ -77,6 +90,9 @@
|
||||
<td colspan="6" style="text-align: center">{{'NO_MATCH_RESULT' | translate}}</td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in messageShowList">
|
||||
<td class="text-center">
|
||||
<input type="checkbox" ng-model='item.checked' ng-change="selectItem()"/>
|
||||
</td>
|
||||
<td class="text-center">{{item.msgId}}</td>
|
||||
<td class="text-center">{{item.properties.TAGS}}</td>
|
||||
<td class="text-center">{{item.properties.KEYS}}</td>
|
||||
@@ -192,7 +208,7 @@
|
||||
<label class="control-label col-sm-2">Properties:</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control"
|
||||
style="min-height:60px; resize: none"
|
||||
style="min-height:100px; resize: none"
|
||||
readonly>{{ngDialogData.messageView.properties}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -73,6 +73,9 @@
|
||||
<th class="text-center">StoreTime</th>
|
||||
<th class="text-center">Operation</th>
|
||||
</tr>
|
||||
<tr style="display: none" id="noMsgTip">
|
||||
<td colspan="5" style="text-align: center">{{'NO_MATCH_RESULT' | translate}}</td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in messageShowList">
|
||||
<td class="text-center">{{item.msgId}}</td>
|
||||
<td class="text-center">{{item.properties.TAGS}}</td>
|
||||
@@ -227,7 +230,13 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<p>messageTrackList:</p>
|
||||
<div style="font-weight:700; color:#000">messageTrackList:</div>
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<label>consumerGroup:</label>
|
||||
<input type="text" class="form-control" ng-model="filterConsumerGroup">
|
||||
</div>
|
||||
</form>
|
||||
<table class="table-bordered table text-middle">
|
||||
<tr>
|
||||
<th class="text-center">consumerGroup</th>
|
||||
@@ -235,7 +244,7 @@
|
||||
<!--<th class="text-center">exceptionDesc</th>-->
|
||||
<th class="text-center">Operation</th>
|
||||
</tr>
|
||||
<tr ng-repeat="item in ngDialogData.messageTrackList">
|
||||
<tr ng-repeat="item in messageTrackShowList">
|
||||
<td class="text-center">{{item.consumerGroup}}</td>
|
||||
<td class="text-center">{{item.trackType}}</td>
|
||||
<td class="text-center">
|
||||
|
@@ -17,15 +17,26 @@
|
||||
<div class="container-fluid" id="deployHistoryList">
|
||||
<div class="page-content">
|
||||
<h2 class="md-title">NameServerAddressList</h2>
|
||||
<div class="pull-left">
|
||||
<md-chips ng-model="namesvrAddrList" md-on-add="eleChange(namesvrAddrList)"
|
||||
md-on-remove="eleChange(namesvrAddrList)" readonly="inputReadonly" md-removable="ctrl.removable"></md-chips>
|
||||
<div class="pull-left" style="min-width: 400px; max-width: 500px; padding: 10px 10px 10px 0">
|
||||
<select ng-model="selectedNamesrv" chosen
|
||||
ng-options="x for x in namesvrAddrList"
|
||||
ng-change="updateNameSvrAddr()"
|
||||
required></select>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button" ng-show="{{writeOperationEnabled}}"
|
||||
ng-click="updateNameSvrAddr()">{{'UPDATE' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<form class="form-inline pull-left" style="margin-left: 20px" ng-show="{{writeOperationEnabled}}">
|
||||
<div class="form-group" style="margin: 0">
|
||||
<label for="namesrvAddr">NamesrvAddr:</label>
|
||||
<input id="namesrvAddr" class="form-control" style="width: 300px; margin: 0 10px 0 10px" type="text" ng-model="newNamesrvAddr" required/>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="addNameSvrAddr()"> {{ 'ADD' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<br/>
|
||||
<br/>
|
||||
<h2 class="md-title">IsUseVIPChannel</h2>
|
||||
|
67
src/main/resources/static/view/pages/proxy.html
Normal file
67
src/main/resources/static/view/pages/proxy.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<div class="container-fluid" id="deployHistoryList">
|
||||
<div class="page-content">
|
||||
<h2 class="md-title">ProxyServerAddressList</h2>
|
||||
<div class="pull-left" style="min-width: 400px; max-width: 500px; padding: 10px 10px 10px 0">
|
||||
<select ng-model="selectedProxy" chosen
|
||||
ng-options="x for x in proxyAddrList"
|
||||
ng-change="updateProxyAddr()"
|
||||
required></select>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button" ng-show="{{writeOperationEnabled}}"
|
||||
ng-click="updateProxyAddr()">{{'UPDATE' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<form class="form-inline pull-left" style="margin-left: 20px" ng-show="{{writeOperationEnabled}}">
|
||||
<div class="form-group" style="margin: 0">
|
||||
<label for="proxyAddr">ProxyAddr:</label>
|
||||
<input id="proxyAddr" class="form-control" style="width: 300px; margin: 0 10px 0 10px" type="text" ng-model="newProxyAddr" required/>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="addProxyAddr()"> {{ 'ADD' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal proxyModal fade" role="dialog" tabindex="-1" aria-hidden="true" aria-labelledby="config-modal-label">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content" >
|
||||
<div class="modal-header">
|
||||
<button class="close" type="button" data-dismiss="modal">×</button>
|
||||
<h4 id="config-modal-label" class="modal-title">
|
||||
[{{selectedProxy}}]
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body limit_height">
|
||||
<table class="table table-bordered">
|
||||
<tr ng-repeat="(key, value) in allProxyConfig">
|
||||
<td>{{key}}</td>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="col-md-12 text-center">
|
||||
<button type="button" class="btn btn-raised" data-dismiss="modal">{{ 'CLOSE' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -24,6 +24,14 @@
|
||||
</div>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterNormal" class="md-primary">{{'NORMAL' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterDelay" class="md-primary" ng-show="rmqVersion">{{'DELAY' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterFifo" class="md-primary" ng-show="rmqVersion">{{'FIFO' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterTransaction" class="md-primary" ng-show="rmqVersion">{{'TRANSACTION' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterUnspecified" class="md-primary" ng-show="rmqVersion">{{'UNSPECIFIED' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterRetry" class="md-primary">{{'RETRY' | translate}}
|
||||
</md-checkbox>
|
||||
<md-checkbox aria-label="Checkbox" ng-model="filterDLQ" class="md-primary">{{'DLQ' | translate}}
|
||||
@@ -63,6 +71,7 @@
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openUpdateDialog(topic, sysFlag)">topic {{'CONFIG' |translate}}
|
||||
</button>
|
||||
<!-- todo 发送消息,根据消息类型判断-->
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-show="{{!sysFlag}}"
|
||||
ng-click="openSendTopicMessageDialog(topic)">{{'SEND_MSG' | translate}}
|
||||
@@ -189,6 +198,18 @@
|
||||
<span class="text-danger" ng-show="addAppForm.topicName.$error.required">{{'TOPIC_NAME'|translate}}不能为空.</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 设置topic 类型 -->
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'MESSAGE_TYPE'|translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="mySelectMessageType" chosen ng-disabled="ngDialogData.bIsUpdate"
|
||||
ng-model="item.messageType"
|
||||
ng-options="messageType as value | translate disable when messageType=='UNSPECIFIED' for (messageType , value) in ngDialogData.allMessageTypeList"
|
||||
>
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'WRITE_QUEUE_NUMS'|translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
|
@@ -34,27 +34,27 @@ import org.apache.rocketmq.client.impl.MQClientAPIImpl;
|
||||
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeStatsList;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
|
||||
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeStatsList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.QueueTimeSpan;
|
||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.dashboard.service.client.MQAdminExtImpl;
|
||||
import org.apache.rocketmq.dashboard.service.client.MQAdminInstance;
|
||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||
@@ -82,6 +82,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -418,8 +419,10 @@ public class MQAdminExtImplTest {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
doNothing().when(defaultMQAdminExt).deleteSubscriptionGroup(anyString(), anyString());
|
||||
doNothing().when(defaultMQAdminExt).deleteSubscriptionGroup(anyString(), anyString(), anyBoolean());
|
||||
}
|
||||
mqAdminExtImpl.deleteSubscriptionGroup(brokerAddr, "group_test");
|
||||
mqAdminExtImpl.deleteSubscriptionGroup(brokerAddr, "group_test", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -568,11 +571,13 @@ public class MQAdminExtImplTest {
|
||||
public void testCreateTopic() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
doNothing().when(defaultMQAdminExt).createTopic(anyString(), anyString(), anyInt());
|
||||
doNothing().when(defaultMQAdminExt).createTopic(anyString(), anyString(), anyInt(), anyInt());
|
||||
doNothing().when(defaultMQAdminExt).createTopic(anyString(), anyString(), anyInt(), anyMap());
|
||||
doNothing().when(defaultMQAdminExt).createTopic(anyString(), anyString(), anyInt(), anyInt(), anyMap());
|
||||
}
|
||||
mqAdminExtImpl.createTopic("key", "topic_test", 8);
|
||||
mqAdminExtImpl.createTopic("key", "topic_test", 8, 1);
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("message.type", "FIFO");
|
||||
mqAdminExtImpl.createTopic("key", "topic_test", 8, map);
|
||||
mqAdminExtImpl.createTopic("key", "topic_test", 8, 1, map);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -758,16 +763,6 @@ public class MQAdminExtImplTest {
|
||||
Assert.assertNotNull(wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllTopicGroup() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
when(defaultMQAdminExt.getAllTopicGroup(anyString(), anyLong())).thenReturn(new TopicConfigSerializeWrapper());
|
||||
}
|
||||
TopicConfigSerializeWrapper wrapper = mqAdminExtImpl.getAllTopicGroup(brokerAddr, 5000L);
|
||||
Assert.assertNotNull(wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConsumeOffset() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
@@ -801,4 +796,42 @@ public class MQAdminExtImplTest {
|
||||
Assert.assertFalse(mqAdminExtImpl.resumeCheckHalfMessage("topic_test", "7F000001ACC018B4AAC2116AF6500000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddWritePermOfBroker() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
when(defaultMQAdminExt.addWritePermOfBroker(anyString(), anyString())).thenReturn(6);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.addWritePermOfBroker("127.0.0.1:9876", "broker-a"), 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserSubscriptionGroup() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
SubscriptionGroupWrapper wrapper = new SubscriptionGroupWrapper();
|
||||
{
|
||||
when(defaultMQAdminExt.getUserSubscriptionGroup(anyString(), anyLong())).thenReturn(wrapper);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.getUserSubscriptionGroup("127.0.0.1:10911", 3000), wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllTopicConfig() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
TopicConfigSerializeWrapper wrapper = new TopicConfigSerializeWrapper();
|
||||
{
|
||||
when(defaultMQAdminExt.getAllTopicConfig(anyString(), anyLong())).thenReturn(wrapper);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.getAllTopicConfig("127.0.0.1:10911", 3000), wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserTopicConfig() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
TopicConfigSerializeWrapper wrapper = new TopicConfigSerializeWrapper();
|
||||
{
|
||||
when(defaultMQAdminExt.getUserTopicConfig(anyString(), anyBoolean(), anyLong())).thenReturn(wrapper);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.getUserTopicConfig("127.0.0.1:10911", true, 3000), wrapper);
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ package org.apache.rocketmq.dashboard.admin;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CollectExecutorConfigTest {
|
||||
|
||||
private final static int COUNT = 100;
|
||||
|
||||
@Test
|
||||
public void testCollectExecutor() throws Exception {
|
||||
AtomicInteger num = new AtomicInteger(0);
|
||||
CollectExecutorConfig config = new CollectExecutorConfig();
|
||||
config.setCoreSize(10);
|
||||
config.setMaxSize(10);
|
||||
config.setQueueSize(500);
|
||||
config.setKeepAliveTime(3000);
|
||||
ExecutorService collectExecutor = config.collectExecutor(config);
|
||||
Assert.assertNotNull(collectExecutor);
|
||||
CountDownLatch countDownLatch = new CountDownLatch(COUNT);
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
collectExecutor.submit(() -> {
|
||||
num.getAndIncrement();
|
||||
countDownLatch.countDown();
|
||||
});
|
||||
}
|
||||
countDownLatch.await();
|
||||
System.out.println(collectExecutor.isTerminated());
|
||||
Assert.assertEquals(COUNT, num.get());
|
||||
}
|
||||
}
|
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.File;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@@ -39,6 +40,7 @@ public class RMQConfigureTest {
|
||||
rmqConfigure.setLoginRequired(true);
|
||||
rmqConfigure.setNamesrvAddr("127.0.0.1:9876");
|
||||
rmqConfigure.setTimeoutMillis(3000L);
|
||||
rmqConfigure.setNamesrvAddrs(Lists.asList("127.0.0.1:9876", new String[] {"127.0.0.2:9876"}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -54,6 +56,7 @@ public class RMQConfigureTest {
|
||||
Assert.assertTrue(rmqConfigure.isEnableDashBoardCollect());
|
||||
Assert.assertTrue(rmqConfigure.isLoginRequired());
|
||||
Assert.assertEquals(rmqConfigure.getNamesrvAddr(), "127.0.0.1:9876");
|
||||
Assert.assertEquals(rmqConfigure.getNamesrvAddrs().size(), 2);
|
||||
Assert.assertEquals(rmqConfigure.getTimeoutMillis().longValue(), 3000L);
|
||||
ErrorPageRegistrar registrar = rmqConfigure.errorPageRegistrar();
|
||||
registrar.registerErrorPages(new ErrorPageRegistry() {
|
||||
|
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Spy;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
public class AclControllerTest extends BaseControllerTest {
|
||||
|
||||
@InjectMocks
|
||||
private AclController aclController;
|
||||
|
||||
@Spy
|
||||
private AclServiceImpl aclService;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
AclConfig aclConfig = MockObjectUtil.createAclConfig();
|
||||
when(mqAdminExt.examineBrokerClusterAclConfig(anyString())).thenReturn(aclConfig);
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
doNothing().when(mqAdminExt).createAndUpdatePlainAccessConfig(anyString(), any(PlainAccessConfig.class));
|
||||
doNothing().when(mqAdminExt).deletePlainAccessConfig(anyString(), anyString());
|
||||
doNothing().when(mqAdminExt).updateGlobalWhiteAddrConfig(anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEnableAcl() throws Exception {
|
||||
final String url = "/acl/enable.query";
|
||||
// 1. disable acl.
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").value(false));
|
||||
|
||||
// 2.enable acl.
|
||||
super.mockRmqConfigure();
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAclConfig() throws Exception {
|
||||
final String url = "/acl/config.query";
|
||||
|
||||
// 1. broker addr table is not empty.
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs[0].secretKey").isNotEmpty());
|
||||
|
||||
// 2. broker addr table is empty.
|
||||
clusterInfo.getBrokerAddrTable().clear();
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isEmpty());
|
||||
|
||||
// 3. login required and user info is null.
|
||||
when(configure.isLoginRequired()).thenReturn(true);
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(MockObjectUtil.createClusterInfo());
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs[0].secretKey").isEmpty());
|
||||
// 4. login required, but user is not admin. emmmm, Mockito may can not mock static method.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAclConfig() throws Exception {
|
||||
final String url = "/acl/add.do";
|
||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
|
||||
// 1. access key is null.
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. secret key is null.
|
||||
accessConfig.setAccessKey("test-access-key");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
|
||||
// 3. add if the access key not exist.
|
||||
accessConfig.setSecretKey("12345678");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 4. add failed if the access key is existed.
|
||||
accessConfig.setAccessKey("rocketmq2");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 5. add failed if there is no alive broker.
|
||||
clusterInfo.getBrokerAddrTable().clear();
|
||||
accessConfig.setAccessKey("test-access-key");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAclConfig() throws Exception {
|
||||
final String url = "/acl/delete.do";
|
||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
|
||||
// 1. access key is null.
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. access key is not null.
|
||||
accessConfig.setAccessKey("rocketmq");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAclConfig() throws Exception {
|
||||
final String url = "/acl/update.do";
|
||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
|
||||
// 1. secret key is null.
|
||||
accessConfig.setAccessKey("rocketmq");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. update.
|
||||
accessConfig.setSecretKey("abcdefghjkl");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAclTopicConfig() throws Exception {
|
||||
final String url = "/acl/topic/add.do";
|
||||
AclRequest request = new AclRequest();
|
||||
request.setConfig(createDefaultPlainAccessConfig());
|
||||
|
||||
// 1. if not exist.
|
||||
request.setTopicPerm("test_topic=PUB");
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 2. if exist.
|
||||
request.setTopicPerm("topicA=PUB");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 3. if access key not exist.
|
||||
request.getConfig().setAccessKey("test_access_key123");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAclGroupConfig() throws Exception {
|
||||
final String url = "/acl/group/add.do";
|
||||
AclRequest request = new AclRequest();
|
||||
request.setConfig(createDefaultPlainAccessConfig());
|
||||
|
||||
// 1. if not exist.
|
||||
request.setGroupPerm("test_consumer=PUB|SUB");
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 2. if exist.
|
||||
request.setGroupPerm("groupA=PUB|SUB");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 3. if access key not exist.
|
||||
request.getConfig().setAccessKey("test_access_key123");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletePermConfig() throws Exception {
|
||||
final String url = "/acl/perm/delete.do";
|
||||
AclRequest request = new AclRequest();
|
||||
request.setConfig(createDefaultPlainAccessConfig());
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// if access key not exist.
|
||||
request.getConfig().setAccessKey("test_access_key123");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyncConfig() throws Exception {
|
||||
final String url = "/acl/sync.do";
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(createDefaultPlainAccessConfig()));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddWhiteList() throws Exception {
|
||||
final String url = "/acl/white/list/add.do";
|
||||
List<String> whiteList = Lists.newArrayList("192.168.0.1");
|
||||
|
||||
// 1. if global white list is not null.
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 2. if global white list is null.
|
||||
AclConfig aclConfig = MockObjectUtil.createAclConfig();
|
||||
aclConfig.setGlobalWhiteAddrs(null);
|
||||
when(mqAdminExt.examineBrokerClusterAclConfig(anyString())).thenReturn(aclConfig);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteWhiteAddr() throws Exception {
|
||||
final String url = "/acl/white/list/delete.do";
|
||||
requestBuilder = MockMvcRequestBuilders.delete(url);
|
||||
requestBuilder.param("request", "localhost");
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronizeWhiteList() throws Exception {
|
||||
final String url = "/acl/white/list/sync.do";
|
||||
List<String> whiteList = Lists.newArrayList();
|
||||
|
||||
// 1. if white list for syncing is empty.
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. if white list for syncing is not empty.
|
||||
whiteList.add("localhost");
|
||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Override protected Object getTestController() {
|
||||
return aclController;
|
||||
}
|
||||
|
||||
private PlainAccessConfig createDefaultPlainAccessConfig() {
|
||||
PlainAccessConfig config = new PlainAccessConfig();
|
||||
config.setAdmin(false);
|
||||
config.setAccessKey("rocketmq");
|
||||
config.setSecretKey("123456789");
|
||||
config.setDefaultGroupPerm("SUB");
|
||||
config.setDefaultTopicPerm("DENY");
|
||||
config.setTopicPerms(Lists.newArrayList("topicA=DENY", "topicB=PUB|SUB"));
|
||||
config.setGroupPerms(Lists.newArrayList("groupA=DENY", "groupB=PUB|SUB"));
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.rocketmq.dashboard.BaseTest;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
||||
@@ -62,6 +63,7 @@ public abstract class BaseControllerTest extends BaseTest {
|
||||
when(configure.getAccessKey()).thenReturn("12345678");
|
||||
when(configure.getSecretKey()).thenReturn("rocketmq");
|
||||
when(configure.getNamesrvAddr()).thenReturn("127.0.0.1:9876");
|
||||
when(configure.getNamesrvAddrs()).thenReturn(Lists.newArrayList("127.0.0.1:9876", "127.0.0.2:9876"));
|
||||
when(configure.isACLEnabled()).thenReturn(true);
|
||||
when(configure.isUseTLS()).thenReturn(false);
|
||||
}
|
||||
|
@@ -18,8 +18,8 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.dashboard.service.impl.ClusterServiceImpl;
|
||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||
import org.junit.Test;
|
||||
|
@@ -23,17 +23,17 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
|
||||
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
|
||||
@@ -67,6 +67,7 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
consumerService.afterPropertiesSet();
|
||||
super.mockRmqConfigure();
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
@@ -93,9 +94,10 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data", hasSize(2)))
|
||||
.andExpect(jsonPath("$.data[0].group").value("group_test"))
|
||||
.andExpect(jsonPath("$.data[0].consumeType").value(ConsumeType.CONSUME_ACTIVELY.name()))
|
||||
.andExpect(jsonPath("$.data[0].messageModel").value(MessageModel.CLUSTERING.name()));
|
||||
// executorService shutdown
|
||||
consumerService.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -182,6 +184,8 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
||||
final String url = "/consumer/deleteSubGroup.do";
|
||||
{
|
||||
doNothing().when(mqAdminExt).deleteSubscriptionGroup(any(), anyString());
|
||||
doNothing().when(mqAdminExt).deleteTopicInBroker(any(), anyString());
|
||||
doNothing().when(mqAdminExt).deleteTopicInNameServer(any(), anyString());
|
||||
}
|
||||
DeleteSubGroupRequest request = new DeleteSubGroupRequest();
|
||||
request.setBrokerNameList(Lists.newArrayList("broker-a"));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user